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