Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgbatchrenderer_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
3// Copyright (C) 2016 Robin Burchell <robin.burchell@viroteck.net>
4// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
5// Qt-Security score:significant reason:default
6
7#ifndef QSGBATCHRENDERER_P_H
8#define QSGBATCHRENDERER_P_H
9
10//
11// W A R N I N G
12// -------------
13//
14// This file is not part of the Qt API. It exists purely as an
15// implementation detail. This header file may change from version to
16// version without notice, or even be removed.
17//
18// We mean it.
19//
20
21#include <private/qsgrenderer_p.h>
22#include <private/qsgdefaultrendercontext_p.h>
23#include <private/qsgnodeupdater_p.h>
24#include <private/qsgrendernode_p.h>
25#include <private/qdatabuffer_p.h>
26#include <private/qsgtexture_p.h>
27
28#include <QtCore/QBitArray>
29#include <QtCore/QElapsedTimer>
30#include <QtCore/QStack>
31
32#include <rhi/qrhi.h>
33
35
36namespace QSGBatchRenderer
37{
38
39#define QSG_RENDERER_COORD_LIMIT 1000000.0f
40
41struct Vec;
42struct Rect;
43struct Buffer;
44struct Chunk;
45struct Batch;
46struct Node;
47class Updater;
48class Renderer;
49class ShaderManager;
50
51template <typename Type, int PageSize> class AllocatorPage
52{
53public:
54 // The memory used by this allocator
55 char data[sizeof(Type) * PageSize];
56
57 // 'blocks' contains a list of free indices which can be allocated.
58 // The first available index is found in PageSize - available.
59 int blocks[PageSize];
60
61 // 'available' is the number of available instances this page has left to allocate.
63
64 // This is not strictly needed, but useful for sanity checking and anyway
65 // pretty small..
67
69 : available(PageSize)
71 {
72 for (int i=0; i<PageSize; ++i)
73 blocks[i] = i;
74
75 // Zero out all new pages.
76 memset(data, 0, sizeof(data));
77 }
78
79 const Type *at(uint index) const
80 {
81 return (Type *) &data[index * sizeof(Type)];
82 }
83
84 Type *at(uint index)
85 {
86 return (Type *) &data[index * sizeof(Type)];
87 }
88};
89
90template <typename Type, int PageSize> class Allocator
91{
92public:
94 {
95 pages.push_back(new AllocatorPage<Type, PageSize>());
96 }
97
99 {
100 qDeleteAll(pages);
101 }
102
103 Type *allocate()
104 {
105 AllocatorPage<Type, PageSize> *p = 0;
106 for (int i = m_freePage; i < pages.size(); i++) {
107 if (pages.at(i)->available > 0) {
108 p = pages.at(i);
109 m_freePage = i;
110 break;
111 }
112 }
113
114 // we couldn't find a free page from m_freePage to the last page.
115 // either there is no free pages, or there weren't any in the area we
116 // scanned: rescanning is expensive, so let's just assume there isn't
117 // one. when an item is released, we'll reset m_freePage anyway.
118 if (!p) {
119 p = new AllocatorPage<Type, PageSize>();
120 m_freePage = pages.size();
121 pages.push_back(p);
122 }
123 uint pos = p->blocks[PageSize - p->available];
124 void *mem = p->at(pos);
125 p->available--;
126 p->allocated.setBit(pos);
127 Type *t = (Type*)mem;
128 return t;
129 }
130
131 void releaseExplicit(uint pageIndex, uint index)
132 {
133 AllocatorPage<Type, PageSize> *page = pages.at(pageIndex);
134 if (!page->allocated.testBit(index))
135 qFatal("Double delete in allocator: page=%d, index=%d", pageIndex , index);
136
137 // Zero this instance as we're done with it.
138 void *mem = page->at(index);
139 memset(mem, 0, sizeof(Type));
140
141 page->allocated[index] = false;
142 page->available++;
143 page->blocks[PageSize - page->available] = index;
144
145 // Remove the pages if they are empty and they are the last ones. We need to keep the
146 // order of pages since we have references to their index, so we can only remove
147 // from the end.
148 while (page->available == PageSize && pages.size() > 1 && pages.back() == page) {
149 pages.pop_back();
150 delete page;
151 page = pages.back();
152 }
153
154 // Reset the free page to force a scan for a new free point.
155 m_freePage = 0;
156 }
157
158 void release(Type *t)
159 {
160 int pageIndex = -1;
161 for (int i=0; i<pages.size(); ++i) {
162 AllocatorPage<Type, PageSize> *p = pages.at(i);
163 if ((Type *) (&p->data[0]) <= t && (Type *) (&p->data[PageSize * sizeof(Type)]) > t) {
164 pageIndex = i;
165 break;
166 }
167 }
168 Q_ASSERT(pageIndex >= 0);
169
170 AllocatorPage<Type, PageSize> *page = pages.at(pageIndex);
171 int index = (quint64(t) - quint64(&page->data[0])) / sizeof(Type);
172
173 releaseExplicit(pageIndex, index);
174 }
175
177 int m_freePage = 0;
178};
179
180
181inline bool hasMaterialWithBlending(QSGGeometryNode *n)
182{
183 return (n->opaqueMaterial() ? n->opaqueMaterial()->flags() & QSGMaterial::Blending
184 : n->material()->flags() & QSGMaterial::Blending);
185}
186
187struct Pt {
188 float x, y;
189
190 void map(const QMatrix4x4 &mat) {
191 Pt r;
192 const float *m = mat.constData();
193 r.x = x * m[0] + y * m[4] + m[12];
194 r.y = x * m[1] + y * m[5] + m[13];
195 x = r.x;
196 y = r.y;
197 }
198
199 void set(float nx, float ny) {
200 x = nx;
201 y = ny;
202 }
203};
204
205inline QDebug operator << (QDebug d, const Pt &p) {
206 d << "Pt(" << p.x << p.y << ")";
207 return d;
208}
209
210
211
212struct Rect {
213 Pt tl, br; // Top-Left (min) and Bottom-Right (max)
214
215 void operator |= (const Pt &pt) {
216 if (pt.x < tl.x)
217 tl.x = pt.x;
218 if (pt.x > br.x)
219 br.x = pt.x;
220 if (pt.y < tl.y)
221 tl.y = pt.y;
222 if (pt.y > br.y)
223 br.y = pt.y;
224 }
225
226 void operator |= (const Rect &r) {
227 if (r.tl.x < tl.x)
228 tl.x = r.tl.x;
229 if (r.tl.y < tl.y)
230 tl.y = r.tl.y;
231 if (r.br.x > br.x)
232 br.x = r.br.x;
233 if (r.br.y > br.y)
234 br.y = r.br.y;
235 }
236
237 void map(const QMatrix4x4 &m);
238
239 void set(float left, float top, float right, float bottom) {
240 tl.set(left, top);
241 br.set(right, bottom);
242 }
243
244 bool intersects(const Rect &r) {
245 bool xOverlap = r.tl.x < br.x && r.br.x > tl.x;
246 bool yOverlap = r.tl.y < br.y && r.br.y > tl.y;
247 return xOverlap && yOverlap;
248 }
249
256};
257
258inline QDebug operator << (QDebug d, const Rect &r) {
259 d << "Rect(" << r.tl.x << r.tl.y << r.br.x << r.br.y << ")";
260 return d;
261}
262
263struct Buffer {
265 // Data is only valid while preparing the upload. Exception is if we are using the
266 // broken IBO workaround or we are using a visualization mode.
267 char *data;
268 QRhiBuffer *buf;
270};
271
272struct Element {
274 : boundsComputed(false)
276 , translateOnlyToRoot(false)
277 , removed(false)
278 , orphaned(false)
279 , isRenderNode(false)
280 , isMaterialBlended(false)
281 {
282 }
283
284 void setNode(QSGGeometryNode *n) {
285 node = n;
286 isMaterialBlended = hasMaterialWithBlending(n);
287 }
288
289 inline void ensureBoundsValid() {
290 if (!boundsComputed)
292 }
293 void computeBounds();
294
296 Batch *batch = nullptr;
298 Node *root = nullptr;
299
300 Rect bounds; // in device coordinates
301
302 int order = 0;
306
314};
315
316struct RenderNodeElement : public Element {
317
318 RenderNodeElement(QSGRenderNode *rn)
319 : renderNode(rn)
320 {
321 isRenderNode = true;
322 }
323
325};
326
335
340
342{
343 DrawSet(int v, int z, int i)
344 : vertices(v)
345 , zorders(z)
346 , indices(i)
347 {
348 }
350 int vertices = 0;
351 int zorders = 0;
352 int indices = 0;
353 int indexCount = 0;
354};
355
361
363{
365 {
366 NoClip = 0x00,
369 };
370 Q_DECLARE_FLAGS(ClipType, ClipTypeBit)
371
376
377 inline void reset();
378};
379
403
404struct Batch
405{
406 Batch() : drawSets(1) {}
407 bool geometryWasChanged(QSGGeometryNode *gn);
409 void invalidate();
411
412 bool isTranslateOnlyToRoot() const;
413 bool isSafeToBatch() const;
414
415 // pseudo-constructor...
416 void init() {
417 // Only non-reusable members are reset here. See Renderer::newBatch().
418 first = nullptr;
419 root = nullptr;
420 vertexCount = 0;
421 indexCount = 0;
422 isOpaque = false;
423 needsUpload = false;
424 merged = false;
426 uploadedThisFrame = false;
427 isRenderNode = false;
428 ubufDataValid = false;
429 needsPurge = false;
430 clipState.reset();
431 blendConstant = QColor();
432 }
433
436
438
441
443
450
451 mutable uint uploadedThisFrame : 1; // solely for debugging purposes
452
455 QRhiBuffer *ubuf;
459
461};
462
463// NOTE: Node is zero-initialized by the Allocator.
464struct Node
465{
467 void *data;
468
473
474 Node *parent() const { return m_parent; }
475
476 void append(Node *child) {
477 Q_ASSERT(child);
478 Q_ASSERT(!hasChild(child));
479 Q_ASSERT(child->m_parent == nullptr);
480 Q_ASSERT(child->m_next == nullptr);
481 Q_ASSERT(child->m_prev == nullptr);
482
483 if (!m_child) {
484 child->m_next = child;
485 child->m_prev = child;
486 m_child = child;
487 } else {
490 m_child->m_prev = child;
491 child->m_next = m_child;
492 }
493 child->setParent(this);
494 }
495
496 void remove(Node *child) {
497 Q_ASSERT(child);
498 Q_ASSERT(hasChild(child));
499
500 // only child..
501 if (child->m_next == child) {
502 m_child = nullptr;
503 } else {
504 if (m_child == child)
505 m_child = child->m_next;
506 child->m_next->m_prev = child->m_prev;
507 child->m_prev->m_next = child->m_next;
508 }
509 child->m_next = nullptr;
510 child->m_prev = nullptr;
511 child->setParent(nullptr);
512 }
513
514 Node *firstChild() const { return m_child; }
515
516 Node *sibling() const {
517 Q_ASSERT(m_parent);
518 return m_next == m_parent->m_child ? nullptr : m_next;
519 }
520
521 void setParent(Node *p) {
522 Q_ASSERT(m_parent == nullptr || p == nullptr);
523 m_parent = p;
524 }
525
526 bool hasChild(Node *child) const {
527 Node *n = m_child;
528 while (n && n != child)
529 n = n->sibling();
530 return n;
531 }
532
533
534
536
540
541 inline QSGNode::NodeType type() const { return sgNode->type(); }
542
543 inline Element *element() const {
544 Q_ASSERT(sgNode->type() == QSGNode::GeometryNodeType);
545 return (Element *) data;
546 }
547
549 Q_ASSERT(sgNode->type() == QSGNode::RenderNodeType);
550 return (RenderNodeElement *) data;
551 }
552
553 inline ClipBatchRootInfo *clipInfo() const {
554 Q_ASSERT(sgNode->type() == QSGNode::ClipNodeType);
555 return (ClipBatchRootInfo *) data;
556 }
557
558 inline BatchRootInfo *rootInfo() const {
559 Q_ASSERT(sgNode->type() == QSGNode::ClipNodeType
560 || (sgNode->type() == QSGNode::TransformNodeType && isBatchRoot));
561 return (BatchRootInfo *) data;
562 }
563};
564
566{
567public:
568 Updater(Renderer *r);
569
570 void visitOpacityNode(Node *n);
571 void visitTransformNode(Node *n);
572 void visitGeometryNode(Node *n);
573 void visitClipNode(Node *n);
575 void updateRootTransforms(Node *n, Node *root, const QMatrix4x4 &combined);
576
577 void updateStates(QSGNode *n) override;
578 void visitNode(Node *n);
579 void registerWithParentRoot(QSGNode *subRoot, QSGNode *parentRoot);
580
581private:
582 Renderer *renderer;
583
584 QDataBuffer<Node *> m_roots;
585 QDataBuffer<QMatrix4x4> m_rootMatrices;
586
587 int m_added;
588 int m_transformChange;
589 int m_opacityChange;
590
591 QMatrix4x4 m_identityMatrix;
592};
593
616
617bool operator==(const GraphicsState &a, const GraphicsState &b) noexcept;
618bool operator!=(const GraphicsState &a, const GraphicsState &b) noexcept;
619size_t qHash(const GraphicsState &s, size_t seed = 0) noexcept;
620
622
624{
629 struct {
632 } extra;
634 const ShaderManagerShader *sms,
635 const QRhiRenderPassDescriptor *rpDesc,
636 const QRhiShaderResourceBindings *srb)
637 {
638 const QList<quint32> rtDesc = rpDesc->serializedFormat();
639 const QList<quint32> srbDesc = srb->serializedLayoutDescription();
640 return { state, sms, rtDesc, srbDesc, { qHash(rtDesc), qHash(srbDesc) } };
641 }
642};
643
644bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) noexcept;
645bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) noexcept;
646size_t qHash(const GraphicsPipelineStateKey &k, size_t seed = 0) noexcept;
647
654
655bool operator==(const ShaderKey &a, const ShaderKey &b) noexcept;
656bool operator!=(const ShaderKey &a, const ShaderKey &b) noexcept;
657size_t qHash(const ShaderKey &k, size_t seed = 0) noexcept;
658
669
670class ShaderManager : public QObject
671{
673public:
675
676 ShaderManager(QSGDefaultRenderContext *ctx) : context(ctx) { }
678 qDeleteAll(rewrittenShaders);
679 qDeleteAll(stockShaders);
680 }
681
683
685
688
689public Q_SLOTS:
690 void invalidated();
691
692public:
693 Shader *prepareMaterial(QSGMaterial *material,
694 const QSGGeometry *geometry = nullptr,
695 QSGRendererInterface::RenderMode renderMode = QSGRendererInterface::RenderMode2D,
696 int multiViewCount = 0);
697 Shader *prepareMaterialNoRewrite(QSGMaterial *material,
698 const QSGGeometry *geometry = nullptr,
699 QSGRendererInterface::RenderMode renderMode = QSGRendererInterface::RenderMode2D,
700 int multiViewCount = 0);
701
702private:
703 QHash<ShaderKey, Shader *> rewrittenShaders;
704 QHash<ShaderKey, Shader *> stockShaders;
705
706 QSGDefaultRenderContext *context;
707};
708
717
719{
720public:
728
729 Visualizer(Renderer *renderer);
730 virtual ~Visualizer();
731
733 void setMode(VisualizeMode mode) { m_visualizeMode = mode; }
734
735 virtual void visualizeChangesPrepare(Node *n, uint parentChanges = 0);
736 virtual void prepareVisualize() = 0;
737 virtual void visualize() = 0;
738
739 virtual void releaseResources() = 0;
740
741protected:
742 Renderer *m_renderer;
745};
746
747class Q_QUICK_EXPORT Renderer : public QSGRenderer
748{
749public:
751 ~Renderer();
752
753protected:
755 void render() override;
756 void prepareInline() override;
757 void renderInline() override;
759
764
777
778 // update batches and queue and commit rhi resource updates
780 // records the beginPass()
782 // records the draw calls, must be preceded by a prepareRenderPass at minimum,
783 // and also surrounded by begin/endRenderPass unless we are recording inside an
784 // already started pass.
786 // does visualizing if enabled and records the endPass()
788
789private:
790 enum RebuildFlag {
792 BuildRenderLists = 0x0002,
793 BuildBatches = 0x0004,
794 FullRebuild = 0xffff
795 };
796
797 friend class Updater;
798 friend class RhiVisualizer;
799
801 void map(Buffer *buffer, quint32 byteSize, bool isIndexBuf = false);
802 void unmap(Buffer *buffer, bool isIndexBuf = false);
803
806 void tagSubRoots(Node *node);
808
812 bool checkOverlap(int first, int last, const Rect &bounds);
813 void prepareAlphaBatches();
815
816 void uploadBatch(Batch *b);
817 void uploadMergedElement(Element *e, int vaOffset, char **vertexData, char **zData, char **indexData, void *iBasePtr, int *indexCount);
818
819 bool ensurePipelineState(Element *e, const ShaderManager::Shader *sms, bool depthPostPass = false);
823 char *directUpdatePtr);
834 void updateClip(const QSGClipNode *clipList, const Batch *batch);
838 void enqueueStencilDraw(const Batch *batch);
842 void renderRhiRenderNode(const Batch *batch);
845
852 void nodeWasRemoved(Node *node);
856
857 inline Batch *newBatch();
859 void releaseElement(Element *e, bool inDestructor = false);
860
863
870 bool m_partialRebuild;
873
878
883
888
891#if defined(QSGBATCHRENDERER_INVALIDATE_WEDGED_NODES)
894#endif
895
901
903
904 ShaderManager *m_shaderManager; // per rendercontext, shared
909
912
915
924 QRhiTexture *m_dummyTexture = nullptr;
925
926 struct StencilClipCommonData {
928 QRhiGraphicsPipeline *incrPs = nullptr;
929 QShader vs;
930 QShader fs;
933 inline void reset();
935
936 inline int mergedIndexElemSize() const;
937 inline bool useDepthBuffer() const;
938 inline void setStateForDepthPostPass();
939};
940
942{
943 Batch *b;
944 int size = m_batchPool.size();
945 if (size) {
946 b = m_batchPool.at(size - 1);
947 // vbo, ibo, ubuf, stencil-related buffers are reused
949 } else {
950 b = new Batch();
951 Q_ASSERT(offsetof(Batch, ibo) == sizeof(Buffer) + offsetof(Batch, vbo));
952 memset(&b->vbo, 0, sizeof(Buffer) * 2); // Clear VBO & IBO
953 b->ubuf = nullptr;
955 }
956 // initialize (when new batch) or reset (when reusing a batch) the non-reusable fields
957 b->init();
958 return b;
959}
960
961int Renderer::mergedIndexElemSize() const
962{
963 return m_uint32IndexForRhi ? sizeof(quint32) : sizeof(quint16);
964}
965
966// "use" here means that both depth test and write is wanted (the latter for
967// opaque batches only). Therefore neither RenderMode2DNoDepthBuffer nor
968// RenderMode3D must result in true. So while RenderMode3D requires a depth
969// buffer, this here must say false. In addition, m_forceNoDepthBuffer is a
970// dynamic override relevant with QSGRenderNode.
971//
972bool Renderer::useDepthBuffer() const
973{
975}
976
978{
979 m_gstate.colorWrite = {};
980 m_gstate.depthWrite = true;
981 m_gstate.depthTest = true;
983}
984
986{
987 delete replacePs;
988 replacePs = nullptr;
989
990 delete incrPs;
991 incrPs = nullptr;
992
993 vs = QShader();
994 fs = QShader();
995}
996
998{
999 clipList = nullptr;
1000 type = NoClip;
1001 stencilRef = 0;
1002}
1003
1005{
1006 updateStencilBuffer = false;
1007
1008 delete srb;
1009 srb = nullptr;
1010
1011 delete vbuf;
1012 vbuf = nullptr;
1013
1014 delete ibuf;
1015 ibuf = nullptr;
1016
1017 delete ubuf;
1018 ubuf = nullptr;
1019
1020 drawCalls.reset();
1021}
1022
1023}
1024
1029
1030QT_END_NAMESPACE
1031
1032#endif // QSGBATCHRENDERER_P_H
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:323
const Type * at(uint index) const
char data[sizeof(Type) *PageSize]
QList< AllocatorPage< Type, PageSize > * > pages
void releaseExplicit(uint pageIndex, uint index)
QMultiHash< QList< quint32 >, QRhiShaderResourceBindings * > srbPool
Shader * prepareMaterial(QSGMaterial *material, const QSGGeometry *geometry=nullptr, QSGRendererInterface::RenderMode renderMode=QSGRendererInterface::RenderMode2D, int multiViewCount=0)
QList< quint32 > srbLayoutDescSerializeWorkspace
QHash< GraphicsPipelineStateKey, QRhiGraphicsPipeline * > pipelineCache
ShaderManager(QSGDefaultRenderContext *ctx)
Shader * prepareMaterialNoRewrite(QSGMaterial *material, const QSGGeometry *geometry=nullptr, QSGRendererInterface::RenderMode renderMode=QSGRendererInterface::RenderMode2D, int multiViewCount=0)
void updateRootTransforms(Node *n, Node *root, const QMatrix4x4 &combined)
void registerWithParentRoot(QSGNode *subRoot, QSGNode *parentRoot)
void updateStates(QSGNode *n) override
void updateRootTransforms(Node *n)
virtual void visualize()=0
void setMode(VisualizeMode mode)
virtual void visualizeChangesPrepare(Node *n, uint parentChanges=0)
virtual void prepareVisualize()=0
virtual void releaseResources()=0
QHash< Node *, uint > m_visualizeChangeSet
const int ZORDER_BUFFER_BINDING
static void qsg_wipeBuffer(Buffer *buffer)
static void rendererToMaterialGraphicsState(QSGMaterialShader::GraphicsPipelineState *dst, GraphicsState *src)
size_t qHash(const GraphicsState &s, size_t seed) noexcept
static QRhiVertexInputLayout calculateVertexInputLayout(const QSGMaterialShader *s, const QSGGeometry *geometry, bool batchable)
static void qsg_addBackOrphanedElements(QDataBuffer< Element * > &orphans, QDataBuffer< Element * > &renderList)
bool operator!=(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) noexcept
const float VIEWPORT_MIN_DEPTH
QSGMaterial::Flag QSGMaterial_FullMatrix
bool qsg_sort_batch_decreasing_order(Batch *a, Batch *b)
QDebug operator<<(QDebug d, const Pt &p)
QDebug operator<<(QDebug d, const Rect &r)
bool operator==(const ShaderKey &a, const ShaderKey &b) noexcept
bool operator==(const GraphicsPipelineStateKey &a, const GraphicsPipelineStateKey &b) noexcept
bool operator!=(const ShaderKey &a, const ShaderKey &b) noexcept
static void qsg_wipeBatch(Batch *batch)
static QRhiSampler * newSampler(QRhi *rhi, const QSGSamplerDescription &desc)
QRhiVertexInputAttribute::Format qsg_vertexInputFormat(const QSGGeometry::Attribute &a)
QRhiGraphicsPipeline::Topology qsg_topology(int geomDrawMode, QRhi *rhi)
QMatrix4x4 qsg_matrixForRoot(Node *node)
bool qsg_sort_batch_increasing_order(Batch *a, Batch *b)
static void qsg_addOrphanedElements(QDataBuffer< Element * > &orphans, const QDataBuffer< Element * > &renderList)
void qsg_setMultiViewFlagsOnMaterial(QSGMaterial *material, int multiViewCount)
const float VIEWPORT_MAX_DEPTH
int qsg_positionAttribute(QSGGeometry *g)
static int size_of_type(int type)
static bool isTranslate(const QMatrix4x4 &m)
static int qsg_countNodesInBatches(const QDataBuffer< Batch * > &batches)
static float calculateElementZOrder(const Element *e, qreal zRange)
static int qsg_fixIndexCount(int iCount, int drawMode)
bool qsg_sort_element_increasing_order(Element *a, Element *b)
static void materialToRendererGraphicsState(GraphicsState *dst, QSGMaterialShader::GraphicsPipelineState *src)
static bool needsBlendConstant(QRhiGraphicsPipeline::BlendFactor f)
const int VERTEX_BUFFER_BINDING
const uint DYNAMIC_VERTEX_INDEX_BUFFER_THRESHOLD
bool hasMaterialWithBlending(QSGGeometryNode *n)
static int qsg_countNodesInBatch(const Batch *batch)
bool operator==(const GraphicsState &a, const GraphicsState &b) noexcept
QRhiCommandBuffer::IndexFormat qsg_indexFormat(const QSGGeometry *geometry)
bool operator!=(const GraphicsState &a, const GraphicsState &b) noexcept
bool qsg_sort_element_decreasing_order(Element *a, Element *b)
size_t qHash(const ShaderKey &k, size_t seed) noexcept
void qsg_dumpShadowRoots(BatchRootInfo *i, int indent)
void qsg_dumpShadowRoots(Node *n)
static bool isScale(const QMatrix4x4 &m)
static bool is2DSafe(const QMatrix4x4 &m)
size_t qHash(const GraphicsPipelineStateKey &k, size_t seed) noexcept
Int aligned(Int v, Int byteAlign)
const quint32 DEFAULT_BUFFER_POOL_SIZE_LIMIT
Combined button and popup list for selecting options.
Q_CORE_EXPORT QDebug operator<<(QDebug debug, QDir::Filters filters)
Definition qdir.cpp:2582
#define DECLARE_DEBUG_VAR(variable)
#define QSGNODE_DIRTY_PARENT
QT_BEGIN_NAMESPACE int qt_sg_envInt(const char *name, int defaultValue)
#define SHADOWNODE_TRAVERSE(NODE)
#define QSGNODE_TRAVERSE(NODE)
Q_DECLARE_TYPEINFO(QSGBatchRenderer::DrawSet, Q_PRIMITIVE_TYPE)
Q_DECLARE_TYPEINFO(QSGBatchRenderer::GraphicsState, Q_RELOCATABLE_TYPE)
Q_DECLARE_TYPEINFO(QSGBatchRenderer::GraphicsPipelineStateKey, Q_RELOCATABLE_TYPE)
#define QSG_RENDERER_COORD_LIMIT
Q_DECLARE_TYPEINFO(QSGBatchRenderer::RenderPassState, Q_RELOCATABLE_TYPE)
bool geometryWasChanged(QSGGeometryNode *gn)
BatchCompatibility isMaterialCompatible(Element *e) const
StencilClipState stencilClipState
QDataBuffer< DrawSet > drawSets
DrawSet(int v, int z, int i)
QRhiGraphicsPipeline * depthPostPassPs
QRhiShaderResourceBindings * srb
QRhiGraphicsPipeline * ps
void setNode(QSGGeometryNode *n)
static GraphicsPipelineStateKey create(const GraphicsState &state, const ShaderManagerShader *sms, const QRhiRenderPassDescriptor *rpDesc, const QRhiShaderResourceBindings *srb)
QSGGeometry::DrawingMode drawMode
QSGNode::NodeType type() const
BatchRootInfo * rootInfo() const
QSGNode::DirtyState dirtyState
ClipBatchRootInfo * clipInfo() const
RenderNodeElement * renderNodeElement() const
bool hasChild(Node *child) const
void map(const QMatrix4x4 &mat)
void set(float nx, float ny)
void operator|=(const Pt &pt)
void set(float left, float top, float right, float bottom)
void map(const QMatrix4x4 &m)
bool intersects(const Rect &r)
void operator|=(const Rect &r)
const QMatrix4x4 * projectionMatrix() const override
const QRegion * clipRegion() const override
QRhiDepthStencilClearValue dsClear
QSGRendererInterface::RenderMode renderMode
QVarLengthArray< QRhiShaderStage, 2 > stages
QRhiShaderResourceBindings * srb
QDataBuffer< StencilDrawCall > drawCalls