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
qsgrhivisualizer.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 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
8#include <qmath.h>
9#include <private/qsgmaterialshader_p.h>
10
12
13namespace QSGBatchRenderer
14{
15
16#define QSGNODE_TRAVERSE(NODE) for (QSGNode *child = NODE->firstChild(); child; child = child->nextSibling())
17#define SHADOWNODE_TRAVERSE(NODE) for (Node *child = NODE->firstChild(); child; child = child->sibling())
18#define QSGNODE_DIRTY_PARENT (QSGNode::DirtyNodeAdded
19 | QSGNode::DirtyOpacity
20 | QSGNode::DirtyMatrix
21 | QSGNode::DirtyNodeRemoved)
22
24QRhiVertexInputAttribute::Format qsg_vertexInputFormat(const QSGGeometry::Attribute &a);
25QRhiCommandBuffer::IndexFormat qsg_indexFormat(const QSGGeometry *geometry);
26QRhiGraphicsPipeline::Topology qsg_topology(int geomDrawMode, QRhi *rhi);
27
28RhiVisualizer::RhiVisualizer(Renderer *renderer)
29 : Visualizer(renderer)
30{
31}
32
37
39{
40 m_pipelines.releaseResources();
41
42 m_fade.releaseResources();
43
44 m_changeVis.releaseResources();
45 m_batchVis.releaseResources();
46 m_clipVis.releaseResources();
47 m_overdrawVis.releaseResources();
48}
49
51{
52 // Called before the render pass has begun (but after preparing the
53 // batches). Now is the time to put resource updates to the renderer's
54 // current m_resourceUpdates instance.
55
56 if (m_visualizeMode == VisualizeNothing)
57 return;
58
59 if (!m_vs.isValid()) {
60 m_vs = QSGMaterialShaderPrivate::loadShader(
61 QLatin1String(":/qt-project.org/scenegraph/shaders_ng/visualization.vert.qsb"));
62 m_fs = QSGMaterialShaderPrivate::loadShader(
63 QLatin1String(":/qt-project.org/scenegraph/shaders_ng/visualization.frag.qsb"));
64 }
65
66 m_fade.prepare(this, m_renderer->m_rhi, m_renderer->m_resourceUpdates, m_renderer->renderTarget().rpDesc);
67
68 const bool forceUintIndex = m_renderer->m_uint32IndexForRhi;
69
70 switch (m_visualizeMode) {
71 case VisualizeBatches:
72 m_batchVis.prepare(m_renderer->m_opaqueBatches, m_renderer->m_alphaBatches,
73 this,
74 m_renderer->m_rhi, m_renderer->m_resourceUpdates,
75 forceUintIndex);
76 break;
77 case VisualizeClipping:
78 m_clipVis.prepare(m_renderer->rootNode(), this,
79 m_renderer->m_rhi, m_renderer->m_resourceUpdates);
80 break;
81 case VisualizeChanges:
82 m_changeVis.prepare(m_renderer->m_nodes.value(m_renderer->rootNode()),
83 this,
84 m_renderer->m_rhi, m_renderer->m_resourceUpdates);
85 m_visualizeChangeSet.clear();
86 break;
87 case VisualizeOverdraw:
88 m_overdrawVis.prepare(m_renderer->m_nodes.value(m_renderer->rootNode()),
89 this,
90 m_renderer->m_rhi, m_renderer->m_resourceUpdates);
91 break;
92 default:
93 Q_UNREACHABLE();
94 break;
95 }
96}
97
99{
100 if (m_visualizeMode == VisualizeNothing)
101 return;
102
103 QRhiCommandBuffer *cb = m_renderer->renderTarget().cb;
104 m_fade.render(cb);
105
106 switch (m_visualizeMode) {
107 case VisualizeBatches:
108 m_batchVis.render(cb);
109 break;
110 case VisualizeClipping:
111 m_clipVis.render(cb);
112 break;
113 case VisualizeChanges:
114 m_changeVis.render(cb);
115 break;
116 case VisualizeOverdraw:
117 m_overdrawVis.render(cb);
118 break;
119 default:
120 Q_UNREACHABLE();
121 break;
122 }
123}
124
125void RhiVisualizer::recordDrawCalls(const QList<DrawCall> &drawCalls,
126 QRhiCommandBuffer *cb,
127 QRhiShaderResourceBindings *srb,
128 bool blendOneOne)
129{
130 for (const DrawCall &dc : drawCalls) {
131 QRhiGraphicsPipeline *ps = m_pipelines.pipeline(this, m_renderer->m_rhi, srb, m_renderer->renderTarget().rpDesc,
132 dc.vertex.topology, dc.vertex.format, dc.vertex.stride,
133 blendOneOne);
134 if (!ps)
135 continue;
136 cb->setGraphicsPipeline(ps); // no-op if same as the last one
137 QRhiCommandBuffer::DynamicOffset dynofs(0, dc.buf.ubufOffset);
138 cb->setShaderResources(srb, 1, &dynofs);
139 QRhiCommandBuffer::VertexInput vb(dc.buf.vbuf, dc.buf.vbufOffset);
140 if (dc.index.count) {
141 cb->setVertexInput(0, 1, &vb, dc.buf.ibuf, dc.buf.ibufOffset, dc.index.format);
142 cb->drawIndexed(dc.index.count);
143 } else {
144 cb->setVertexInput(0, 1, &vb);
145 cb->draw(dc.vertex.count);
146 }
147 }
148}
149
152
153void RhiVisualizer::Fade::prepare(RhiVisualizer *visualizer,
154 QRhi *rhi, QRhiResourceUpdateBatch *u, QRhiRenderPassDescriptor *rpDesc)
155{
156 this->visualizer = visualizer;
157
158 if (!vbuf) {
159 float v[] = { -1, 1, 1, 1, -1, -1, 1, -1 };
160 vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(v));
161 if (!vbuf->create())
162 return;
163 u->uploadStaticBuffer(vbuf, v);
164 }
165
166 if (!ubuf) {
167 ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, DrawCall::UBUF_SIZE);
168 if (!ubuf->create())
169 return;
170 float bgOpacity = 0.8f;
171 if (visualizer->m_visualizeMode == Visualizer::VisualizeBatches)
172 bgOpacity = 1.0;
173 QMatrix4x4 ident;
174 u->updateDynamicBuffer(ubuf, 0, 64, ident.constData()); // matrix
175 u->updateDynamicBuffer(ubuf, 64, 64, ident.constData()); // rotation
176 float color[4] = { 0.0f, 0.0f, 0.0f, bgOpacity };
177 u->updateDynamicBuffer(ubuf, 128, 16, color);
178 float pattern = 0.0f;
179 u->updateDynamicBuffer(ubuf, 144, 4, &pattern);
180 qint32 projection = 0;
181 u->updateDynamicBuffer(ubuf, 148, 4, &projection);
182 }
183
184 if (!srb) {
185 srb = rhi->newShaderResourceBindings();
186 srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, ubufVisibility, ubuf) });
187 if (!srb->create())
188 return;
189 }
190
191 if (!ps) {
192 ps = rhi->newGraphicsPipeline();
193 ps->setTopology(QRhiGraphicsPipeline::TriangleStrip);
194 QRhiGraphicsPipeline::TargetBlend blend; // defaults to premul alpha, just what we need
195 blend.enable = true;
196 ps->setTargetBlends({ blend });
197 ps->setShaderStages({ { QRhiShaderStage::Vertex, visualizer->m_vs },
198 { QRhiShaderStage::Fragment, visualizer->m_fs } });
199 QRhiVertexInputLayout inputLayout;
200 inputLayout.setBindings({ { 2 * sizeof(float) } });
201 inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float2, 0 } });
202 ps->setVertexInputLayout(inputLayout);
203 ps->setShaderResourceBindings(srb);
204 ps->setRenderPassDescriptor(rpDesc);
205 if (!ps->create())
206 return;
207 }
208}
209
210void RhiVisualizer::Fade::releaseResources()
211{
212 delete ps;
213 ps = nullptr;
214
215 delete srb;
216 srb = nullptr;
217
218 delete ubuf;
219 ubuf = nullptr;
220
221 delete vbuf;
222 vbuf = nullptr;
223}
224
225void RhiVisualizer::Fade::render(QRhiCommandBuffer *cb)
226{
227 cb->setGraphicsPipeline(ps);
228 cb->setViewport(visualizer->m_renderer->m_pstate.viewport);
229 cb->setShaderResources();
230 QRhiCommandBuffer::VertexInput vb(vbuf, 0);
231 cb->setVertexInput(0, 1, &vb);
232 cb->draw(4);
233}
234
235static void fillVertexIndex(RhiVisualizer::DrawCall *dc, QSGGeometry *g, bool withData, bool forceUintIndex, QRhi *rhi)
236{
237 dc->vertex.topology = qsg_topology(g->drawingMode(), rhi);
238 dc->vertex.format = qsg_vertexInputFormat(g->attributes()[0]);
239 dc->vertex.count = g->vertexCount();
240 dc->vertex.stride = g->sizeOfVertex();
241 if (withData)
242 dc->vertex.data = g->vertexData();
243
244 dc->index.format = forceUintIndex ? QRhiCommandBuffer::IndexUInt32 : qsg_indexFormat(g);
245 dc->index.count = g->indexCount();
246 dc->index.stride = forceUintIndex ? sizeof(quint32) : g->sizeOfIndex();
247 if (withData && g->indexCount())
248 dc->index.data = g->indexData();
249}
250
251static inline uint aligned(uint v, uint byteAlign)
252{
253 return (v + byteAlign - 1) & ~(byteAlign - 1);
254}
255
256static bool ensureBuffer(QRhi *rhi, QRhiBuffer **buf, QRhiBuffer::UsageFlags usage, quint32 newSize)
257{
258 if (!*buf) {
259 *buf = rhi->newBuffer(QRhiBuffer::Dynamic, usage, newSize);
260 if (!(*buf)->create())
261 return false;
262 } else if ((*buf)->size() < newSize) {
263 (*buf)->setSize(newSize);
264 if (!(*buf)->create())
265 return false;
266 }
267 return true;
268}
269
270QRhiGraphicsPipeline *RhiVisualizer::PipelineCache::pipeline(RhiVisualizer *visualizer,
271 QRhi *rhi,
272 QRhiShaderResourceBindings *srb,
273 QRhiRenderPassDescriptor *rpDesc,
274 QRhiGraphicsPipeline::Topology topology,
275 QRhiVertexInputAttribute::Format vertexFormat,
276 quint32 vertexStride,
277 bool blendOneOne)
278{
279 for (int i = 0, ie = pipelines.size(); i != ie; ++i) {
280 const Pipeline &p(pipelines.at(i));
281 if (p.topology == topology && p.format == vertexFormat && p.stride == vertexStride)
282 return p.ps;
283 }
284
285 QRhiGraphicsPipeline *ps = rhi->newGraphicsPipeline();
286 ps->setTopology(topology);
287 QRhiGraphicsPipeline::TargetBlend blend; // premul alpha
288 blend.enable = true;
289 if (blendOneOne) {
290 // only for visualizing overdraw, other modes use premul alpha
291 blend.srcColor = QRhiGraphicsPipeline::One;
292 blend.dstColor = QRhiGraphicsPipeline::One;
293 blend.srcAlpha = QRhiGraphicsPipeline::One;
294 blend.dstAlpha = QRhiGraphicsPipeline::One;
295 }
296 ps->setTargetBlends({ blend });
297 ps->setShaderStages({ { QRhiShaderStage::Vertex, visualizer->m_vs },
298 { QRhiShaderStage::Fragment, visualizer->m_fs } });
299 QRhiVertexInputLayout inputLayout;
300 inputLayout.setBindings({ { vertexStride } });
301 inputLayout.setAttributes({ { 0, 0, vertexFormat, 0 } });
302 ps->setVertexInputLayout(inputLayout);
303 ps->setShaderResourceBindings(srb);
304 ps->setRenderPassDescriptor(rpDesc);
305 if (!ps->create())
306 return nullptr;
307
308 Pipeline p;
309 p.topology = topology;
310 p.format = vertexFormat;
311 p.stride = vertexStride;
312 p.ps = ps;
313 pipelines.append(p);
314
315 return ps;
316}
317
318void RhiVisualizer::PipelineCache::releaseResources()
319{
320 for (int i = 0, ie = pipelines.size(); i != ie; ++i)
321 delete pipelines.at(i).ps;
322
323 pipelines.clear();
324}
325
326void RhiVisualizer::ChangeVis::gather(Node *n)
327{
328 if (n->type() == QSGNode::GeometryNodeType && n->element()->batch && visualizer->m_visualizeChangeSet.contains(n)) {
329 const uint dirty = visualizer->m_visualizeChangeSet.value(n);
330 const bool tinted = (dirty & QSGNODE_DIRTY_PARENT) != 0;
331 const QColor color = QColor::fromHsvF((visualizer->m_randomGenerator.generate() & 1023) / 1023.0f, 0.3f, 1.0f).toRgb();
332 const float alpha = 0.5f;
333
334 QMatrix4x4 matrix = visualizer->m_renderer->m_current_projection_matrix[0];
335 if (n->element()->batch->root)
336 matrix = matrix * qsg_matrixForRoot(n->element()->batch->root);
337
338 QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(n->sgNode);
339 matrix = matrix * *gn->matrix();
340
341 QSGGeometry *g = gn->geometry();
342 if (g->attributeCount() >= 1) {
343 DrawCall dc;
344 memcpy(dc.uniforms.data, matrix.constData(), 64);
345 QMatrix4x4 rotation;
346 memcpy(dc.uniforms.data + 64, rotation.constData(), 64);
347 float c[4] = {
348 float(color.redF()) * alpha,
349 float(color.greenF()) * alpha,
350 float(color.blueF()) * alpha,
351 alpha
352 };
353 memcpy(dc.uniforms.data + 128, c, 16);
354 float pattern = tinted ? 0.5f : 0.0f;
355 memcpy(dc.uniforms.data + 144, &pattern, 4);
356 qint32 projection = 0;
357 memcpy(dc.uniforms.data + 148, &projection, 4);
358
359 fillVertexIndex(&dc, g, true, false, visualizer->m_renderer->m_rhi);
360 drawCalls.append(dc);
361 }
362
363 // This is because many changes don't propegate their dirty state to the
364 // parent so the node updater will not unset these states. They are
365 // not used for anything so, unsetting it should have no side effects.
366 n->dirtyState = { };
367 }
368
370 gather(child);
371 }
372}
373
374void RhiVisualizer::ChangeVis::prepare(Node *n, RhiVisualizer *visualizer,
375 QRhi *rhi, QRhiResourceUpdateBatch *u)
376{
377 this->visualizer = visualizer;
378
379 drawCalls.clear();
380 gather(n);
381
382 if (drawCalls.isEmpty())
383 return;
384
385 const int ubufAlign = rhi->ubufAlignment();
386 int vbufOffset = 0;
387 int ibufOffset = 0;
388 int ubufOffset = 0;
389 for (RhiVisualizer::DrawCall &dc : drawCalls) {
390 dc.buf.vbufOffset = aligned(vbufOffset, 4);
391 vbufOffset = dc.buf.vbufOffset + dc.vertex.count * dc.vertex.stride;
392
393 dc.buf.ibufOffset = aligned(ibufOffset, 4);
394 ibufOffset = dc.buf.ibufOffset + dc.index.count * dc.index.stride;
395
396 dc.buf.ubufOffset = aligned(ubufOffset, ubufAlign);
397 ubufOffset = dc.buf.ubufOffset + DrawCall::UBUF_SIZE;
398 }
399
400 ensureBuffer(rhi, &vbuf, QRhiBuffer::VertexBuffer, vbufOffset);
401 if (ibufOffset)
402 ensureBuffer(rhi, &ibuf, QRhiBuffer::IndexBuffer, ibufOffset);
403 const int ubufSize = ubufOffset;
404 ensureBuffer(rhi, &ubuf, QRhiBuffer::UniformBuffer, ubufSize);
405
406 for (RhiVisualizer::DrawCall &dc : drawCalls) {
407 u->updateDynamicBuffer(vbuf, dc.buf.vbufOffset, dc.vertex.count * dc.vertex.stride, dc.vertex.data);
408 dc.buf.vbuf = vbuf;
409 if (dc.index.count) {
410 u->updateDynamicBuffer(ibuf, dc.buf.ibufOffset, dc.index.count * dc.index.stride, dc.index.data);
411 dc.buf.ibuf = ibuf;
412 }
413 u->updateDynamicBuffer(ubuf, dc.buf.ubufOffset, DrawCall::UBUF_SIZE, dc.uniforms.data);
414 }
415
416 if (!srb) {
417 srb = rhi->newShaderResourceBindings();
418 srb->setBindings({ QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, ubufVisibility, ubuf, DrawCall::UBUF_SIZE) });
419 if (!srb->create())
420 return;
421 }
422}
423
424void RhiVisualizer::ChangeVis::releaseResources()
425{
426 delete srb;
427 srb = nullptr;
428
429 delete ubuf;
430 ubuf = nullptr;
431
432 delete ibuf;
433 ibuf = nullptr;
434
435 delete vbuf;
436 vbuf = nullptr;
437}
438
439void RhiVisualizer::ChangeVis::render(QRhiCommandBuffer *cb)
440{
441 visualizer->recordDrawCalls(drawCalls, cb, srb);
442}
443
444void RhiVisualizer::BatchVis::gather(Batch *b)
445{
446 if (b->positionAttribute != 0)
447 return;
448
449 QMatrix4x4 matrix(visualizer->m_renderer->m_current_projection_matrix[0]);
450 if (b->root)
451 matrix = matrix * qsg_matrixForRoot(b->root);
452
453 DrawCall dc;
454
455 QMatrix4x4 rotation;
456 memcpy(dc.uniforms.data + 64, rotation.constData(), 64);
457
458 const QColor color = QColor::fromHsvF((visualizer->m_randomGenerator.generate() & 1023) / 1023.0, 1.0, 1.0).toRgb();
459
460 float c[4] = {
461 float(color.redF()),
462 float(color.greenF()),
463 float(color.blueF()),
464 1.0f
465 };
466 memcpy(dc.uniforms.data + 128, c, 16);
467
468 float pattern = b->merged ? 0.0f : 1.0f;
469 memcpy(dc.uniforms.data + 144, &pattern, 4);
470
471 qint32 projection = 0;
472 memcpy(dc.uniforms.data + 148, &projection, 4);
473
474 if (b->merged) {
475 memcpy(dc.uniforms.data, matrix.constData(), 64);
476
477 QSGGeometryNode *gn = b->first->node;
478 QSGGeometry *g = gn->geometry();
479
480 fillVertexIndex(&dc, g, false, forceUintIndex, visualizer->m_renderer->m_rhi);
481
482 for (int ds = 0; ds < b->drawSets.size(); ++ds) {
483 const DrawSet &set = b->drawSets.at(ds);
484 dc.buf.vbuf = b->vbo.buf;
485 dc.buf.vbufOffset = set.vertices;
486 dc.buf.ibuf = b->ibo.buf;
487 dc.buf.ibufOffset = set.indices;
488 dc.index.count = set.indexCount;
489 drawCalls.append(dc);
490 }
491 } else {
492 Element *e = b->first;
493 int vOffset = 0;
494 int iOffset = 0;
495
496 while (e) {
497 QSGGeometryNode *gn = e->node;
498 QSGGeometry *g = gn->geometry();
499
500 QMatrix4x4 m = matrix * *gn->matrix();
501 memcpy(dc.uniforms.data, m.constData(), 64);
502
503 fillVertexIndex(&dc, g, false, forceUintIndex, visualizer->m_renderer->m_rhi);
504
505 dc.buf.vbuf = b->vbo.buf;
506 dc.buf.vbufOffset = vOffset;
507 if (g->indexCount()) {
508 dc.buf.ibuf = b->ibo.buf;
509 dc.buf.ibufOffset = iOffset;
510 }
511
512 drawCalls.append(dc);
513
514 vOffset += dc.vertex.count * dc.vertex.stride;
515 iOffset += dc.index.count * dc.index.stride;
516
517 e = e->nextInBatch;
518 }
519 }
520}
521
522void RhiVisualizer::BatchVis::prepare(const QDataBuffer<Batch *> &opaqueBatches, const QDataBuffer<Batch *> &alphaBatches,
523 RhiVisualizer *visualizer,
524 QRhi *rhi, QRhiResourceUpdateBatch *u,
525 bool forceUintIndex)
526{
527 this->visualizer = visualizer;
528 this->forceUintIndex = forceUintIndex;
529
530 drawCalls.clear();
531
532 for (int i = 0; i < opaqueBatches.size(); ++i)
533 gather(opaqueBatches.at(i));
534 for (int i = 0; i < alphaBatches.size(); ++i)
535 gather(alphaBatches.at(i));
536
537 if (drawCalls.isEmpty())
538 return;
539
540 const int ubufAlign = rhi->ubufAlignment();
541 int ubufOffset = 0;
542 for (RhiVisualizer::DrawCall &dc : drawCalls) {
543 dc.buf.ubufOffset = aligned(ubufOffset, ubufAlign);
544 ubufOffset = dc.buf.ubufOffset + DrawCall::UBUF_SIZE;
545 }
546
547 const int ubufSize = ubufOffset;
548 ensureBuffer(rhi, &ubuf, QRhiBuffer::UniformBuffer, ubufSize);
549
550 for (RhiVisualizer::DrawCall &dc : drawCalls)
551 u->updateDynamicBuffer(ubuf, dc.buf.ubufOffset, DrawCall::UBUF_SIZE, dc.uniforms.data);
552
553 if (!srb) {
554 srb = rhi->newShaderResourceBindings();
555 srb->setBindings({ QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, ubufVisibility, ubuf, DrawCall::UBUF_SIZE) });
556 if (!srb->create())
557 return;
558 }
559}
560
561void RhiVisualizer::BatchVis::releaseResources()
562{
563 delete srb;
564 srb = nullptr;
565
566 delete ubuf;
567 ubuf = nullptr;
568}
569
570void RhiVisualizer::BatchVis::render(QRhiCommandBuffer *cb)
571{
572 visualizer->recordDrawCalls(drawCalls, cb, srb);
573}
574
575void RhiVisualizer::ClipVis::gather(QSGNode *node)
576{
577 if (node->type() == QSGNode::ClipNodeType) {
578 QSGClipNode *clipNode = static_cast<QSGClipNode *>(node);
579 QMatrix4x4 matrix = visualizer->m_renderer->m_current_projection_matrix[0];
580 if (clipNode->matrix())
581 matrix = matrix * *clipNode->matrix();
582
583 QSGGeometry *g = clipNode->geometry();
584 if (g->attributeCount() >= 1) {
585 DrawCall dc;
586 memcpy(dc.uniforms.data, matrix.constData(), 64);
587 QMatrix4x4 rotation;
588 memcpy(dc.uniforms.data + 64, rotation.constData(), 64);
589 float c[4] = { 0.2f, 0.0f, 0.0f, 0.2f };
590 memcpy(dc.uniforms.data + 128, c, 16);
591 float pattern = 0.5f;
592 memcpy(dc.uniforms.data + 144, &pattern, 4);
593 qint32 projection = 0;
594 memcpy(dc.uniforms.data + 148, &projection, 4);
595 fillVertexIndex(&dc, g, true, false, visualizer->m_renderer->m_rhi);
596 drawCalls.append(dc);
597 }
598 }
599
600 QSGNODE_TRAVERSE(node) {
601 gather(child);
602 }
603}
604
605void RhiVisualizer::ClipVis::prepare(QSGNode *node, RhiVisualizer *visualizer,
606 QRhi *rhi, QRhiResourceUpdateBatch *u)
607{
608 this->visualizer = visualizer;
609
610 drawCalls.clear();
611 gather(node);
612
613 if (drawCalls.isEmpty())
614 return;
615
616 const int ubufAlign = rhi->ubufAlignment();
617 int vbufOffset = 0;
618 int ibufOffset = 0;
619 int ubufOffset = 0;
620 for (RhiVisualizer::DrawCall &dc : drawCalls) {
621 dc.buf.vbufOffset = aligned(vbufOffset, 4);
622 vbufOffset = dc.buf.vbufOffset + dc.vertex.count * dc.vertex.stride;
623
624 dc.buf.ibufOffset = aligned(ibufOffset, 4);
625 ibufOffset = dc.buf.ibufOffset + dc.index.count * dc.index.stride;
626
627 dc.buf.ubufOffset = aligned(ubufOffset, ubufAlign);
628 ubufOffset = dc.buf.ubufOffset + DrawCall::UBUF_SIZE;
629 }
630
631 ensureBuffer(rhi, &vbuf, QRhiBuffer::VertexBuffer, vbufOffset);
632 if (ibufOffset)
633 ensureBuffer(rhi, &ibuf, QRhiBuffer::IndexBuffer, ibufOffset);
634 const int ubufSize = ubufOffset;
635 ensureBuffer(rhi, &ubuf, QRhiBuffer::UniformBuffer, ubufSize);
636
637 for (RhiVisualizer::DrawCall &dc : drawCalls) {
638 u->updateDynamicBuffer(vbuf, dc.buf.vbufOffset, dc.vertex.count * dc.vertex.stride, dc.vertex.data);
639 dc.buf.vbuf = vbuf;
640 if (dc.index.count) {
641 u->updateDynamicBuffer(ibuf, dc.buf.ibufOffset, dc.index.count * dc.index.stride, dc.index.data);
642 dc.buf.ibuf = ibuf;
643 }
644 u->updateDynamicBuffer(ubuf, dc.buf.ubufOffset, DrawCall::UBUF_SIZE, dc.uniforms.data);
645 }
646
647 if (!srb) {
648 srb = rhi->newShaderResourceBindings();
649 srb->setBindings({ QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, ubufVisibility, ubuf, DrawCall::UBUF_SIZE) });
650 if (!srb->create())
651 return;
652 }
653}
654
655void RhiVisualizer::ClipVis::releaseResources()
656{
657 delete srb;
658 srb = nullptr;
659
660 delete ubuf;
661 ubuf = nullptr;
662
663 delete ibuf;
664 ibuf = nullptr;
665
666 delete vbuf;
667 vbuf = nullptr;
668}
669
670void RhiVisualizer::ClipVis::render(QRhiCommandBuffer *cb)
671{
672 visualizer->recordDrawCalls(drawCalls, cb, srb);
673}
674
675void RhiVisualizer::OverdrawVis::gather(Node *n)
676{
677 if (n->type() == QSGNode::GeometryNodeType && n->element()->batch) {
678 QMatrix4x4 matrix = visualizer->m_renderer->m_current_projection_matrix[0];
679 matrix(2, 2) = visualizer->m_renderer->m_zRange;
680 matrix(2, 3) = 1.0f - n->element()->order * visualizer->m_renderer->m_zRange;
681
682 if (n->element()->batch->root)
683 matrix = matrix * qsg_matrixForRoot(n->element()->batch->root);
684
685 QSGGeometryNode *gn = static_cast<QSGGeometryNode *>(n->sgNode);
686 matrix = matrix * *gn->matrix();
687
688 QSGGeometry *g = gn->geometry();
689 if (g->attributeCount() >= 1) {
690 DrawCall dc;
691 memcpy(dc.uniforms.data, matrix.constData(), 64);
692 memcpy(dc.uniforms.data + 64, rotation.constData(), 64);
693
694 float c[4];
695 const float ca = 0.33f;
696 if (n->element()->batch->isOpaque) {
697 c[0] = ca * 0.3f; c[1] = ca * 1.0f; c[2] = ca * 0.3f; c[3] = ca;
698 } else {
699 c[0] = ca * 1.0f; c[1] = ca * 0.3f; c[2] = ca * 0.3f; c[3] = ca;
700 }
701 memcpy(dc.uniforms.data + 128, c, 16);
702 float pattern = 0.0f;
703 memcpy(dc.uniforms.data + 144, &pattern, 4);
704 qint32 projection = 1;
705 memcpy(dc.uniforms.data + 148, &projection, 4);
706
707 fillVertexIndex(&dc, g, true, false, visualizer->m_renderer->m_rhi);
708 drawCalls.append(dc);
709 }
710 }
711
713 gather(child);
714 }
715}
716
717void RhiVisualizer::OverdrawVis::prepare(Node *n, RhiVisualizer *visualizer,
718 QRhi *rhi, QRhiResourceUpdateBatch *u)
719{
720 this->visualizer = visualizer;
721
722 step += float(M_PI * 2 / 1000.0);
723 if (step > float(M_PI * 2))
724 step = 0.0f;
725
726 const float yfix = rhi->isYUpInNDC() ? 1.0f : -1.0f;
727 rotation.setToIdentity();
728 rotation.translate(0.0f, 0.5f * yfix, 4.0f);
729 rotation.scale(2.0f, 2.0f, 1.0f);
730 rotation.rotate(-30.0f * yfix, 1.0f, 0.0f, 0.0f);
731 rotation.rotate(80.0f * std::sin(step), 0.0f, 1.0f, 0.0f);
732 rotation.translate(0.0f, 0.0f, -1.0f);
733
734 drawCalls.clear();
735 gather(n);
736
737 if (!box.vbuf) {
738 const float v[] = {
739 // lower
740 -1, 1, 0, 1, 1, 0,
741 -1, 1, 0, -1, -1, 0,
742 1, 1, 0, 1, -1, 0,
743 -1, -1, 0, 1, -1, 0,
744
745 // upper
746 -1, 1, 1, 1, 1, 1,
747 -1, 1, 1, -1, -1, 1,
748 1, 1, 1, 1, -1, 1,
749 -1, -1, 1, 1, -1, 1,
750
751 // sides
752 -1, -1, 0, -1, -1, 1,
753 1, -1, 0, 1, -1, 1,
754 -1, 1, 0, -1, 1, 1,
755 1, 1, 0, 1, 1, 1
756 };
757 box.vbuf = rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, sizeof(v));
758 if (!box.vbuf->create())
759 return;
760 u->uploadStaticBuffer(box.vbuf, v);
761 }
762
763 if (!box.ubuf) {
764 box.ubuf = rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, DrawCall::UBUF_SIZE);
765 if (!box.ubuf->create())
766 return;
767 QMatrix4x4 ident;
768 u->updateDynamicBuffer(box.ubuf, 0, 64, ident.constData());
769 float color[4] = { 0.5f, 0.5f, 1.0f, 1.0f };
770 u->updateDynamicBuffer(box.ubuf, 128, 16, color);
771 float pattern = 0.0f;
772 u->updateDynamicBuffer(box.ubuf, 144, 4, &pattern);
773 qint32 projection = 1;
774 u->updateDynamicBuffer(box.ubuf, 148, 4, &projection);
775 }
776
777 u->updateDynamicBuffer(box.ubuf, 64, 64, rotation.constData());
778
779 if (!box.srb) {
780 box.srb = rhi->newShaderResourceBindings();
781 box.srb->setBindings({ QRhiShaderResourceBinding::uniformBuffer(0, ubufVisibility, box.ubuf) });
782 if (!box.srb->create())
783 return;
784 }
785
786 if (!box.ps) {
787 box.ps = rhi->newGraphicsPipeline();
788 box.ps->setTopology(QRhiGraphicsPipeline::Lines);
789 box.ps->setLineWidth(2); // may be be ignored (D3D, Metal), but may be used on GL and Vulkan
790 QRhiGraphicsPipeline::TargetBlend blend;
791 blend.enable = true;
792 blend.srcColor = QRhiGraphicsPipeline::One;
793 blend.dstColor = QRhiGraphicsPipeline::One;
794 blend.srcAlpha = QRhiGraphicsPipeline::One;
795 blend.dstAlpha = QRhiGraphicsPipeline::One;
796 box.ps->setTargetBlends({ blend });
797 box.ps->setShaderStages({ { QRhiShaderStage::Vertex, visualizer->m_vs },
798 { QRhiShaderStage::Fragment, visualizer->m_fs } });
799 QRhiVertexInputLayout inputLayout;
800 inputLayout.setBindings({ { 3 * sizeof(float) } });
801 inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 } });
802 box.ps->setVertexInputLayout(inputLayout);
803 box.ps->setShaderResourceBindings(box.srb);
804 box.ps->setRenderPassDescriptor(visualizer->m_renderer->renderTarget().rpDesc);
805 if (!box.ps->create())
806 return;
807 }
808
809 if (drawCalls.isEmpty())
810 return;
811
812 const int ubufAlign = rhi->ubufAlignment();
813 int vbufOffset = 0;
814 int ibufOffset = 0;
815 int ubufOffset = 0;
816 for (RhiVisualizer::DrawCall &dc : drawCalls) {
817 dc.buf.vbufOffset = aligned(vbufOffset, 4);
818 vbufOffset = dc.buf.vbufOffset + dc.vertex.count * dc.vertex.stride;
819
820 dc.buf.ibufOffset = aligned(ibufOffset, 4);
821 ibufOffset = dc.buf.ibufOffset + dc.index.count * dc.index.stride;
822
823 dc.buf.ubufOffset = aligned(ubufOffset, ubufAlign);
824 ubufOffset = dc.buf.ubufOffset + DrawCall::UBUF_SIZE;
825 }
826
827 ensureBuffer(rhi, &vbuf, QRhiBuffer::VertexBuffer, vbufOffset);
828 if (ibufOffset)
829 ensureBuffer(rhi, &ibuf, QRhiBuffer::IndexBuffer, ibufOffset);
830 const int ubufSize = ubufOffset;
831 ensureBuffer(rhi, &ubuf, QRhiBuffer::UniformBuffer, ubufSize);
832
833 for (RhiVisualizer::DrawCall &dc : drawCalls) {
834 u->updateDynamicBuffer(vbuf, dc.buf.vbufOffset, dc.vertex.count * dc.vertex.stride, dc.vertex.data);
835 dc.buf.vbuf = vbuf;
836 if (dc.index.count) {
837 u->updateDynamicBuffer(ibuf, dc.buf.ibufOffset, dc.index.count * dc.index.stride, dc.index.data);
838 dc.buf.ibuf = ibuf;
839 }
840 u->updateDynamicBuffer(ubuf, dc.buf.ubufOffset, DrawCall::UBUF_SIZE, dc.uniforms.data);
841 }
842
843 if (!srb) {
844 srb = rhi->newShaderResourceBindings();
845 srb->setBindings({ QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, ubufVisibility, ubuf, DrawCall::UBUF_SIZE) });
846 if (!srb->create())
847 return;
848 }
849}
850
851void RhiVisualizer::OverdrawVis::releaseResources()
852{
853 delete srb;
854 srb = nullptr;
855
856 delete ubuf;
857 ubuf = nullptr;
858
859 delete ibuf;
860 ibuf = nullptr;
861
862 delete vbuf;
863 vbuf = nullptr;
864
865 delete box.ps;
866 box.ps = nullptr;
867
868 delete box.srb;
869 box.srb = nullptr;
870
871 delete box.ubuf;
872 box.ubuf = nullptr;
873
874 delete box.vbuf;
875 box.vbuf = nullptr;
876}
877
878void RhiVisualizer::OverdrawVis::render(QRhiCommandBuffer *cb)
879{
880 cb->setGraphicsPipeline(box.ps);
881 cb->setShaderResources();
882 QRhiCommandBuffer::VertexInput vb(box.vbuf, 0);
883 cb->setVertexInput(0, 1, &vb);
884 cb->draw(24);
885
886 visualizer->recordDrawCalls(drawCalls, cb, srb, true);
887}
888
889}
890
891QT_END_NAMESPACE
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:323
static bool ensureBuffer(QRhi *rhi, QRhiBuffer **buf, QRhiBuffer::UsageFlags usage, quint32 newSize)
QRhiVertexInputAttribute::Format qsg_vertexInputFormat(const QSGGeometry::Attribute &a)
QRhiGraphicsPipeline::Topology qsg_topology(int geomDrawMode, QRhi *rhi)
QMatrix4x4 qsg_matrixForRoot(Node *node)
static void fillVertexIndex(RhiVisualizer::DrawCall *dc, QSGGeometry *g, bool withData, bool forceUintIndex, QRhi *rhi)
const QRhiShaderResourceBinding::StageFlags ubufVisibility
QRhiCommandBuffer::IndexFormat qsg_indexFormat(const QSGGeometry *geometry)
static uint aligned(uint v, uint byteAlign)
Combined button and popup list for selecting options.
#define M_PI
Definition qmath.h:201
#define QSGNODE_DIRTY_PARENT
#define SHADOWNODE_TRAVERSE(NODE)
#define QSGNODE_TRAVERSE(NODE)