10#include <QtCore/QElapsedTimer>
11#include <QtCore/QtNumeric>
13#include <QtGui/QGuiApplication>
15#include <private/qnumeric_p.h>
33#define DECLARE_DEBUG_VAR(variable) \
34 static bool debug_ ## variable() \
35 { static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
45#undef DECLARE_DEBUG_VAR
47#define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling())
48#define SHADOWNODE_TRAVERSE(NODE) for (Node *child = NODE->firstChild(); child; child = child->sibling())
52 static int sizes[] = {
54 sizeof(
unsigned char),
56 sizeof(
unsigned short),
93 return (
v + byteAlign - 1) & ~(byteAlign - 1);
100 if (
a.tupleSize == 4)
102 if (
a.tupleSize == 3)
104 if (
a.tupleSize == 2)
106 if (
a.tupleSize == 1)
110 if (
a.tupleSize == 4)
112 if (
a.tupleSize == 2)
114 if (
a.tupleSize == 1)
120 qWarning(
"Unsupported attribute type 0x%x with %d components",
a.type,
a.tupleSize);
129 qWarning(
"No vertex shader in QSGMaterialShader %p",
s);
135 inputAttributes.
reserve(attrCount + 1);
137 for (
int i = 0;
i < attrCount; ++
i) {
140 qWarning(
"Vertex input %d is present in material but not in shader. This is wrong.",
181 switch (geomDrawMode) {
198 qWarning(
"Primitive topology 0x%x not supported", geomDrawMode);
264 stockShaders.clear();
266 rewrittenShaders.clear();
295 static int extraIndent = 0;
298 QByteArray ind(indent + extraIndent + 10,
' ');
303 qDebug() << ind.
constData() <<
"- parent:" <<
i->parentRoot <<
"orders" <<
i->firstOrder <<
"->" <<
i->lastOrder <<
", avail:" <<
i->availableOrders;
305 it !=
i->subRoots.constEnd(); ++
it) {
316#ifndef QT_NO_DEBUG_OUTPUT
317 static int indent = 0;
329 d <<
"order" <<
Qt::dec <<
n->element()->order;
348 m_rootMatrices.
add(m_identityMatrix);
356 m_transformChange = 0;
359 Node *sn = renderer->m_nodes.value(
n, 0);
366 qDebug(
"Updater::updateStates()");
368 qDebug(
" - nodes have been added");
370 qDebug(
" - transforms have changed");
372 qDebug(
" - opacity has changed");
385 if (m_added == 0 &&
n->dirtyState == 0 &&
m_force_update == 0 && m_transformChange == 0 && m_opacityChange == 0)
411 n->renderNodeElement()->root = m_roots.last();
429 if (m_roots.last() && m_added > 0)
430 renderer->registerBatchRoot(
n, m_roots.last());
457 bool was =
n->isOpaque;
460 renderer->m_rebuild = Renderer::FullRebuild;
477 bool popMatrixStack =
false;
478 bool popRootStack =
false;
483 if (
n->isBatchRoot) {
484 if (m_added > 0 && m_roots.last())
485 renderer->registerBatchRoot(
n, m_roots.last());
494 it !=
info->subRoots.constEnd(); ++
it) {
500 n->becameBatchRoot =
false;
506 popMatrixStack =
true;
511 popMatrixStack =
true;
541 e->root = m_roots.last();
546 while (
info !=
nullptr) {
547 info->availableOrders--;
548 if (
info->availableOrders < 0) {
549 renderer->m_rebuild |= Renderer::BuildRenderLists;
551 renderer->m_rebuild |= Renderer::BuildRenderListsForTaggedRoots;
552 renderer->m_taggedRoots <<
e->root;
554 if (
info->parentRoot !=
nullptr)
555 info = renderer->batchRootInfo(
info->parentRoot);
560 renderer->m_rebuild |= Renderer::FullRebuild;
563 if (m_transformChange) {
567 if (m_opacityChange) {
570 renderer->invalidateBatchAndOverlappingRenderOrders(
e->batch);
599 it !=
info->subRoots.constEnd(); ++
it) {
607 for (
int a=0;
a<
g->attributeCount(); ++
a) {
620 const float *
m =
matrix.constData();
641 set(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
658 bounds.
set(-FLT_MAX, -FLT_MAX, FLT_MAX, FLT_MAX);
662 bounds.
set(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
663 char *vd = (
char *)
g->vertexData() +
offset;
664 for (
int i=0;
i<
g->vertexCount(); ++
i) {
666 vd +=
g->sizeOfVertex();
689 while (
n && (
n ==
e ||
n->removed))
712 Q_ASSERT_X(
e,
"Batch::geometryWasChanged",
"Batch is expected to 'valid' at this time");
714 while (
e && (
e->node == gn ||
e->removed))
737 while (
e->nextInBatch) {
738 if (
e->nextInBatch->removed)
739 e->nextInBatch =
e->nextInBatch->nextInBatch;
762 e->nextInBatch =
nullptr;
771 only &=
e->translateOnlyToRoot;
797 if (
e->boundsOutsideFloatRange)
820 for (
int i=0;
i<batches.
size(); ++
i) {
829 , m_renderMode(renderMode)
830 , m_opaqueRenderList(64)
831 , m_alphaRenderList(64)
832 , m_nextRenderOrder(0)
833 , m_partialRebuild(
false)
834 , m_partialRebuildRoot(
nullptr)
835 , m_forceNoDepthBuffer(
false)
836 , m_opaqueBatches(16)
839 , m_elementsToDelete(64)
840 , m_tmpAlphaElements(16)
841 , m_tmpOpaqueElements(16)
842 , m_rebuild(FullRebuild)
844#
if defined(QSGBATCHRENDERER_INVALIDATE_WEDGED_NODES)
845 , m_renderOrderRebuildLower(-1)
846 , m_renderOrderRebuildUpper(-1)
850 , m_vertexUploadPool(256)
851 , m_indexUploadPool(64)
860 m_uint32IndexForRhi =
true;
870 if (!m_shaderManager) {
877 m_batchNodeThreshold =
qt_sg_envInt(
"QSG_RENDERER_BATCH_NODE_THRESHOLD", 64);
878 m_batchVertexThreshold =
qt_sg_envInt(
"QSG_RENDERER_BATCH_VERTEX_THRESHOLD", 1024);
879 m_srbPoolThreshold =
qt_sg_envInt(
"QSG_RENDERER_SRB_POOL_THRESHOLD", 1024);
881 if (
Q_UNLIKELY(debug_build() || debug_render())) {
882 qDebug(
"Batch thresholds: nodes: %d vertices: %d Srb pool threshold: %d",
883 m_batchNodeThreshold, m_batchVertexThreshold, m_srbPoolThreshold);
912 for (
int i = 0;
i < m_opaqueBatches.size(); ++
i)
914 for (
int i = 0;
i < m_alphaBatches.size(); ++
i)
916 for (
int i = 0;
i < m_batchPool.size(); ++
i)
920 for (
Node *
n : std::as_const(m_nodes)) {
924 m_elementsToDelete.add(
e);
926 m_nodeAllocator.release(
n);
930 for (
int i=0;
i<m_elementsToDelete.size(); ++
i)
931 releaseElement(m_elementsToDelete.at(
i),
true);
933 destroyGraphicsResources();
938void Renderer::destroyGraphicsResources()
947 m_stencilClipCommon.reset();
948 delete m_dummyTexture;
956 destroyGraphicsResources();
959 m_dummyTexture =
nullptr;
963 m_vertexUploadPool.
shrink(0);
964 m_vertexUploadPool.
reset();
965 m_indexUploadPool.
shrink(0);
966 m_indexUploadPool.
reset();
969void Renderer::invalidateAndRecycleBatch(
Batch *
b)
972 for (
int i=0;
i<m_batchPool.size(); ++
i)
973 if (
b == m_batchPool.at(
i))
978void Renderer::map(Buffer *
buffer,
quint32 byteSize,
bool isIndexBuf)
985 pool.resize(byteSize);
987 }
else if (
buffer->size != byteSize) {
989 buffer->data = (
char *) malloc(byteSize);
995void Renderer::unmap(Buffer *
buffer,
bool isIndexBuf)
1004 if (!
buffer->buf->create()) {
1005 qWarning(
"Failed to build vertex/index buffer of size %u",
buffer->size);
1010 bool needsRebuild =
false;
1013 needsRebuild =
true;
1019 buffer->nonDynamicChangeCount = 0;
1020 needsRebuild =
true;
1023 if (!
buffer->buf->create()) {
1024 qWarning(
"Failed to (re)build vertex/index buffer of size %u",
buffer->size);
1034 buffer->nonDynamicChangeCount += 1;
1044BatchRootInfo *Renderer::batchRootInfo(
Node *node)
1046 BatchRootInfo *
info = node->rootInfo();
1049 info =
new ClipBatchRootInfo;
1052 info =
new BatchRootInfo;
1059void Renderer::removeBatchRootFromParent(
Node *childRoot)
1061 BatchRootInfo *childInfo = batchRootInfo(childRoot);
1062 if (!childInfo->parentRoot)
1064 BatchRootInfo *parentInfo = batchRootInfo(childInfo->parentRoot);
1066 Q_ASSERT(parentInfo->subRoots.contains(childRoot));
1067 parentInfo->subRoots.remove(childRoot);
1068 childInfo->parentRoot =
nullptr;
1071void Renderer::registerBatchRoot(
Node *subRoot,
Node *parentRoot)
1073 BatchRootInfo *subInfo = batchRootInfo(subRoot);
1074 BatchRootInfo *parentInfo = batchRootInfo(parentRoot);
1075 subInfo->parentRoot = parentRoot;
1076 parentInfo->subRoots << subRoot;
1079bool Renderer::changeBatchRoot(
Node *node,
Node *root)
1081 BatchRootInfo *subInfo = batchRootInfo(node);
1082 if (subInfo->parentRoot == root)
1084 if (subInfo->parentRoot) {
1085 BatchRootInfo *oldRootInfo = batchRootInfo(subInfo->parentRoot);
1086 oldRootInfo->subRoots.remove(node);
1088 BatchRootInfo *newRootInfo = batchRootInfo(root);
1089 newRootInfo->subRoots << node;
1090 subInfo->parentRoot = root;
1094void Renderer::nodeChangedBatchRoot(
Node *node,
Node *root)
1099 changeBatchRoot(node, root);
1103 Element *
e = node->element();
1106 e->boundsComputed =
false;
1109 RenderNodeElement *
e = node->renderNodeElement();
1115 nodeChangedBatchRoot(
child, root);
1118void Renderer::nodeWasTransformed(
Node *node,
int *vertexCount)
1123 Element *
e = node->element();
1125 e->boundsComputed =
false;
1127 if (!
e->batch->isOpaque) {
1128 invalidateBatchAndOverlappingRenderOrders(
e->batch);
1129 }
else if (
e->batch->merged) {
1130 e->batch->needsUpload =
true;
1137 nodeWasTransformed(
child, vertexCount);
1140void Renderer::nodeWasAdded(
QSGNode *node,
Node *shadowParent)
1146 Node *snode = m_nodeAllocator.allocate();
1147 snode->sgNode = node;
1148 m_nodes.insert(node, snode);
1150 shadowParent->append(snode);
1153 snode->
data = m_elementAllocator.allocate();
1157 snode->
data =
new ClipBatchRootInfo;
1158 m_rebuild |= FullRebuild;
1162 RenderNodeElement *
e =
new RenderNodeElement(rn);
1164 Q_ASSERT(!m_renderNodeElements.contains(rn));
1165 m_renderNodeElements.insert(
e->renderNode,
e);
1167 m_forceNoDepthBuffer =
true;
1168 m_rebuild |= FullRebuild;
1172 nodeWasAdded(
child, snode);
1175void Renderer::nodeWasRemoved(
Node *node)
1185 node->remove(
child);
1186 nodeWasRemoved(
child);
1187 child = node->firstChild();
1192 Element *
e = node->element();
1195 m_elementsToDelete.add(
e);
1198 BatchRootInfo *
info = batchRootInfo(
e->root);
1199 info->availableOrders++;
1202 e->batch->needsUpload =
true;
1203 e->batch->needsPurge =
true;
1209 removeBatchRootFromParent(node);
1210 delete node->clipInfo();
1211 m_rebuild |= FullRebuild;
1212 m_taggedRoots.remove(node);
1214 }
else if (node->isBatchRoot) {
1215 removeBatchRootFromParent(node);
1216 delete node->rootInfo();
1217 m_rebuild |= FullRebuild;
1218 m_taggedRoots.remove(node);
1221 RenderNodeElement *
e = m_renderNodeElements.take(
static_cast<QSGRenderNode *
>(node->sgNode));
1224 m_elementsToDelete.add(
e);
1225 if (m_renderNodeElements.isEmpty())
1226 m_forceNoDepthBuffer =
false;
1228 if (
e->batch !=
nullptr)
1229 e->batch->needsPurge =
true;
1233 Q_ASSERT(m_nodes.contains(node->sgNode));
1235 m_nodeAllocator.release(m_nodes.take(node->sgNode));
1238void Renderer::turnNodeIntoBatchRoot(
Node *node)
1241 m_rebuild |= FullRebuild;
1242 node->isBatchRoot =
true;
1243 node->becameBatchRoot =
true;
1245 Node *
p = node->parent();
1248 registerBatchRoot(node,
p);
1255 nodeChangedBatchRoot(
child, node);
1261#ifndef QT_NO_DEBUG_OUTPUT
1266 debug <<
"Geometry";
1268 debug <<
"Material";
1278 debug <<
"SubtreeBlocked";
1280 debug <<
"ForceUpdate";
1293 Node *sn = m_nodes.value(node);
1297 m_rebuild |= FullRebuild;
1300 if (blocked && sn) {
1302 Q_ASSERT(m_nodes.value(node) == 0);
1303 }
else if (!blocked && !sn) {
1315 nodeWasAdded(node,
nullptr);
1317 nodeWasAdded(node, m_nodes.value(node->
parent()));
1321 Node *shadowNode = m_nodes.value(node);
1334 if (node->m_subtreeRenderableCount > m_batchNodeThreshold) {
1335 turnNodeIntoBatchRoot(shadowNode);
1338 nodeWasTransformed(shadowNode, &vertices);
1339 if (vertices > m_batchVertexThreshold) {
1340 turnNodeIntoBatchRoot(shadowNode);
1349 e->boundsComputed =
false;
1352 if (!
e->batch->geometryWasChanged(gn) || !
e->batch->isOpaque) {
1353 invalidateBatchAndOverlappingRenderOrders(
e->batch);
1355 b->needsUpload =
true;
1365 if (
e->isMaterialBlended != blended) {
1366 m_rebuild |= Renderer::FullRebuild;
1367 e->isMaterialBlended = blended;
1368 }
else if (
e->batch) {
1370 invalidateBatchAndOverlappingRenderOrders(
e->batch);
1372 m_rebuild |= Renderer::BuildBatches;
1383 if (dirtyChain != 0) {
1384 dirtyChain = QSGNode::DirtyState(dirtyChain << 16);
1396 parent->remove(shadowNode);
1397 nodeWasRemoved(shadowNode);
1398 Q_ASSERT(m_nodes.value(node) == 0);
1418void Renderer::buildRenderLists(
QSGNode *node)
1423 Node *shadowNode = m_nodes.value(node);
1433 if (opaque && useDepthBuffer())
1434 m_opaqueRenderList <<
e;
1436 m_alphaRenderList <<
e;
1438 e->order = ++m_nextRenderOrder;
1440 if (m_partialRebuild)
1441 e->orphaned =
false;
1445 BatchRootInfo *
info = batchRootInfo(shadowNode);
1446 if (node == m_partialRebuildRoot) {
1447 m_nextRenderOrder =
info->firstOrder;
1449 buildRenderLists(
child);
1450 m_nextRenderOrder =
info->lastOrder + 1;
1452 int currentOrder = m_nextRenderOrder;
1454 buildRenderLists(
child);
1455 int padding = (m_nextRenderOrder - currentOrder) >> 2;
1456 info->firstOrder = currentOrder;
1457 info->availableOrders = padding;
1458 info->lastOrder = m_nextRenderOrder + padding;
1459 m_nextRenderOrder =
info->lastOrder;
1464 m_alphaRenderList <<
e;
1465 e->order = ++m_nextRenderOrder;
1470 buildRenderLists(
child);
1473void Renderer::tagSubRoots(
Node *node)
1475 BatchRootInfo *
i = batchRootInfo(node);
1476 m_taggedRoots << node;
1478 it !=
i->subRoots.constEnd(); ++
it) {
1486 for (
int i=0;
i<renderList.
size(); ++
i) {
1488 if (
e && !
e->removed) {
1497 for (
int i=0;
i<orphans.
size(); ++
i) {
1519void Renderer::buildRenderListsForTaggedRoots()
1539 for (
int i=0;
i<m_opaqueBatches.size(); ++
i) {
1540 Batch *
b = m_opaqueBatches.at(
i);
1541 if (m_taggedRoots.contains(
b->root))
1542 invalidateAndRecycleBatch(
b);
1545 for (
int i=0;
i<m_alphaBatches.size(); ++
i) {
1546 Batch *
b = m_alphaBatches.at(
i);
1547 if (m_taggedRoots.contains(
b->root))
1548 invalidateAndRecycleBatch(
b);
1551 m_opaqueRenderList.reset();
1552 m_alphaRenderList.reset();
1553 int maxRenderOrder = m_nextRenderOrder;
1554 m_partialRebuild =
true;
1557 it != m_taggedRoots.constEnd(); ++
it) {
1559 BatchRootInfo *
i = batchRootInfo(root);
1560 if ((!
i->parentRoot || !m_taggedRoots.contains(
i->parentRoot))
1562 m_nextRenderOrder =
i->firstOrder;
1563 m_partialRebuildRoot = root->sgNode;
1564 buildRenderLists(root->sgNode);
1567 m_partialRebuild =
false;
1568 m_partialRebuildRoot =
nullptr;
1569 m_taggedRoots.clear();
1570 m_nextRenderOrder =
qMax(m_nextRenderOrder, maxRenderOrder);
1576 if (m_opaqueRenderList.size())
1578 if (m_alphaRenderList.size())
1583void Renderer::buildRenderListsFromScratch()
1585 m_opaqueRenderList.reset();
1586 m_alphaRenderList.reset();
1588 for (
int i=0;
i<m_opaqueBatches.size(); ++
i)
1589 invalidateAndRecycleBatch(m_opaqueBatches.at(
i));
1590 for (
int i=0;
i<m_alphaBatches.size(); ++
i)
1591 invalidateAndRecycleBatch(m_alphaBatches.at(
i));
1592 m_opaqueBatches.reset();
1593 m_alphaBatches.reset();
1595 m_nextRenderOrder = 0;
1600void Renderer::invalidateBatchAndOverlappingRenderOrders(Batch *batch)
1605#if defined(QSGBATCHRENDERER_INVALIDATE_WEDGED_NODES)
1606 if (m_renderOrderRebuildLower < 0 || batch->
first->order < m_renderOrderRebuildLower)
1607 m_renderOrderRebuildLower = batch->first->order;
1608 if (m_renderOrderRebuildUpper < 0 || batch->lastOrderInBatch > m_renderOrderRebuildUpper)
1609 m_renderOrderRebuildUpper = batch->lastOrderInBatch;
1611 int first = m_renderOrderRebuildLower;
1612 int last = m_renderOrderRebuildUpper;
1614 int first = batch->first->order;
1615 int last = batch->lastOrderInBatch;
1618 batch->invalidate();
1620 for (
int i=0;
i<m_alphaBatches.size(); ++
i) {
1621 Batch *
b = m_alphaBatches.at(
i);
1623 int bf =
b->first->order;
1624 int bl =
b->lastOrderInBatch;
1625 if (bl >
first && bf < last)
1630 m_rebuild |= BuildBatches;
1637 if (batches->
size()) {
1640 while (count < batches->
size() && batches->
at(
count)->first)
1643 invalidateAndRecycleBatch(batches->
at(
i));
1648void Renderer::prepareOpaqueBatches()
1650 for (
int i=m_opaqueRenderList.size() - 1;
i >= 0; --
i) {
1651 Element *ei = m_opaqueRenderList.at(
i);
1652 if (!ei || ei->batch || ei->node->geometry()->vertexCount() == 0)
1654 Batch *batch = newBatch();
1656 batch->root = ei->root;
1657 batch->isOpaque =
true;
1658 batch->needsUpload =
true;
1661 m_opaqueBatches.add(batch);
1668 for (
int j =
i - 1;
j >= 0; --
j) {
1669 Element *ej = m_opaqueRenderList.at(
j);
1672 if (ej->root != ei->root)
1674 if (ej->batch || ej->node->geometry()->vertexCount() == 0)
1687 next->nextInBatch = ej;
1692 batch->lastOrderInBatch =
next->order;
1696bool Renderer::checkOverlap(
int first,
int last,
const Rect &bounds)
1699 Element *
e = m_alphaRenderList.at(
i);
1700#if defined(QSGBATCHRENDERER_INVALIDATE_WEDGED_NODES)
1707 if (
e->bounds.intersects(bounds))
1724void Renderer::prepareAlphaBatches()
1726 for (
int i=0;
i<m_alphaRenderList.size(); ++
i) {
1727 Element *
e = m_alphaRenderList.at(
i);
1728 if (!
e ||
e->isRenderNode)
1731 e->ensureBoundsValid();
1734 for (
int i=0;
i<m_alphaRenderList.size(); ++
i) {
1735 Element *ei = m_alphaRenderList.at(
i);
1736 if (!ei || ei->batch)
1739 if (ei->isRenderNode) {
1740 Batch *rnb = newBatch();
1742 rnb->root = ei->root;
1743 rnb->isOpaque =
false;
1744 rnb->isRenderNode =
true;
1746 m_alphaBatches.add(rnb);
1750 if (ei->node->geometry()->vertexCount() == 0)
1753 Batch *batch = newBatch();
1755 batch->root = ei->root;
1756 batch->isOpaque =
false;
1757 batch->needsUpload =
true;
1758 m_alphaBatches.add(batch);
1765 overlapBounds.set(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
1769 for (
int j =
i + 1;
j < m_alphaRenderList.size(); ++
j) {
1770 Element *ej = m_alphaRenderList.at(
j);
1773 if (ej->root != ei->root || ej->isRenderNode)
1776#if !defined(QSGBATCHRENDERER_INVALIDATE_WEDGED_NODES)
1777 overlapBounds |= ej->bounds;
1797 if (!overlapBounds.intersects(ej->bounds) || !checkOverlap(
i+1,
j - 1, ej->bounds)) {
1799 next->nextInBatch = ej;
1810 overlapBounds |= ej->bounds;
1814 batch->lastOrderInBatch =
next->order;
1832 return iCount - (iCount % 2);
1835 return iCount - (iCount % 3);
1861void Renderer::uploadMergedElement(Element *
e,
int vaOffset,
char **vertexData,
char **zData,
char **indexData,
void *iBasePtr,
int *indexCount)
1863 if (
Q_UNLIKELY(debug_upload()))
qDebug() <<
" - uploading element:" <<
e <<
e->node << (
void *) *vertexData << (
qintptr) (*zData - *vertexData) << (
qintptr) (*indexData - *vertexData);
1867 const float *localxdata = localx.
constData();
1869 const int vCount =
g->vertexCount();
1870 const int vSize =
g->sizeOfVertex();
1871 memcpy(*vertexData,
g->vertexData(), vSize * vCount);
1874 char *vdata = *vertexData + vaOffset;
1876 for (
int i=0;
i<vCount; ++
i) {
1877 Pt *
p = (Pt *) vdata;
1878 p->x += localxdata[12];
1879 p->y += localxdata[13];
1883 for (
int i=0;
i<vCount; ++
i) {
1884 ((Pt *) vdata)->map(localx);
1889 if (useDepthBuffer()) {
1890 float *vzorder = (
float *) *zData;
1892 for (
int i=0;
i<vCount; ++
i)
1893 vzorder[
i] = zorder;
1894 *zData += vCount *
sizeof(float);
1897 int iCount =
g->indexCount();
1898 if (m_uint32IndexForRhi) {
1909 for (
int i=0;
i<iCount; ++
i)
1913 const quint16 *srcIndices =
g->indexDataAsUShort();
1915 *
indices++ = *iBase + srcIndices[0];
1919 for (
int i=0;
i<iCount; ++
i)
1938 for (
int i=0;
i<iCount; ++
i)
1941 const quint16 *srcIndices =
g->indexDataAsUShort();
1943 *
indices++ = *iBase + srcIndices[0];
1947 for (
int i=0;
i<iCount; ++
i)
1957 *vertexData += vCount * vSize;
1958 *indexData += iCount * mergedIndexElemSize();
1959 *indexCount += iCount;
1971void Renderer::uploadBatch(Batch *
b)
1974 if (!
b->needsUpload) {
1975 if (
Q_UNLIKELY(debug_upload()))
qDebug() <<
" Batch:" <<
b <<
"already uploaded...";
1984 if (
b->isRenderNode) {
1985 if (
Q_UNLIKELY(debug_upload()))
qDebug() <<
" Batch: " <<
b <<
"is a render node...";
1998 &&
b->positionAttribute >= 0
2002 &&
b->isSafeToBatch();
2004 b->merged = canMerge;
2009 int unmergedIndexSize = 0;
2010 Element *
e =
b->first;
2021 const int effectiveIndexSize = m_uint32IndexForRhi ?
sizeof(
quint32) : eg->sizeOfIndex();
2022 unmergedIndexSize += iCount * effectiveIndexSize;
2030 if (
b->vertexCount == 0 || (
b->merged &&
b->indexCount == 0))
2045 int bufferSize =
b->vertexCount *
g->sizeOfVertex();
2046 int ibufferSize = 0;
2048 ibufferSize =
b->indexCount * mergedIndexElemSize();
2049 if (useDepthBuffer())
2050 bufferSize +=
b->vertexCount *
sizeof(float);
2052 ibufferSize = unmergedIndexSize;
2055 map(&
b->ibo, ibufferSize,
true);
2056 map(&
b->vbo, bufferSize);
2058 if (
Q_UNLIKELY(debug_upload()))
qDebug() <<
" - batch" <<
b <<
" first:" <<
b->first <<
" root:"
2059 <<
b->root <<
" merged:" <<
b->merged <<
" positionAttribute" <<
b->positionAttribute
2060 <<
" vbo:" <<
b->vbo.buf <<
":" <<
b->vbo.size;
2063 char *vertexData =
b->vbo.data;
2064 char *zData = vertexData +
b->vertexCount *
g->sizeOfVertex();
2065 char *indexData =
b->ibo.data;
2070 uint verticesInSet = 0;
2074 const uint verticesInSetLimit = m_uint32IndexForRhi ? 0xfffffffe : 0xfffe;
2075 int indicesInSet = 0;
2076 b->drawSets.reset();
2077 int drawSetIndices = 0;
2078 const char *indexBase =
b->ibo.data;
2079 b->drawSets << DrawSet(0, zData - vertexData, drawSetIndices);
2081 verticesInSet +=
e->node->geometry()->vertexCount();
2082 if (verticesInSet > verticesInSetLimit) {
2083 b->drawSets.last().indexCount = indicesInSet;
2085 b->drawSets.last().indices += 1 * mergedIndexElemSize();
2086 b->drawSets.last().indexCount -= 2;
2088 drawSetIndices = indexData - indexBase;
2089 b->drawSets << DrawSet(vertexData -
b->vbo.data,
2090 zData -
b->vbo.data,
2094 verticesInSet =
e->node->geometry()->vertexCount();
2097 void *iBasePtr = &iOffset16;
2098 if (m_uint32IndexForRhi)
2099 iBasePtr = &iOffset32;
2100 uploadMergedElement(
e,
b->positionAttribute, &vertexData, &zData, &indexData, iBasePtr, &indicesInSet);
2103 b->drawSets.last().indexCount = indicesInSet;
2107 b->drawSets.last().indices += 1 * mergedIndexElemSize();
2108 b->drawSets.last().indexCount -= 2;
2111 char *vboData =
b->vbo.data;
2112 char *iboData =
b->ibo.data;
2113 Element *
e =
b->first;
2116 int vbs =
g->vertexCount() *
g->sizeOfVertex();
2117 memcpy(vboData,
g->vertexData(), vbs);
2118 vboData = vboData + vbs;
2119 const int indexCount =
g->indexCount();
2121 const int effectiveIndexSize = m_uint32IndexForRhi ?
sizeof(
quint32) :
g->sizeOfIndex();
2122 const int ibs = indexCount * effectiveIndexSize;
2123 if (
g->sizeOfIndex() == effectiveIndexSize) {
2124 memcpy(iboData,
g->indexData(), ibs);
2126 if (
g->sizeOfIndex() ==
sizeof(
quint16) && effectiveIndexSize ==
sizeof(
quint32)) {
2129 for (
int i = 0;
i < indexCount; ++
i)
2132 Q_ASSERT_X(
false,
"uploadBatch (unmerged)",
"uint index with ushort effective index - cannot happen");
2140#ifndef QT_NO_DEBUG_OUTPUT
2142 const char *vd =
b->vbo.data;
2143 qDebug() <<
" -- Vertex Data, count:" <<
b->vertexCount <<
" - " <<
g->sizeOfVertex() <<
"bytes/vertex";
2144 for (
int i=0;
i<
b->vertexCount; ++
i) {
2146 dump <<
" --- " <<
i <<
": ";
2148 for (
int a=0;
a<
g->attributeCount(); ++
a) {
2156 dump << *(
const float *)(vd +
offset +
t *
sizeof(float)) <<
" ";
2160 dump << *(
const unsigned char *)(vd +
offset +
t *
sizeof(
unsigned char)) <<
" ";
2165 if (
b->merged && useDepthBuffer()) {
2166 float zorder = ((
float*)(
b->vbo.data +
b->vertexCount *
g->sizeOfVertex()))[
i];
2167 dump <<
" Z:(" << zorder <<
")";
2169 vd +=
g->sizeOfVertex();
2172 if (!
b->drawSets.isEmpty()) {
2173 if (m_uint32IndexForRhi) {
2177 iDump <<
" -- Index Data, count:" <<
b->indexCount;
2178 for (
int i=0;
i<
b->indexCount; ++
i) {
2188 iDump <<
" -- Index Data, count:" <<
b->indexCount;
2189 for (
int i=0;
i<
b->indexCount; ++
i) {
2197 for (
int i=0;
i<
b->drawSets.size(); ++
i) {
2198 const DrawSet &
s =
b->drawSets.at(
i);
2199 qDebug() <<
" -- DrawSet: indexCount:" <<
s.indexCount <<
" vertices:" <<
s.vertices <<
" z:" <<
s.zorders <<
" indices:" <<
s.indices;
2206 unmap(&
b->ibo,
true);
2208 if (
Q_UNLIKELY(debug_upload()))
qDebug() <<
" --- vertex/index buffers unmapped, batch upload completed...";
2210 b->needsUpload =
false;
2213 b->uploadedThisFrame =
true;
2216void Renderer::applyClipStateToGraphicsState()
2222QRhiGraphicsPipeline *Renderer::buildStencilPipeline(
const Batch *batch,
bool firstStencilClipInBatch)
2232 if (firstStencilClipInBatch) {
2255 qWarning(
"Failed to build stencil clip pipeline");
2263void Renderer::updateClipState(
const QSGClipNode *clipList, Batch *batch)
2277 batch->stencilClipState.updateStencilBuffer =
false;
2279 applyClipStateToGraphicsState();
2280 batch->clipState = m_currentClipState;
2289 batch->stencilClipState.drawCalls.reset();
2293 const quint32 StencilClipUbufSize = 64;
2305 if (isRectangleWithNoPerspective && (noRotate || isRotate90)) {
2307 qreal invW = 1 /
m(3, 3);
2308 qreal fx1, fy1, fx2, fy2;
2310 fx1 = (bbox.
left() *
m(0, 0) +
m(0, 3)) * invW;
2311 fy1 = (bbox.
bottom() *
m(1, 1) +
m(1, 3)) * invW;
2312 fx2 = (bbox.
right() *
m(0, 0) +
m(0, 3)) * invW;
2313 fy2 = (bbox.
top() *
m(1, 1) +
m(1, 3)) * invW;
2316 fx1 = (bbox.
bottom() *
m(0, 1) +
m(0, 3)) * invW;
2317 fy1 = (bbox.
left() *
m(1, 0) +
m(1, 3)) * invW;
2318 fx2 = (bbox.
top() *
m(0, 1) +
m(0, 3)) * invW;
2319 fy2 = (bbox.
right() *
m(1, 0) +
m(1, 3)) * invW;
2336 scissorRect =
QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
2338 scissorRect &=
QRect(ix1, iy1, ix2 - ix1, iy2 - iy1);
2346 const int vertexByteSize =
g->sizeOfVertex() *
g->vertexCount();
2348 totalVSize =
aligned(totalVSize, 4u) + vertexByteSize;
2349 if (
g->indexCount()) {
2350 const int indexByteSize =
g->sizeOfIndex() *
g->indexCount();
2352 totalISize =
aligned(totalISize, 4u) + indexByteSize;
2355 totalUSize =
aligned(totalUSize, m_ubufAlignment) + StencilClipUbufSize;
2357 stencilClipNodes.
append(clip);
2364 bool rebuildVBuf =
false;
2365 if (!batch->stencilClipState.vbuf) {
2368 }
else if (batch->stencilClipState.vbuf->size() < totalVSize) {
2369 batch->stencilClipState.vbuf->
setSize(totalVSize);
2373 if (!batch->stencilClipState.vbuf->create()) {
2374 qWarning(
"Failed to build stencil clip vertex buffer");
2375 delete batch->stencilClipState.vbuf;
2376 batch->stencilClipState.vbuf =
nullptr;
2382 bool rebuildIBuf =
false;
2383 if (!batch->stencilClipState.ibuf) {
2386 }
else if (batch->stencilClipState.ibuf->size() < totalISize) {
2387 batch->stencilClipState.ibuf->
setSize(totalISize);
2391 if (!batch->stencilClipState.ibuf->create()) {
2392 qWarning(
"Failed to build stencil clip index buffer");
2393 delete batch->stencilClipState.ibuf;
2394 batch->stencilClipState.ibuf =
nullptr;
2400 bool rebuildUBuf =
false;
2401 if (!batch->stencilClipState.ubuf) {
2404 }
else if (batch->stencilClipState.ubuf->size() < totalUSize) {
2405 batch->stencilClipState.ubuf->
setSize(totalUSize);
2409 if (!batch->stencilClipState.ubuf->create()) {
2410 qWarning(
"Failed to build stencil clip uniform buffer");
2411 delete batch->stencilClipState.ubuf;
2412 batch->stencilClipState.ubuf =
nullptr;
2417 if (!batch->stencilClipState.srb) {
2421 batch->stencilClipState.srb->setBindings({ ubufBinding });
2422 if (!batch->stencilClipState.srb->create()) {
2423 qWarning(
"Failed to build stencil clip srb");
2424 delete batch->stencilClipState.srb;
2425 batch->stencilClipState.srb =
nullptr;
2433 for (
const QSGClipNode *clip : stencilClipNodes) {
2436 StencilClipState::StencilDrawCall drawCall;
2437 const bool firstStencilClipInBatch = batch->stencilClipState.drawCalls.isEmpty();
2439 if (firstStencilClipInBatch) {
2442 m_stencilClipCommon.topology =
qsg_topology(
g->drawingMode());
2446 if (
qsg_topology(
g->drawingMode()) != m_stencilClipCommon.topology)
2447 qWarning(
"updateClipState: Clip list entries have different primitive topologies, this is not currently supported.");
2449 qWarning(
"updateClipState: Clip list entries have different vertex input layouts, this is must not happen.");
2453 drawCall.vbufOffset =
aligned(vOffset, 4u);
2454 const int vertexByteSize =
g->sizeOfVertex() *
g->vertexCount();
2455 vOffset = drawCall.vbufOffset + vertexByteSize;
2457 int indexByteSize = 0;
2458 if (
g->indexCount()) {
2459 drawCall.ibufOffset =
aligned(iOffset, 4u);
2460 indexByteSize =
g->sizeOfIndex() *
g->indexCount();
2461 iOffset = drawCall.ibufOffset + indexByteSize;
2464 drawCall.ubufOffset =
aligned(uOffset, m_ubufAlignment);
2465 uOffset = drawCall.ubufOffset + StencilClipUbufSize;
2469 matrixYUpNDC *= *clip->
matrix();
2472 m_resourceUpdates->
updateDynamicBuffer(batch->stencilClipState.vbuf, drawCall.vbufOffset, vertexByteSize,
g->vertexData());
2474 m_resourceUpdates->
updateDynamicBuffer(batch->stencilClipState.ibuf, drawCall.ibufOffset, indexByteSize,
g->indexData());
2480 drawCall.stencilRef = firstStencilClipInBatch ? m_currentClipState.
stencilRef + 1 : m_currentClipState.
stencilRef;
2483 drawCall.vertexCount =
g->vertexCount();
2484 drawCall.indexCount =
g->indexCount();
2486 batch->stencilClipState.drawCalls.add(drawCall);
2489 if (!m_stencilClipCommon.vs.isValid())
2492 if (!m_stencilClipCommon.fs.isValid())
2495 if (!m_stencilClipCommon.replacePs)
2496 m_stencilClipCommon.replacePs = buildStencilPipeline(batch,
true);
2498 if (!m_stencilClipCommon.incrPs)
2499 m_stencilClipCommon.incrPs = buildStencilPipeline(batch,
false);
2501 batch->stencilClipState.updateStencilBuffer =
true;
2504 m_currentClipState.
clipList = clipList;
2505 m_currentClipState.
type = clipType;
2509 applyClipStateToGraphicsState();
2510 batch->clipState = m_currentClipState;
2513void Renderer::enqueueStencilDraw(
const Batch *batch)
2519 if (!batch->stencilClipState.updateStencilBuffer)
2523 const int count = batch->stencilClipState.drawCalls.size();
2525 const StencilClipState::StencilDrawCall &drawCall(batch->stencilClipState.drawCalls.at(
i));
2529 cb->setGraphicsPipeline(m_stencilClipCommon.replacePs);
2531 }
else if (
i == 1) {
2532 cb->setGraphicsPipeline(m_stencilClipCommon.incrPs);
2536 cb->setShaderResources(srb, 1, &ubufOffset);
2537 cb->setStencilRef(drawCall.stencilRef);
2539 if (drawCall.indexCount) {
2540 cb->setVertexInput(0, 1, &vbufBinding,
2541 batch->stencilClipState.ibuf, drawCall.ibufOffset, drawCall.indexFormat);
2542 cb->drawIndexed(drawCall.indexCount);
2544 cb->setVertexInput(0, 1, &vbufBinding);
2545 cb->draw(drawCall.vertexCount);
2554 m_currentShader =
shader;
2555 m_currentMaterial =
nullptr;
2613 e->depthPostPassPs = *
it;
2626 QRhiGraphicsPipeline::Flags
flags;
2671 qWarning(
"Failed to build graphics pipeline state");
2678 e->depthPostPassPs = ps;
2692 switch (
desc.filtering) {
2707 switch (
desc.mipmapFiltering) {
2723 switch (
desc.horizontalWrap) {
2739 switch (
desc.verticalWrap) {
2755 return rhi->
newSampler(magFilter, minFilter, mipmapMode, u,
v);
2760 if (!m_dummyTexture) {
2762 if (m_dummyTexture->
create()) {
2763 if (m_resourceUpdates) {
2770 return m_dummyTexture;
2776 dst->blendEnable =
src->blending;
2792 dst->separateBlendFactors =
false;
2797 dst->colorWrite = QSGMaterialShader::GraphicsPipelineState::ColorMask(
int(
src->colorWrite));
2806 dst->blending =
src->blendEnable;
2809 if (
src->separateBlendFactors) {
2813 dst->srcAlpha =
dst->srcColor;
2814 dst->dstAlpha =
dst->dstColor;
2816 dst->colorWrite = QRhiGraphicsPipeline::ColorMask(
int(
src->colorWrite));
2837 const bool changed =
shader->updateUniformData(renderState, material, m_currentMaterial);
2840 if (changed || !batch->ubufDataValid)
2861 shader->updateSampledImage(renderState, binding, nextTex.
data(), material,
2865 qWarning(
"No QSGTexture provided from updateSampledImage(). This is wrong.");
2869 bool hasDirtySamplerOptions =
false;
2870 bool isAnisotropic =
false;
2879 if (nextTex != prevTex || hasDirtySamplerOptions) {
2887 qWarning(
"QSGTexture anisotropy levels are not currently supported");
2899 qWarning(
"Failed to build sampler");
2903 m_samplers[samplerDesc] =
sampler;
2931 if (!textureSamplers.
isEmpty())
2939 qWarning(
"No shader resources for material %p, this is odd.", material);
2942 enum class SrbAction {
2947 } srbAction = SrbAction::Unknown;
2956 e->srb = m_shaderManager->
srbPool.take(layoutDesc);
2961 srbAction = SrbAction::UpdateResources;
2969 if (srbAction == SrbAction::Unknown &&
e->srb) {
2970 if (std::equal(
e->srb->cbeginBindings(),
e->srb->cendBindings(), bindings.
cbegin(), bindings.
cend())) {
2971 srbAction = SrbAction::DoNothing;
2972 }
else if (std::equal(
e->srb->cbeginBindings(),
e->srb->cendBindings(), bindings.
cbegin(), bindings.
cend(),
2973 [](
const auto &
a,
const auto &
b) { return a.isLayoutCompatible(b); }))
2975 srbAction = SrbAction::UpdateResources;
2977 srbAction = SrbAction::Rebake;
2985 srbAction = SrbAction::Rebake;
2988 Q_ASSERT(srbAction != SrbAction::Unknown &&
e->srb);
2990 switch (srbAction) {
2991 case SrbAction::DoNothing:
2993 case SrbAction::UpdateResources:
2995 e->srb->setBindings(bindings.
cbegin(), bindings.
cend());
2996 QRhiShaderResourceBindings::UpdateFlags
flags;
3005 e->srb->updateResources(
flags);
3008 case SrbAction::Rebake:
3009 e->srb->setBindings(bindings.
cbegin(), bindings.
cend());
3010 if (!
e->srb->create())
3014 Q_ASSERT_X(
false,
"updateMaterialDynamicData",
"No srb action set, this cannot happen");
3022 bool *gstateChanged)
3025 *gstateChanged =
false;
3032 const bool changed =
shader->updateGraphicsPipelineState(renderState, &shaderPs, material, m_currentMaterial);
3034 m_gstateStack.push(m_gstate);
3041 *gstateChanged =
true;
3046bool Renderer::prepareRenderMergedBatch(Batch *batch, PreparedRenderBatch *renderBatch)
3048 if (batch->vertexCount == 0 || batch->indexCount == 0)
3051 Element *
e = batch->first;
3054#ifndef QT_NO_DEBUG_OUTPUT
3059 << (batch->uploadedThisFrame ?
"[ upload]" :
"[retained]")
3060 << (
e->node->clipList() ?
"[ clip]" :
"[noclip]")
3061 << (batch->isOpaque ?
"[opaque]" :
"[ alpha]")
3064 <<
" Vertices:" <<
QString::fromLatin1(
"%1").
arg(batch->vertexCount, 5).toLatin1().constData()
3065 <<
" Indices:" <<
QString::fromLatin1(
"%1").
arg(batch->indexCount, 5).toLatin1().constData()
3066 <<
" root:" << batch->root;
3067 if (batch->drawSets.size() > 1)
3068 debug <<
"sets:" << batch->drawSets.size();
3069 if (!batch->isOpaque)
3070 debug <<
"opacity:" <<
e->node->inheritedOpacity();
3071 batch->uploadedThisFrame =
false;
3089 updateClipState(gn->
clipList(), batch);
3098 if (m_currentShader != sms)
3099 setActiveRhiShader(sms->materialShader, sms);
3110 bool ubufRebuild =
false;
3115 if (batch->ubuf->size() < ubufSize) {
3116 batch->ubuf->
setSize(ubufSize);
3121 batch->ubufDataValid =
false;
3122 if (!batch->ubuf->create()) {
3123 qWarning(
"Failed to build uniform buffer of size %u bytes", ubufSize);
3125 batch->ubuf =
nullptr;
3133 bool pendingGStatePop =
false;
3134 updateMaterialStaticData(sms, renderState, material, batch, &pendingGStatePop);
3136 updateMaterialDynamicData(sms, renderState, material, batch,
e, 0, ubufSize);
3140 qDebug(
"QSGMaterial::updateState triggered an error (merged), batch will be skipped:");
3143 qDebug() <<
" -" << ee->node;
3144 ee = ee->nextInBatch;
3147 qFatal(
"Aborting: scene graph is invalid...");
3154 const bool hasPipeline = ensurePipelineState(
e, sms);
3156 if (pendingGStatePop)
3157 m_gstate = m_gstateStack.pop();
3163 m_gstateStack.push(m_gstate);
3164 setStateForDepthPostPass();
3165 ensurePipelineState(
e, sms,
true);
3166 m_gstate = m_gstateStack.pop();
3169 batch->ubufDataValid =
true;
3171 m_currentMaterial = material;
3173 renderBatch->batch = batch;
3174 renderBatch->sms = sms;
3184 if (
g->lineWidth() != 1.0f) {
3185 static bool checkedWideLineSupport =
false;
3186 if (!checkedWideLineSupport) {
3187 checkedWideLineSupport =
true;
3189 qWarning(
"Line widths other than 1 are not supported by the graphics API");
3193 if (
g->lineWidth() != 1.0f) {
3194 static bool warnedPointSize =
false;
3195 if (!warnedPointSize) {
3196 warnedPointSize =
true;
3197 qWarning(
"Point size is not controllable by QSGGeometry. "
3198 "Set gl_PointSize from the vertex shader instead.");
3204void Renderer::renderMergedBatch(PreparedRenderBatch *renderBatch,
bool depthPostPass)
3206 const Batch *batch = renderBatch->batch;
3207 if (!batch->vbo.buf || !batch->ibo.buf)
3210 Element *
e = batch->first;
3216 enqueueStencilDraw(batch);
3219 setGraphicsPipeline(
cb, batch,
e, depthPostPass);
3221 for (
int i = 0, ie = batch->drawSets.size();
i != ie; ++
i) {
3222 const DrawSet &
draw = batch->drawSets.at(
i);
3230 cb->drawIndexed(
draw.indexCount);
3234bool Renderer::prepareRenderUnmergedBatch(Batch *batch, PreparedRenderBatch *renderBatch)
3236 if (batch->vertexCount == 0)
3239 Element *
e = batch->first;
3245 << (batch->uploadedThisFrame ?
"[ upload]" :
"[retained]")
3246 << (
e->node->clipList() ?
"[ clip]" :
"[noclip]")
3247 << (batch->isOpaque ?
"[opaque]" :
"[ alpha]")
3250 <<
" Vertices:" <<
QString::fromLatin1(
"%1").
arg(batch->vertexCount, 5).toLatin1().constData()
3251 <<
" Indices:" <<
QString::fromLatin1(
"%1").
arg(batch->indexCount, 5).toLatin1().constData()
3252 <<
" root:" << batch->root;
3254 batch->uploadedThisFrame =
false;
3262 updateClipState(gn->
clipList(), batch);
3276 if (m_currentShader != sms)
3277 setActiveRhiShader(sms->materialShader, sms);
3292 totalUBufSize +=
aligned(ubufSize, m_ubufAlignment);
3295 bool ubufRebuild =
false;
3300 if (batch->ubuf->size() < totalUBufSize) {
3301 batch->ubuf->
setSize(totalUBufSize);
3306 batch->ubufDataValid =
false;
3307 if (!batch->ubuf->create()) {
3308 qWarning(
"Failed to build uniform buffer of size %u bytes", totalUBufSize);
3310 batch->ubuf =
nullptr;
3317 bool pendingGStatePop =
false;
3318 updateMaterialStaticData(sms, renderState,
3319 material, batch, &pendingGStatePop);
3333 if (useDepthBuffer()) {
3339 updateMaterialDynamicData(sms, renderState, material, batch,
e, ubufOffset, ubufSize);
3343 qDebug(
"QSGMaterial::updateState() triggered an error (unmerged), batch will be skipped:");
3344 qDebug() <<
" - offending node is" <<
e->node;
3346 qFatal(
"Aborting: scene graph is invalid...");
3351 ubufOffset +=
aligned(ubufSize, m_ubufAlignment);
3354 const float prevLineWidth = m_gstate.
lineWidth;
3361 if (!ps || m_gstate.
drawMode != prevDrawMode || m_gstate.
lineWidth != prevLineWidth || pendingGStatePop) {
3362 if (!ensurePipelineState(
e, sms)) {
3363 if (pendingGStatePop)
3364 m_gstate = m_gstateStack.pop();
3369 m_gstateStack.push(m_gstate);
3370 setStateForDepthPostPass();
3371 ensurePipelineState(
e, sms,
true);
3372 m_gstate = m_gstateStack.pop();
3373 depthPostPassPs =
e->depthPostPassPs;
3378 e->depthPostPassPs = depthPostPassPs;
3383 m_currentMaterial = material;
3391 if (pendingGStatePop)
3392 m_gstate = m_gstateStack.pop();
3394 batch->ubufDataValid =
true;
3396 renderBatch->batch = batch;
3397 renderBatch->sms = sms;
3402void Renderer::renderUnmergedBatch(PreparedRenderBatch *renderBatch,
bool depthPostPass)
3404 const Batch *batch = renderBatch->batch;
3405 if (!batch->vbo.buf)
3408 Element *
e = batch->first;
3411 enqueueStencilDraw(batch);
3420 const int effectiveIndexSize = m_uint32IndexForRhi ?
sizeof(
quint32) :
g->sizeOfIndex();
3422 setGraphicsPipeline(
cb, batch,
e, depthPostPass);
3425 if (
g->indexCount()) {
3426 if (batch->ibo.buf) {
3428 batch->ibo.buf, iOffset,
3431 cb->drawIndexed(
g->indexCount());
3435 cb->draw(
g->vertexCount());
3438 vOffset +=
g->sizeOfVertex() *
g->vertexCount();
3439 iOffset +=
g->indexCount() * effectiveIndexSize;
3445void Renderer::setGraphicsPipeline(
QRhiCommandBuffer *
cb,
const Batch *batch, Element *
e,
bool depthPostPass)
3447 cb->setGraphicsPipeline(depthPostPass ?
e->depthPostPassPs :
e->ps);
3456 cb->setScissor(batch->clipState.scissor);
3470 cb->setStencilRef(batch->clipState.stencilRef);
3473 cb->setBlendConstants(batch->blendConstant);
3475 cb->setShaderResources(
e->srb);
3478void Renderer::releaseElement(Element *
e,
bool inDestructor)
3480 if (
e->isRenderNode) {
3481 delete static_cast<RenderNodeElement *
>(
e);
3484 if (!inDestructor) {
3485 if (m_shaderManager->
srbPool.size() < m_srbPoolThreshold)
3486 m_shaderManager->
srbPool.insert(
e->srb->serializedLayoutDescription(),
e->srb);
3494 m_elementAllocator.release(
e);
3498void Renderer::deleteRemovedElements()
3500 if (!m_elementsToDelete.size())
3503 for (
int i=0;
i<m_opaqueRenderList.size(); ++
i) {
3504 Element **
e = m_opaqueRenderList.data() +
i;
3505 if (*
e && (*e)->removed)
3508 for (
int i=0;
i<m_alphaRenderList.size(); ++
i) {
3509 Element **
e = m_alphaRenderList.data() +
i;
3510 if (*
e && (*e)->removed)
3514 for (
int i=0;
i<m_elementsToDelete.size(); ++
i)
3515 releaseElement(m_elementsToDelete.at(
i));
3517 m_elementsToDelete.reset();
3552 qWarning(
"prepareRenderPass() called with an already prepared render pass context");
3561 ctx->timeRenderLists = 0;
3562 ctx->timePrepareOpaque = 0;
3563 ctx->timePrepareAlpha = 0;
3564 ctx->timeSorting = 0;
3565 ctx->timeUploadOpaque = 0;
3566 ctx->timeUploadAlpha = 0;
3568 if (
Q_UNLIKELY(debug_render() || debug_build())) {
3572 if (m_rebuild == FullRebuild)
3575 if (m_rebuild & BuildRenderLists)
3576 type +=
" renderlists";
3577 else if (m_rebuild & BuildRenderListsForTaggedRoots)
3579 else if (m_rebuild & BuildBatches)
3583 qDebug() <<
"Renderer::render()" <<
this <<
type;
3589 if (m_rebuild & (BuildRenderLists | BuildRenderListsForTaggedRoots)) {
3590 bool complete = (m_rebuild & BuildRenderLists) != 0;
3592 buildRenderListsFromScratch();
3594 buildRenderListsForTaggedRoots();
3595 m_rebuild |= BuildBatches;
3598 qDebug(
"Opaque render lists %s:", (complete ?
"(complete)" :
"(partial)"));
3599 for (
int i=0;
i<m_opaqueRenderList.size(); ++
i) {
3601 qDebug() <<
" - element:" <<
e <<
" batch:" <<
e->batch <<
" node:" <<
e->node <<
" order:" <<
e->order;
3603 qDebug(
"Alpha render list %s:", complete ?
"(complete)" :
"(partial)");
3604 for (
int i=0;
i<m_alphaRenderList.size(); ++
i) {
3606 qDebug() <<
" - element:" <<
e <<
" batch:" <<
e->batch <<
" node:" <<
e->node <<
" order:" <<
e->order;
3610 if (
Q_UNLIKELY(debug_render()))
ctx->timeRenderLists =
ctx->timer.restart();
3612 for (
int i=0;
i<m_opaqueBatches.size(); ++
i)
3613 m_opaqueBatches.at(
i)->cleanupRemovedElements();
3614 for (
int i=0;
i<m_alphaBatches.size(); ++
i)
3615 m_alphaBatches.at(
i)->cleanupRemovedElements();
3616 deleteRemovedElements();
3618 cleanupBatches(&m_opaqueBatches);
3619 cleanupBatches(&m_alphaBatches);
3621 if (m_rebuild & BuildBatches) {
3622 prepareOpaqueBatches();
3623 if (
Q_UNLIKELY(debug_render()))
ctx->timePrepareOpaque =
ctx->timer.restart();
3624 prepareAlphaBatches();
3625 if (
Q_UNLIKELY(debug_render()))
ctx->timePrepareAlpha =
ctx->timer.restart();
3628 qDebug(
"Opaque Batches:");
3629 for (
int i=0;
i<m_opaqueBatches.size(); ++
i) {
3630 Batch *
b = m_opaqueBatches.at(
i);
3631 qDebug() <<
" - Batch " <<
i <<
b << (
b->needsUpload ?
"upload" :
"") <<
" root:" <<
b->root;
3633 qDebug() <<
" - element:" <<
e <<
" node:" <<
e->node <<
e->order;
3636 qDebug(
"Alpha Batches:");
3637 for (
int i=0;
i<m_alphaBatches.size(); ++
i) {
3638 Batch *
b = m_alphaBatches.at(
i);
3639 qDebug() <<
" - Batch " <<
i <<
b << (
b->needsUpload ?
"upload" :
"") <<
" root:" <<
b->root;
3641 qDebug() <<
" - element:" <<
e <<
e->bounds <<
" node:" <<
e->node <<
" order:" <<
e->order;
3646 if (
Q_UNLIKELY(debug_render()))
ctx->timePrepareOpaque =
ctx->timePrepareAlpha =
ctx->timer.restart();
3650 deleteRemovedElements();
3652 if (m_rebuild != 0) {
3655 if (m_opaqueBatches.size())
3659 if (m_alphaBatches.size())
3662 m_zRange = m_nextRenderOrder != 0
3663 ? 1.0 / (m_nextRenderOrder)
3671 m_vertexUploadPool.
reset();
3672 m_indexUploadPool.
reset();
3675 for (
int i=0;
i<m_opaqueBatches.size(); ++
i) {
3676 Batch *
b = m_opaqueBatches.at(
i);
3679 if (
Q_UNLIKELY(debug_render()))
ctx->timeUploadOpaque =
ctx->timer.restart();
3682 for (
int i=0;
i<m_alphaBatches.size(); ++
i) {
3683 Batch *
b = m_alphaBatches.at(
i);
3686 if (
Q_UNLIKELY(debug_render()))
ctx->timeUploadAlpha =
ctx->timer.restart();
3691 <<
" -> Alpha: " <<
qsg_countNodesInBatches(m_alphaBatches) <<
" nodes in " << m_alphaBatches.size() <<
" batches...";
3695 m_currentMaterial =
nullptr;
3696 m_currentShader =
nullptr;
3697 m_currentProgram =
nullptr;
3698 m_currentClipState.
reset();
3702 bool renderOpaque = !debug_noopaque();
3703 bool renderAlpha = !debug_noalpha();
3729 ctx->opaqueRenderBatches.clear();
3731 for (
int i = 0, ie = m_opaqueBatches.size();
i != ie; ++
i) {
3732 Batch *
b = m_opaqueBatches.at(
i);
3736 ok = prepareRenderMergedBatch(
b, &renderBatch);
3738 ok = prepareRenderUnmergedBatch(
b, &renderBatch);
3740 ctx->opaqueRenderBatches.append(renderBatch);
3755 Q_ASSERT(m_opaqueBatches.isEmpty());
3759 ctx->alphaRenderBatches.clear();
3761 for (
int i = 0, ie = m_alphaBatches.size();
i != ie; ++
i) {
3762 Batch *
b = m_alphaBatches.at(
i);
3766 ok = prepareRenderMergedBatch(
b, &renderBatch);
3767 else if (
b->isRenderNode)
3768 ok = prepareRhiRenderNode(
b, &renderBatch);
3770 ok = prepareRenderUnmergedBatch(
b, &renderBatch);
3772 ctx->alphaRenderBatches.append(renderBatch);
3778#if defined(QSGBATCHRENDERER_INVALIDATE_WEDGED_NODES)
3779 m_renderOrderRebuildLower = -1;
3780 m_renderOrderRebuildUpper = -1;
3787 m_resourceUpdates =
nullptr;
3817 qWarning(
"recordRenderPass() called without a prepared render pass context");
3824 for (
int i = 0, ie =
ctx->opaqueRenderBatches.size();
i != ie; ++
i) {
3829 renderMergedBatch(renderBatch);
3831 renderUnmergedBatch(renderBatch);
3834 for (
int i = 0, ie =
ctx->alphaRenderBatches.size();
i != ie; ++
i) {
3843 renderMergedBatch(renderBatch);
3845 renderRhiRenderNode(renderBatch->
batch);
3847 renderUnmergedBatch(renderBatch);
3857 for (
int i = 0, ie =
ctx->alphaRenderBatches.size();
i != ie; ++
i) {
3862 renderMergedBatch(renderBatch,
true);
3864 renderUnmergedBatch(renderBatch,
true);
3868 if (m_currentShader)
3869 setActiveRhiShader(
nullptr,
nullptr);
3874 qDebug(
" -> times: build: %d, prepare(opaque/alpha): %d/%d, sorting: %d, upload(opaque/alpha): %d/%d, record rendering: %d",
3875 (
int)
ctx->timeRenderLists,
3876 (
int)
ctx->timePrepareOpaque, (
int)
ctx->timePrepareAlpha,
3877 (
int)
ctx->timeSorting,
3878 (
int)
ctx->timeUploadOpaque, (
int)
ctx->timeUploadAlpha,
3879 (
int)
ctx->timer.elapsed());
3910bool Renderer::prepareRhiRenderNode(
Batch *batch, PreparedRenderBatch *renderBatch)
3913 qDebug() <<
" -" << batch <<
"rendernode";
3918 setActiveRhiShader(
nullptr,
nullptr);
3921 rd->m_clip_list =
nullptr;
3923 QSGNode *clip =
e->renderNode->parent();
3931 updateClipState(
rd->m_clip_list, batch);
3939 root =
e->root->sgNode;
3941 while (
xform != root) {
3949 rd->m_matrix = &
rd->m_localMatrix;
3951 QSGNode *opacity =
e->renderNode->parent();
3952 rd->m_opacity = 1.0;
3958 opacity = opacity->
parent();
3964 if (useDepthBuffer()) {
3965 rd->m_projectionMatrix(2, 2) = m_zRange;
3969 e->renderNode->prepare();
3971 renderBatch->batch = batch;
3972 renderBatch->sms =
nullptr;
3977void Renderer::renderRhiRenderNode(
const Batch *batch)
3980 enqueueStencilDraw(batch);
3982 RenderNodeElement *
e =
static_cast<RenderNodeElement *
>(batch->first);
3986 state.m_projectionMatrix = &
rd->m_projectionMatrix;
3987 const std::array<int, 4> scissor = batch->clipState.scissor.scissor();
3988 state.m_scissorRect =
QRect(scissor[0], scissor[1], scissor[2], scissor[3]);
3989 state.m_stencilValue = batch->clipState.stencilRef;
3993 const QSGRenderNode::StateFlags changes =
e->renderNode->changedStates();
3998 cb->beginExternal();
3999 e->renderNode->render(&
state);
4003 rd->m_matrix =
nullptr;
4004 rd->m_clip_list =
nullptr;
4025 else if (
mode ==
"clip")
4027 else if (
mode ==
"overdraw")
4029 else if (
mode ==
"batches")
4031 else if (
mode ==
"changes")
4042 return a.depthTest ==
b.depthTest
4043 &&
a.depthWrite ==
b.depthWrite
4044 &&
a.depthFunc ==
b.depthFunc
4045 &&
a.blending ==
b.blending
4046 &&
a.srcColor ==
b.srcColor
4047 &&
a.dstColor ==
b.dstColor
4048 &&
a.srcAlpha ==
b.srcAlpha
4049 &&
a.dstAlpha ==
b.dstAlpha
4050 &&
a.colorWrite ==
b.colorWrite
4051 &&
a.cullMode ==
b.cullMode
4052 &&
a.usesScissor ==
b.usesScissor
4053 &&
a.stencilTest ==
b.stencilTest
4054 &&
a.sampleCount ==
b.sampleCount
4055 &&
a.drawMode ==
b.drawMode
4056 &&
a.lineWidth ==
b.lineWidth
4057 &&
a.polygonMode ==
b.polygonMode;
4069 +
s.depthTest * 1000
4070 +
s.depthWrite * 100
4082 return a.state ==
b.state
4083 &&
a.sms->materialShader ==
b.sms->materialShader
4084 &&
a.renderTargetDescription ==
b.renderTargetDescription
4085 &&
a.srbLayoutDescription ==
b.srbLayoutDescription;
4096 ^
qHash(k.sms->materialShader)
4097 ^ k.extra.renderTargetDescriptionHash
4098 ^ k.extra.srbLayoutDescriptionHash;
4103 m_visualizeMode(VisualizeNothing)
4111#define QSGNODE_DIRTY_PARENT (QSGNode::DirtyNodeAdded \
4112 | QSGNode::DirtyOpacity \
4113 | QSGNode::DirtyMatrix \
4114 | QSGNode::DirtyNodeRemoved)
4119 uint selfDirty =
n->dirtyState | parentChanges;
4131#include "moc_qsgbatchrenderer_p.cpp"
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
void resize(qsizetype size)
void shrink(qsizetype size)
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
@ Format_RGBA8888_Premultiplied
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
double determinant() const
Returns the determinant of this matrix.
void setToIdentity()
Sets this matrix to the identity.
bool isIdentity() const
Returns true if this matrix is the identity; false otherwise.
const float * constData() const
Returns a constant pointer to the raw data of this matrix.
T findChild(const QString &aName=QString(), Qt::FindChildOptions options=Qt::FindChildrenRecursively) const
Returns the child of this object that can be cast into type T and that is called name,...
QObject * parent() const
Returns a pointer to the parent object.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void setParent(QObject *parent)
Makes the object a child of parent.
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
\inmodule QtCore\reentrant
constexpr qreal bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height of the rectangle.
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr int width() const noexcept
Returns the width of the rectangle.
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
The QRegion class specifies a clip region for a painter.
void setSize(quint32 sz)
Sets the size of the buffer in bytes.
void endPass(QRhiResourceUpdateBatch *resourceUpdates=nullptr)
Records ending the current render pass.
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
Sometimes committing resource updates is necessary or just more convenient without starting a render ...
void beginPass(QRhiRenderTarget *rt, const QColor &colorClearValue, const QRhiDepthStencilClearValue &depthStencilClearValue, QRhiResourceUpdateBatch *resourceUpdates=nullptr, BeginPassFlags flags={})
Records starting a new render pass targeting the render target rt.
QPair< int, quint32 > DynamicOffset
Synonym for QPair<int, quint32>.
IndexFormat
Specifies the index data type.
void setStencilFront(const StencilOpState &state)
Sets the stencil test state for front faces.
void setCullMode(CullMode mode)
Sets the specified face culling mode.
PolygonMode
Specifies the polygon rasterization mode.
void setTargetBlends(std::initializer_list< TargetBlend > list)
Sets the list of render target blend settings.
void setStencilTest(bool enable)
Enables or disables stencil tests based on enable.
BlendFactor
Specifies the blend factor.
void setDepthWrite(bool enable)
Controls the writing out of depth data into the depth buffer based on enable.
void setShaderResourceBindings(QRhiShaderResourceBindings *srb)
Associates with srb describing the resource binding layout and the resources (QRhiBuffer,...
void setDepthOp(CompareOp op)
Sets the depth comparison function op.
void setVertexInputLayout(const QRhiVertexInputLayout &layout)
Specifies the vertex input layout.
CullMode
Specifies the culling mode.
void setFlags(Flags f)
Sets the flags f.
void setShaderStages(std::initializer_list< QRhiShaderStage > list)
Sets the list of shader stages.
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Associates with the specified QRhiRenderPassDescriptor desc.
void setSampleCount(int s)
Sets the sample count.
void setTopology(Topology t)
Sets the primitive topology t.
Topology
Specifies the primitive topology.
virtual bool create()=0
Creates the corresponding native graphics resources.
void setDepthTest(bool enable)
Enables or disables depth testing based on enable.
void setPolygonMode(PolygonMode mode)
Sets the polygon mode.
void setLineWidth(float width)
Sets the line width.
void setStencilBack(const StencilOpState &state)
Sets the stencil test state for back faces.
virtual int sampleCount() const =0
void updateDynamicBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Enqueues updating a region of a QRhiBuffer buf created with the type QRhiBuffer::Dynamic.
void uploadStaticBuffer(QRhiBuffer *buf, quint32 offset, quint32 size, const void *data)
Enqueues updating a region of a QRhiBuffer buf created with the type QRhiBuffer::Immutable or QRhiBuf...
void uploadTexture(QRhiTexture *tex, const QRhiTextureUploadDescription &desc)
Enqueues uploading the image data for one or more mip levels in one or more layers of the texture tex...
Filter
Specifies the minification, magnification, or mipmap filtering.
AddressMode
Specifies the addressing mode.
static void serializeLayoutDescription(const QRhiShaderResourceBinding *first, const QRhiShaderResourceBinding *last, Output dst)
static QRhiShaderResourceBinding sampledTextures(int binding, StageFlags stage, int count, const TextureAndSampler *texSamplers)
static QRhiShaderResourceBinding uniformBufferWithDynamicOffset(int binding, StageFlags stage, QRhiBuffer *buf, quint32 size)
static QRhiShaderResourceBinding uniformBuffer(int binding, StageFlags stage, QRhiBuffer *buf)
virtual bool create()=0
Creates the corresponding native graphics resources.
QRhiBuffer * newBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
bool isFeatureSupported(QRhi::Feature feature) const
QRhiShaderResourceBindings * newShaderResourceBindings()
QRhiSampler * newSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, QRhiSampler::Filter mipmapMode, QRhiSampler::AddressMode addressU, QRhiSampler::AddressMode addressV, QRhiSampler::AddressMode addressW=QRhiSampler::Repeat)
QRhiGraphicsPipeline * newGraphicsPipeline()
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
@ NonFourAlignedEffectiveIndexBufferOffset
QRhiResourceUpdateBatch * nextResourceUpdateBatch()
int ubufAlignment() const
void releaseCachedResources()
Attempts to release resources in the backend's caches.
QRect deviceRect() const
Returns the device rect of the surface being rendered to.
QRect viewportRect() const
Returns the rect of the viewport to render.
QMatrix4x4 projectionMatrix() const
Returns the projection matrix.
QSGRootNode * rootNode() const
Returns the root of the QSGNode scene.
QMatrix4x4 projectionMatrixWithNativeNDC() const
QColor clearColor() const
Returns the color that clears the framebuffer at the beginning of the rendering.
const QSGClipNode * clipList() const
Will be set during rendering to contain the clip of the geometry for that rendering pass.
const QSGGeometry * geometry() const
Returns this node's geometry.
void setRendererClipList(const QSGClipNode *c)
void setRendererMatrix(const QMatrix4x4 *m)
const QMatrix4x4 * matrix() const
Will be set during rendering to contain transformation of the geometry for that rendering pass.
void beginRenderPass(RenderPassContext *ctx)
friend class RhiVisualizer
bool hasVisualizationModeWithContinuousUpdate() const override
void releaseCachedResources() override
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override
Updates internal data structures and emits the sceneGraphChanged() signal.
void setVisualizationMode(const QByteArray &mode) override
void renderInline() override
void prepareInline() override
void recordRenderPass(RenderPassContext *ctx)
void prepareRenderPass(RenderPassContext *ctx)
Renderer(QSGDefaultRenderContext *ctx, QSGRendererInterface::RenderMode renderMode=QSGRendererInterface::RenderMode2D)
void endRenderPass(RenderPassContext *ctx)
void clearCachedRendererData()
QMultiHash< QVector< quint32 >, QRhiShaderResourceBindings * > srbPool
Shader * prepareMaterial(QSGMaterial *material, const QSGGeometry *geometry=nullptr, QSGRendererInterface::RenderMode renderMode=QSGRendererInterface::RenderMode2D)
Shader * prepareMaterialNoRewrite(QSGMaterial *material, const QSGGeometry *geometry=nullptr, QSGRendererInterface::RenderMode renderMode=QSGRendererInterface::RenderMode2D)
QHash< GraphicsPipelineStateKey, QRhiGraphicsPipeline * > pipelineCache
QVector< quint32 > srbLayoutDescSerializeWorkspace
ShaderManagerShader Shader
void visitClipNode(Node *n)
void updateStates(QSGNode *n) override
void visitOpacityNode(Node *n)
void updateRootTransforms(Node *n)
void visitTransformNode(Node *n)
void visitGeometryNode(Node *n)
virtual void visualize()=0
Visualizer(Renderer *renderer)
void setMode(VisualizeMode mode)
virtual void visualizeChangesPrepare(Node *n, uint parentChanges=0)
virtual void prepareVisualize()=0
VisualizeMode mode() const
virtual void releaseResources()=0
QHash< Node *, uint > m_visualizeChangeSet
The QSGClipNode class implements the clipping functionality in the scene graph.
bool isRectangular() const
Returns if this clip node has a rectangular clip.
QRectF clipRect() const
Returns the clip rect of this node.
virtual void initializeRhiShader(QSGMaterialShader *shader, QShader::Variant shaderVariant)
QRhi * rhi() const override
The QSGGeometryNode class is used for all rendered content in the scene graph.
qreal inheritedOpacity() const
Set during rendering to specify the inherited opacity for that rendering pass.
QSGMaterial * activeMaterial() const
Returns the material which should currently be used for geometry node.
void setInheritedOpacity(qreal opacity)
Sets the inherited opacity of this geometry to opacity.
The QSGGeometry class provides low-level storage for graphics primitives in the \l{Qt Quick Scene Gra...
unsigned int drawingMode() const
Returns the drawing mode of this geometry.
DrawingMode
Specifies the drawing mode, also called primitive topology.
const Attribute * attributes() const
Returns an array with the attributes of this geometry.
int attributeCount() const
Returns the number of attributes in the attrbute set used by this geometry.
int indexType() const
Returns the primitive type used for indices in this geometry object.
int sizeOfVertex() const
Returns the size in bytes of one vertex.
int indexCount() const
Returns the number of indices in this geometry object.
float lineWidth() const
Gets the current line or point width or to be used for this geometry.
int vertexCount() const
Returns the number of vertices in this geometry object.
QVarLengthArray< QRhiSampler *, 4 > samplerBindingTable[MAX_SHADER_RESOURCE_BINDINGS]
void clearCachedRendererData()
QRhiShaderResourceBinding::StageFlags combinedImageSamplerBindings[MAX_SHADER_RESOURCE_BINDINGS]
int combinedImageSamplerCount[MAX_SHADER_RESOURCE_BINDINGS]
static const int MAX_SHADER_RESOURCE_BINDINGS
static QSGMaterialShaderPrivate * get(QSGMaterialShader *s)
QByteArray masterUniformData
ShaderStageData * vertexShader
QRhiShaderResourceBinding::StageFlags ubufStages
QVarLengthArray< QSGTexture *, 4 > textureBindingTable[MAX_SHADER_RESOURCE_BINDINGS]
QShader shader(QShader::Stage stage) const
static QShader loadShader(const QString &filename)
Encapsulates the current rendering state during a call to QSGMaterialShader::updateUniformData() and ...
The QSGMaterialShader class represents a graphics API independent shader program.
@ UpdatesGraphicsPipelineState
The QSGMaterial class encapsulates rendering state for a shader program.
virtual QSGMaterialShader * createShader(QSGRendererInterface::RenderMode renderMode) const =0
This function returns a new instance of a the QSGMaterialShader implementation used to render geometr...
QSGMaterial::Flags flags() const
Returns the material's flags.
virtual int compare(const QSGMaterial *other) const
Compares this material to other and returns 0 if they are equal; -1 if this material should sort befo...
virtual QSGMaterialType * type() const =0
This function is called by the scene graph to query an identifier that is unique to the QSGMaterialSh...
Flag
\value Blending Set this flag to true if the material requires blending to be enabled during renderin...
@ RequiresFullMatrixExceptTranslate
static void dump(QSGNode *n)
QDataBuffer< qreal > m_opacity_stack
const QSGClipNode * m_current_clip
QDataBuffer< const QMatrix4x4 * > m_combined_matrix_stack
\group qtquick-scenegraph-nodes \title Qt Quick Scene Graph Node classes
virtual bool isSubtreeBlocked() const
Returns whether this node and its subtree is available for use.
QSGNode * parent() const
Returns the parent node of this node.
NodeType type() const
Returns the type of this node.
The QSGOpacityNode class is used to change opacity of nodes.
qreal opacity() const
Returns this opacity node's opacity.
void setCombinedOpacity(qreal opacity)
Sets the combined opacity of this node to opacity.
static QSGRenderNodePrivate * get(QSGRenderNode *node)
The QSGRenderNode class represents a set of custom rendering commands targeting the graphics API that...
virtual RenderingFlags flags() const
QRhiRenderPassDescriptor * rpDesc
RenderMode
\value RenderMode2D Normal 2D rendering \value RenderMode2DNoDepthBuffer Normal 2D rendering with dep...
The renderer class is the abstract baseclass used for rendering the QML scene graph.
QMatrix4x4 m_current_projection_matrix_native_ndc
QMatrix4x4 m_current_projection_matrix
void setNodeUpdater(QSGNodeUpdater *updater)
Sets the node updater that this renderer uses to update states in the scene graph.
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override
Updates internal data structures and emits the sceneGraphChanged() signal.
const QSGRenderTarget & renderTarget() const
QRhiResourceUpdateBatch * m_current_resource_update_batch
QMatrix4x4 m_current_model_view_matrix
QByteArray * m_current_uniform_data
qreal m_current_determinant
QSGNodeUpdater * nodeUpdater() const
Returns the node updater that this renderer uses to update states in the scene graph.
struct QSGRenderer::@693 m_renderPassRecordingCallbacks
static QSGTexturePrivate * get(QSGTexture *t)
void resetDirtySamplerOptions()
bool hasDirtySamplerOptions() const
virtual QRhiTexture * rhiTexture() const
const_iterator constBegin() const noexcept
const_iterator constEnd() const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
QChar * data()
Returns a pointer to the data stored in the QString.
constexpr size_type size() const noexcept
const T & at(qsizetype idx) const
void resize(qsizetype sz)
const_iterator cbegin() const noexcept
const_iterator cend() const noexcept
bool contains(const AT &t) const
const T * constData() const
void reserve(qsizetype sz)
QMap< QString, QString > map
[6]
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
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)
const float VIEWPORT_MIN_DEPTH
QSGMaterial::Flag QSGMaterial_FullMatrix
bool qsg_sort_batch_decreasing_order(Batch *a, Batch *b)
static void qsg_wipeBatch(Batch *batch)
static QRhiSampler * newSampler(QRhi *rhi, const QSGSamplerDescription &desc)
QRhiVertexInputAttribute::Format qsg_vertexInputFormat(const QSGGeometry::Attribute &a)
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)
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)
void qsg_dumpShadowRoots(BatchRootInfo *i, int indent)
static bool isScale(const QMatrix4x4 &m)
static bool is2DSafe(const QMatrix4x4 &m)
QRhiGraphicsPipeline::Topology qsg_topology(int geomDrawMode)
Int aligned(Int v, Int byteAlign)
bool qsg_sort_batch_is_valid(Batch *a, Batch *b)
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
QTextStream & endl(QTextStream &stream)
Writes '\n' to the stream and flushes the stream.
#define QByteArrayLiteral(str)
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
bool qFuzzyIsNull(qfloat16 f) noexcept
int qRound(qfloat16 d) noexcept
constexpr const T & qMax(const T &a, const T &b)
static Q_DECL_CONST_FUNCTION bool qt_is_finite(double d)
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint GLintptr offset
GLsizei GLenum const void * indices
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
constexpr decltype(auto) qMakePair(T1 &&value1, T2 &&value2) noexcept(noexcept(std::make_pair(std::forward< T1 >(value1), std::forward< T2 >(value2))))
#define DECLARE_DEBUG_VAR(variable)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
#define Q_ASSERT_X(cond, x, msg)
int qt_sg_envInt(const char *name, int defaultValue)
#define QSGNODE_DIRTY_PARENT
QT_BEGIN_NAMESPACE Q_QUICK_PRIVATE_EXPORT bool qsg_test_and_clear_material_failure()
#define SHADOWNODE_TRAVERSE(NODE)
#define QSGNODE_TRAVERSE(NODE)
static QString dump(const QByteArray &)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
QLatin1StringView QLatin1String
#define QStringLiteral(str)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
QFuture< QSet< QChar > > set
[10]
Q_CHECK_PTR(a=new int[80])
if(qFloatDistance(a, b)<(1<< 7))
[0]
QRandomGenerator64 rd
[10]
QFileInfo info(fileName)
[8]
view viewport() -> scroll(dx, dy, deviceRect)
myFilter draw(painter, QPoint(0, 0), originalPixmap)
QSvgRenderer * renderer
[0]
\variable QRhiGraphicsPipeline::TargetBlend::colorWrite
bool geometryWasChanged(QSGGeometryNode *gn)
void cleanupRemovedElements()
bool isTranslateOnlyToRoot() const
bool isSafeToBatch() const
StencilClipState stencilClipState
BatchCompatibility isMaterialCompatible(Element *e) const
const QSGClipNode * clipList
uint boundsOutsideFloatRange
static GraphicsPipelineStateKey create(const GraphicsState &state, const ShaderManagerShader *sms, const QRhiRenderPassDescriptor *rpDesc, const QRhiShaderResourceBindings *srb)
QSGGeometry::DrawingMode drawMode
QRhiGraphicsPipeline::BlendFactor dstColor
QRhiGraphicsPipeline::CompareOp depthFunc
QRhiGraphicsPipeline::ColorMask colorWrite
QRhiGraphicsPipeline::CullMode cullMode
QRhiGraphicsPipeline::BlendFactor srcAlpha
QRhiGraphicsPipeline::BlendFactor dstAlpha
QRhiGraphicsPipeline::BlendFactor srcColor
QRhiGraphicsPipeline::PolygonMode polygonMode
QSGNode::NodeType type() const
QSGNode::DirtyState dirtyState
RenderNodeElement * renderNodeElement() const
Element * element() const
void map(const QMatrix4x4 &mat)
void set(float left, float top, float right, float bottom)
void map(const QMatrix4x4 &m)
bool isOutsideFloatRange() const
bool stencilEnabled() const override
QRect scissorRect() const override
const QMatrix4x4 * projectionMatrix() const override
const QRegion * clipRegion() const override
bool scissorEnabled() const override
int stencilValue() const override
const QMatrix4x4 * m_projectionMatrix
QRhiDepthStencilClearValue dsClear
The QSGGeometry::Attribute describes a single vertex attribute in a QSGGeometry.
QVector< int > vertexInputLocations
int qt_order_attrib_location
Describes state changes that the material wants to apply to the currently active graphics pipeline st...
PolygonMode
Specifies the polygon rasterization mode.
The QSGMaterialType class is used as a unique type token in combination with QSGMaterial.
static QSGSamplerDescription fromTexture(QSGTexture *t)