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
qquick3dscenerenderer.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
7#include "qquick3dobject_p.h"
8#include "qquick3dnode_p.h"
10#include "qquick3dtexture_p.h"
11#include "qquick3dcamera_p.h"
13#include "qquick3dmodel_p.h"
17#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
18
19#include <QtQuick3DRuntimeRender/private/qssgrendererutil_p.h>
20#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
21
22#include <QtQuick/private/qquickwindow_p.h>
23#include <QtQuick/private/qsgdefaultrendercontext_p.h>
24#include <QtQuick/private/qsgtexture_p.h>
25#include <QtQuick/private/qsgplaintexture_p.h>
26#include <QtQuick/private/qsgrendernode_p.h>
27
28#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
29#include <QtQuick3DRuntimeRender/private/qssgrhieffectsystem_p.h>
30#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
31#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
32#include <QtQuick3DRuntimeRender/private/qssgrhicontext_p.h>
33#include <QtQuick3DRuntimeRender/private/qssgcputonemapper_p.h>
34#include <QtQuick3DUtils/private/qssgutils_p.h>
35#include <QtQuick3DUtils/private/qssgassert_p.h>
36
37
38#include <qtquick3d_tracepoints_p.h>
39
40#include <QtCore/QObject>
41#include <QtCore/qqueue.h>
42
44
46 "QT_BEGIN_NAMESPACE" \
47 "class QQuick3DViewport;" \
48 "QT_END_NAMESPACE"
49)
50
52Q_TRACE_POINT(qtquick3d, QSSG_prepareFrame_exit);
53Q_TRACE_POINT(qtquick3d, QSSG_renderFrame_entry, int width, int height);
54Q_TRACE_POINT(qtquick3d, QSSG_renderFrame_exit);
55Q_TRACE_POINT(qtquick3d, QSSG_synchronize_entry, QQuick3DViewport *view3D, const QSize &size, float dpr);
56Q_TRACE_POINT(qtquick3d, QSSG_synchronize_exit);
57Q_TRACE_POINT(qtquick3d, QSSG_renderPass_entry, const QString &renderPass);
58Q_TRACE_POINT(qtquick3d, QSSG_renderPass_exit);
59
60static bool dumpRenderTimes = false;
61
62#if QT_CONFIG(qml_debug)
63
64static inline quint64 statDrawCallCount(const QSSGRhiContextStats &stats)
65{
66 quint64 count = 0;
68 for (const auto &pass : info.renderPasses)
71 return count;
72}
73
74#define STAT_PAYLOAD(stats) \
75 (statDrawCallCount(stats) | (quint64(stats.perLayerInfo[stats.layerKey].renderPasses.size()) << 32))
76
77#endif
78
79template <typename In, typename Out>
80static void bfs(In *inExtension, QList<Out *> &outList)
81{
82 QSSG_ASSERT(inExtension, return);
83
84 QQueue<In *> queue { { inExtension } };
85 while (queue.size() > 0) {
86 if (auto cur = queue.dequeue()) {
87 if (auto *ext = static_cast<Out *>(QQuick3DObjectPrivate::get(cur)->spatialNode))
88 outList.push_back(ext);
89 for (auto &chld : cur->childItems())
90 queue.enqueue(qobject_cast<In *>(chld));
91 }
92 }
93}
94
98 , renderPending(true)
99 , invalidatePending(false)
100 , devicePixelRatio(1)
101{
102 qsgnode_set_description(this, QStringLiteral("fbonode"));
104}
105
111
117
122
127
128// QQuickWindow::update() behaves differently depending on whether it's called from the GUI thread
129// or the render thread.
130// TODO: move this to QQuickWindow::fullUpdate(), if we can't change update()
138
140{
141 if (renderPending) {
142 if (renderer->renderStats())
144
145 renderPending = false;
146
147 if (renderer->m_sgContext->rhiContext()->isValid()) {
149 bool needsNewWrapper = false;
150 if (!texture() || (texture()->textureSize() != renderer->surfaceSize()
151 || texture()->rhiTexture() != rhiTexture))
152 {
153 needsNewWrapper = true;
154 }
155 if (needsNewWrapper) {
156 delete texture();
158 t->setOwnsTexture(false);
159 t->setHasAlphaChannel(true);
160 t->setTexture(rhiTexture);
161 t->setTextureSize(renderer->surfaceSize());
162 setTexture(t);
163 }
164 }
165
168
169 if (renderer->renderStats())
171
172 if (renderer->requestedFramesCount > 0) {
175 renderer->requestedFramesCount--;
176 }
177 }
178}
179
181{
182 if (!qFuzzyCompare(window->effectiveDevicePixelRatio(), devicePixelRatio)) {
184 quickFbo->update();
185 }
186}
187
188
189QQuick3DSceneRenderer::QQuick3DSceneRenderer(const std::shared_ptr<QSSGRenderContextInterface> &rci)
190 : m_sgContext(rci)
191{
192 dumpRenderTimes = (qEnvironmentVariableIntValue("QT_QUICK3D_DUMP_RENDERTIMES") > 0);
193}
194
196{
197 const auto &rhiCtx = m_sgContext->rhiContext();
198 QSSGRhiContextStats::get(*rhiCtx).cleanupLayerInfo(m_layer);
199 m_sgContext->bufferManager()->releaseResourcesForLayer(m_layer);
200 delete m_layer;
201
202 delete m_texture;
203
204 releaseAaDependentRhiResources();
205 delete m_effectSystem;
206}
207
208void QQuick3DSceneRenderer::releaseAaDependentRhiResources()
209{
210 const auto &rhiCtx = m_sgContext->rhiContext();
211 if (!rhiCtx->isValid())
212 return;
213
214 delete m_textureRenderTarget;
215 m_textureRenderTarget = nullptr;
216
217 delete m_textureRenderPassDescriptor;
218 m_textureRenderPassDescriptor = nullptr;
219
220 delete m_depthStencilBuffer;
221 m_depthStencilBuffer = nullptr;
222
223 delete m_multiViewDepthStencilBuffer;
224 m_multiViewDepthStencilBuffer = nullptr;
225
226 delete m_msaaRenderBuffer;
227 m_msaaRenderBuffer = nullptr;
228
229 delete m_msaaMultiViewRenderBuffer;
230 m_msaaMultiViewRenderBuffer = nullptr;
231
232 delete m_ssaaTexture;
233 m_ssaaTexture = nullptr;
234
235 delete m_ssaaTextureToTextureRenderTarget;
236 m_ssaaTextureToTextureRenderTarget = nullptr;
237
238 delete m_ssaaTextureToTextureRenderPassDescriptor;
239 m_ssaaTextureToTextureRenderPassDescriptor = nullptr;
240
241 delete m_temporalAATexture;
242 m_temporalAATexture = nullptr;
243 delete m_temporalAARenderTarget;
244 m_temporalAARenderTarget = nullptr;
245 delete m_temporalAARenderPassDescriptor;
246 m_temporalAARenderPassDescriptor = nullptr;
247
248 delete m_prevTempAATexture;
249 m_prevTempAATexture = nullptr;
250}
251
252// Blend factors are in the form of (frame blend factor, accumulator blend factor)
254 QVector2D(0.500000f, 0.500000f), // 1x
255 QVector2D(0.333333f, 0.666667f), // 2x
256 QVector2D(0.250000f, 0.750000f), // 3x
257 QVector2D(0.200000f, 0.800000f), // 4x
258 QVector2D(0.166667f, 0.833333f), // 5x
259 QVector2D(0.142857f, 0.857143f), // 6x
260 QVector2D(0.125000f, 0.875000f), // 7x
261 QVector2D(0.111111f, 0.888889f), // 8x
262};
263
264static const QVector2D s_TemporalAABlendFactors = { 0.5f, 0.5f };
265
267{
268 if (!m_layer)
269 return nullptr;
270
271 QRhiTexture *currentTexture = m_texture; // the result so far
272
273 if (qw) {
274 if (m_renderStats)
275 m_renderStats->startRenderPrepare();
276
277 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
278
279 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
281
282 rhiCtxD->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
283 rhiCtxD->setRenderTarget(m_textureRenderTarget);
284
285 QRhiCommandBuffer *cb = nullptr;
286 QRhiSwapChain *swapchain = qw->swapChain();
287 if (swapchain) {
288 cb = swapchain->currentFrameCommandBuffer();
289 rhiCtxD->setCommandBuffer(cb);
290 } else {
291 QSGRendererInterface *rif = qw->rendererInterface();
292 cb = static_cast<QRhiCommandBuffer *>(
294 if (cb)
295 rhiCtxD->setCommandBuffer(cb);
296 else {
297 qWarning("Neither swapchain nor redirected command buffer are available.");
298 return currentTexture;
299 }
300 }
301
302 // Graphics pipeline objects depend on the MSAA sample count, so the
303 // renderer needs to know the value.
304 rhiCtxD->setMainPassSampleCount(m_msaaRenderBuffer ? m_msaaRenderBuffer->sampleCount() :
305 (m_msaaMultiViewRenderBuffer ? m_msaaMultiViewRenderBuffer->sampleCount() : 1));
306
307 // mainPassViewCount is left unchanged
308
309 int ssaaAdjustedWidth = m_surfaceSize.width();
310 int ssaaAdjustedHeight = m_surfaceSize.height();
312 ssaaAdjustedWidth *= m_ssaaMultiplier;
313 ssaaAdjustedHeight *= m_ssaaMultiplier;
314 }
315
316 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
317
318 float dpr = m_sgContext->renderer()->dpr();
319 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
320 beginFrame();
321 rhiPrepare(vp, dpr);
322
323 if (m_renderStats)
324 m_renderStats->endRenderPrepare();
325
326 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
327
328 Q_TRACE(QSSG_prepareFrame_exit);
329
330 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
331 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
332
333 QColor clearColor = Qt::transparent;
334 if (m_backgroundMode == QSSGRenderLayer::Background::Color
335 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
336 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe))
337 {
338 // Same logic as with the main render pass and skybox: tonemap
339 // based on tonemapMode (unless it is None), unless there are effects.
340 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
341 }
342
343 // This is called from the node's preprocess() meaning Qt Quick has not
344 // actually began recording a renderpass. Do our own.
345 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 }, nullptr, rhiCtx->commonPassFlags());
346 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
347 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
348 rhiRender();
349 cb->endPass();
350 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
351 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral("main"));
352
353 const bool temporalAA = m_layer->temporalAAIsActive;
354 const bool progressiveAA = m_layer->progressiveAAIsActive;
355 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
356 QRhi *rhi = rhiCtx->rhi();
357
358 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
359
360 // Do effects before antialiasing
361 if (m_effectSystem && m_layer->firstEffect && !m_layer->renderedCameras.isEmpty()) {
362 const auto &renderer = m_sgContext->renderer();
363 QSSGLayerRenderData *theRenderData = renderer->getOrCreateLayerRenderData(*m_layer);
364 Q_ASSERT(theRenderData);
365 QRhiTexture *theDepthTexture = theRenderData->getRenderResult(QSSGFrameData::RenderResult::DepthTexture)->texture;
366 QVector2D cameraClipRange(m_layer->renderedCameras[0]->clipNear, m_layer->renderedCameras[0]->clipFar);
367
368 currentTexture = m_effectSystem->process(*m_layer->firstEffect,
369 currentTexture,
370 theDepthTexture,
371 cameraClipRange);
372 }
373
374 // The only difference between temporal and progressive AA at this point is that tempAA always
375 // uses blend factors of 0.5 and copies currentTexture to m_prevTempAATexture, while progAA uses blend
376 // factors from a table and copies the blend result to m_prevTempAATexture
377
378 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
379 cb->debugMarkBegin(QByteArrayLiteral("Temporal AA"));
380 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
381 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Temporal AA"));
382 QRhiTexture *blendResult;
383 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex; // TODO: can we use only one index?
384
385 if (*aaIndex > 0) {
386 if (temporalAA || *aaIndex < quint32(m_layer->antialiasingQuality)) {
387 const auto &renderer = m_sgContext->renderer();
388
389 // The fragment shader relies on per-target compilation and
390 // QSHADER_ macros of qsb, hence no need to communicate a flip
391 // flag from here.
392 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiProgressiveAAShader();
393 QRhiResourceUpdateBatch *rub = nullptr;
394
395 QSSGRhiDrawCallData &dcd(rhiCtxD->drawCallData({ m_layer, nullptr, nullptr, 0 }));
396 QRhiBuffer *&ubuf = dcd.ubuf;
397 const int ubufSize = 2 * sizeof(float);
398 if (!ubuf) {
400 ubuf->create();
401 }
402
403 rub = rhi->nextResourceUpdateBatch();
404 int idx = *aaIndex - 1;
405 const QVector2D *blendFactors = progressiveAA ? &s_ProgressiveAABlendFactors[idx] : &s_TemporalAABlendFactors;
406 rub->updateDynamicBuffer(ubuf, 0, 2 * sizeof(float), blendFactors);
407 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
408
413 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
414 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
415
416 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
417
419 const QSize textureSize = currentTexture->pixelSize();
420 ps.viewport = QRhiViewport(0, 0, float(textureSize.width()), float(textureSize.height()));
422
423 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
424 blendResult = m_temporalAATexture;
425 } else {
426 blendResult = m_prevTempAATexture;
427 }
428 } else {
429 // For the first frame: no blend, only copy
430 blendResult = currentTexture;
431 }
432
434
435 if (temporalAA || (*aaIndex < quint32(m_layer->antialiasingQuality))) {
436 auto *rub = rhi->nextResourceUpdateBatch();
437 if (progressiveAA)
438 rub->copyTexture(m_prevTempAATexture, blendResult);
439 else
440 rub->copyTexture(m_prevTempAATexture, currentTexture);
441 cb->resourceUpdate(rub);
442 }
443
444 (*aaIndex)++;
445 cb->debugMarkEnd();
446 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("temporal_aa"));
447
448 currentTexture = blendResult;
449 }
450
452 // With supersampling antialiasing we at this point have the
453 // content rendered at a larger size into m_ssaaTexture. Now scale
454 // it down to the expected size into m_texture, using linear
455 // filtering. Unlike in the OpenGL world, there is no
456 // glBlitFramebuffer equivalent available, because APIs like D3D
457 // and Metal have no such operation (the generally supported
458 // texture copy operations are 1:1 copies, without support for
459 // scaling, which is what we would need here). So draw a quad.
460
462 const auto &renderer = m_sgContext->renderer();
463
464 cb->debugMarkBegin(QByteArrayLiteral("SSAA downsample"));
465 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
466
467 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("SSAA downsample"));
468
469 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, nullptr);
470
471 // Instead of passing in a flip flag we choose to rely on qsb's
472 // per-target compilation mode in the fragment shader. (it does UV
473 // flipping based on QSHADER_ macros) This is just better for
474 // performance and the shaders are very simple so introducing a
475 // uniform block and branching dynamically would be an overkill.
476 const auto &shaderPipeline = m_sgContext->shaderCache()->getBuiltInRhiShaders().getRhiSupersampleResolveShader(rhiCtx->mainPassViewCount());
477
481 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
482 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
483
485 ps.viewport = QRhiViewport(0, 0, float(m_surfaceSize.width()), float(m_surfaceSize.height()));
486 ps.viewCount = rhiCtx->mainPassViewCount();
488
489 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
490 cb->debugMarkEnd();
491 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("ssaa_downsample"));
492
493 currentTexture = m_texture;
494 }
495
496 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
497 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiCtx)),
498 profilingId);
499 endFrame();
500
501 Q_TRACE(QSSG_renderFrame_exit);
502
503 }
504
505 return currentTexture;
506}
507
509{
510 m_sgContext->renderer()->beginFrame(*m_layer);
511}
512
514{
515 m_sgContext->renderer()->endFrame(*m_layer);
516}
517
519{
520 if (!m_layer)
521 return;
522
523 const auto &renderer = m_sgContext->renderer();
524
525 renderer->setDpr(displayPixelRatio);
526
527 renderer->setViewport(viewport);
528
529 renderer->prepareLayerForRender(*m_layer);
530 // If sync was called the assumption is that the scene is dirty regardless of what
531 // the scene prep function says, we still should verify that we have a camera before
532 // we call render prep and render.
533 const bool renderReady = !m_layer->renderData->renderedCameras.isEmpty();
534 if (renderReady) {
535 renderer->rhiPrepare(*m_layer);
536 m_prepared = true;
537 }
538}
539
541{
542 if (m_prepared) {
543 // There is no clearFirst flag - the rendering here does not record a
544 // beginPass() so it never clears on its own.
545
546 m_sgContext->renderer()->rhiRender(*m_layer);
547 }
548
549 m_prepared = false;
550}
551
565
582
584{
585 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
586
587 Q_ASSERT(view3D != nullptr); // This is not an option!
588 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
589 Q_ASSERT(rhiCtx != nullptr);
590
591 bool newRenderStats = false;
592 if (!m_renderStats) {
593 m_renderStats = view3D->renderStats();
594 newRenderStats = true;
595 }
596
597 if (m_renderStats)
598 m_renderStats->startSync();
599
600 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
601
602 m_sgContext->renderer()->setDpr(dpr);
603 bool layerSizeIsDirty = m_surfaceSize != size;
604 m_surfaceSize = size;
605
606 // Synchronize scene managers under this window
607 QSet<QSSGRenderGraphObject *> resourceLoaders;
608 bool requestSharedUpdate = false;
609 if (auto window = view3D->window()) {
610 if (!winAttacment || winAttacment->window() != window)
612
613 if (winAttacment && winAttacment->rci() != m_sgContext)
614 winAttacment->setRci(m_sgContext);
615
616 if (winAttacment)
617 requestSharedUpdate = winAttacment->synchronize(resourceLoaders);
618 }
619
620 // Import scenes used in a multi-window application...
621 QQuick3DNode *importScene = view3D->importScene();
622 if (importScene) {
623 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
624 // If the import scene is used with 3D views under a different window, then we'll
625 // need to trigger updates for those as well.
626 if (auto window = importSceneManager->window(); window && window != view3D->window()) {
627 if (auto winAttacment = importSceneManager->wattached) {
628 // Not the same window but backed by the same rhi?
629 auto rci = winAttacment->rci();
630 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
631 if (inlineSync) {
632 // Given that we're on the same thread, we can do an immediate sync
633 // (rhi instances can differ, e.g., basic renderloop).
634 winAttacment->synchronize(resourceLoaders);
635 } else if (rci && !window->isExposed()) { // Forced sync of non-exposed windows
636 // Not exposed, so not rendering (playing with fire here)...
637 winAttacment->synchronize(resourceLoaders);
638 } else if (!rci || requestSharedUpdate) {
639 // If there's no RCI for the importscene we'll request an update, which should
640 // mean we only get here once. It also means the update to any secondary windows
641 // will be delayed. Note that calling this function on each sync would cause the
642 // different views to ping-pong for updated forever...
643 winAttacment->requestUpdate();
644 }
645 }
646 }
647 }
648
649 // Generate layer node
650 if (!m_layer)
651 m_layer = new QSSGRenderLayer();
652
653 if (newRenderStats)
654 m_renderStats->setRhiContext(rhiCtx, m_layer);
655
656 // if the list is dirty we rebuild (assumption is that this won't happen frequently).
657 if (view3D->extensionListDirty()) {
658 for (size_t i = 0; i != size_t(QSSGRenderLayer::RenderExtensionStage::Count); ++i)
659 m_layer->renderExtensions[i].clear();
660 // All items in the extension list are root items,
661 const auto &extensions = view3D->extensionList();
662 for (const auto &ext : extensions) {
663 const auto type = QQuick3DObjectPrivate::get(ext)->type;
665 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
666 if (auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
667 if (QQuick3DObjectPrivate::get(renderExt)->spatialNode) {
668 const auto stage = static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)->stage();
669 QSSG_ASSERT(size_t(stage) < std::size(m_layer->renderExtensions), continue);
670 auto &list = m_layer->renderExtensions[size_t(stage)];
671 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
672 }
673 }
674 }
675 }
676 }
677
678 view3D->clearExtensionListDirty();
679 }
680
681 // Update the layer node properties
682 updateLayerNode(view3D, resourceLoaders.values());
683
684 bool postProcessingNeeded = m_layer->firstEffect;
685 bool postProcessingWasActive = m_effectSystem;
687 if (postProcessingNeeded) {
688 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
689 while (lastEffect->m_nextEffect)
690 lastEffect = lastEffect->m_nextEffect;
691 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
692 }
693 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi, bool postProc) {
694 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
695 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
696
697 // Our standard choice for the postprocessing input/output textures'
698 // format is a floating point one. (unlike intermediate Buffers, which
699 // default to RGBA8 unless the format is explicitly specified)
700 // This is intentional since a float format allows passing in
701 // non-tonemapped content without colors being clamped when written out
702 // to the render target.
703 //
704 // When it comes to the output, this applies to that too due to
705 // QSSGRhiEffectSystem picking it up unless overridden (with a Buffer
706 // an empty 'name'). Here too a float format gives more flexibility:
707 // the effect may or may not do its own tonemapping and this approach
708 // is compatible with potential future on-screen HDR output support.
709
710 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
711 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
712 return preferredPostProcFormat;
713
714 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
715 if (rhi->isTextureFormatSupported(preferredView3DFormat))
716 return preferredView3DFormat;
717
718 return QRhiTexture::RGBA8;
719 };
720 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
721
722 // Store from the layer properties the ones we need to handle ourselves (with the RHI code path)
723 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
724
725 // This is stateful since we only want to recalculate the tonemapped color
726 // when the color changes, not in every frame.
727 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
728 if (m_userBackgroundColor != currentUserBackgroundColor) {
729 m_userBackgroundColor = currentUserBackgroundColor;
730 m_linearBackgroundColor = QSSGUtils::color::sRGBToLinearColor(m_userBackgroundColor);
731 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
732 m_linearBackgroundColor.greenF(),
733 m_linearBackgroundColor.blueF()),
734 view3D->environment()->tonemapMode());
735 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
736 }
737 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
738 view3D->environment()->scissorRect().size() * dpr);
739
740 // Set the root item for the scene to the layer
741 auto rootNode = static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
742 if (rootNode != m_sceneRootNode) {
743 if (m_sceneRootNode)
744 removeNodeFromLayer(m_sceneRootNode);
745
746 if (rootNode)
747 addNodeToLayer(rootNode);
748
749 m_sceneRootNode = rootNode;
750 }
751
752 // Add the referenced scene root node to the layer as well if available
753 QSSGRenderNode *importRootNode = nullptr;
754 if (importScene)
755 importRootNode = static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
756
757 if (importRootNode != m_importRootNode) {
758 if (m_importRootNode)
759 m_layer->removeImportScene(*m_importRootNode);
760
761 if (importRootNode) {
762 // if importScene has the rendered viewport as ancestor, it probably means
763 // "importScene: MyScene { }" type of inclusion.
764 // In this case don't duplicate content by adding it again.
765 QObject *sceneParent = importScene->parent();
766 bool isEmbedded = false;
767 while (sceneParent) {
768 if (sceneParent == view3D) {
769 isEmbedded = true;
770 break;
771 }
772 sceneParent = sceneParent->parent();
773 }
774 if (!isEmbedded)
775 m_layer->setImportScene(*importRootNode);
776 }
777
778 m_importRootNode = importRootNode;
779 }
780
781 if (auto lightmapBaker = view3D->maybeLightmapBaker()) {
782 if (lightmapBaker->m_bakingRequested) {
784
785 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
786 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
788 [qq3dCallback, qq3dBakingControl](
789 QSSGLightmapper::BakingStatus qssgBakingStatus,
790 std::optional<QString> msg,
791 QSSGLightmapper::BakingControl *qssgBakingControl)
792 {
794 switch (qssgBakingStatus)
795 {
797 break;
800 break;
803 break;
806 break;
809 break;
812 break;
813 }
814
815 qq3dCallback(qq3dBakingStatus, msg, qq3dBakingControl);
816
817 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
818 qssgBakingControl->cancelled = true;
819 };
820
821 m_layer->renderData->lightmapBakingOutputCallback = callback;
822 lightmapBaker->m_bakingRequested = false;
823 }
824 }
825
826 const bool progressiveAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::ProgressiveAA;
827 const bool multiSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA;
828 const bool temporalAA = m_layer->temporalAAEnabled && !multiSamplingAA;
829 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
830 const bool timeBasedAA = progressiveAA || temporalAA;
831 m_postProcessingStack = m_layer->firstEffect || timeBasedAA || superSamplingAA;
832 bool useFBO = view3D->renderMode() == QQuick3DViewport::RenderMode::Offscreen ||
834 && m_postProcessingStack);
835 if (useFBO && rhiCtx->isValid()) {
836 QRhi *rhi = rhiCtx->rhi();
837 const QSize renderSize = superSamplingAA ? m_surfaceSize * m_ssaaMultiplier : m_surfaceSize;
838
839 if (m_texture) {
840 // the size changed, or the AA settings changed, or toggled between some effects - no effect
841 if (layerSizeIsDirty || postProcessingStateDirty) {
842 m_texture->setPixelSize(m_surfaceSize);
843 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
844 m_texture->create();
845
846 // If AA settings changed, then we drop and recreate all
847 // resources, otherwise use a lighter path if just the size
848 // changed.
849 if (!m_aaIsDirty) {
850 // A special case: when toggling effects and AA is on,
851 // use the heavier AA path because the renderbuffer for
852 // MSAA and texture for SSAA may need a different
853 // format now since m_texture's format could have
854 // changed between RBGA8 and RGBA16F (due to layerTextureFormat()).
855 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || temporalAA)) {
856 releaseAaDependentRhiResources();
857 } else {
858 if (m_ssaaTexture) {
859 m_ssaaTexture->setPixelSize(renderSize);
860 m_ssaaTexture->create();
861 }
862 if (m_depthStencilBuffer) {
863 m_depthStencilBuffer->setPixelSize(renderSize);
864 m_depthStencilBuffer->create();
865 }
866 if (m_multiViewDepthStencilBuffer) {
867 m_multiViewDepthStencilBuffer->setPixelSize(renderSize);
868 m_multiViewDepthStencilBuffer->create();
869 }
870 if (m_msaaRenderBuffer) {
871 m_msaaRenderBuffer->setPixelSize(renderSize);
872 m_msaaRenderBuffer->create();
873 }
874 if (m_msaaMultiViewRenderBuffer) {
875 m_msaaMultiViewRenderBuffer->setPixelSize(renderSize);
876 m_msaaMultiViewRenderBuffer->create();
877 }
878 // Toggling effects on and off will change the format
879 // (assuming effects default to a floating point
880 // format) and that needs on a different renderpass on
881 // Vulkan. Hence renewing m_textureRenderPassDescriptor as well.
882 if (postProcessingStateDirty) {
883 delete m_textureRenderPassDescriptor;
884 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
885 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
886 }
887 m_textureRenderTarget->create();
888 if (m_ssaaTextureToTextureRenderTarget)
889 m_ssaaTextureToTextureRenderTarget->create();
890
891 if (m_temporalAATexture) {
892 m_temporalAATexture->setPixelSize(renderSize);
893 m_temporalAATexture->create();
894 }
895 if (m_prevTempAATexture) {
896 m_prevTempAATexture->setPixelSize(renderSize);
897 m_prevTempAATexture->create();
898 }
899 if (m_temporalAARenderTarget)
900 m_temporalAARenderTarget->create();
901 }
902 }
903 } else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) { // ### to avoid garbage upon enabling MSAA with macOS 10.14 (why is this needed?)
904 m_texture->create();
905 }
906
907 if (m_aaIsDirty)
908 releaseAaDependentRhiResources();
909 }
910
911 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
912 | QRhiTexture::UsedAsTransferSource; // transfer source is for progressive/temporal AA
913 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
914
915 if (!m_texture) {
916 if (rhiCtx->mainPassViewCount() >= 2)
917 m_texture = rhi->newTextureArray(textureFormat, rhiCtx->mainPassViewCount(), m_surfaceSize, 1, textureFlags);
918 else
919 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
920 m_texture->create();
921 }
922
923 if (!m_ssaaTexture && superSamplingAA) {
924 if (rhiCtx->mainPassViewCount() >= 2)
925 m_ssaaTexture = rhi->newTextureArray(textureFormat, rhiCtx->mainPassViewCount(), renderSize, 1, textureFlags);
926 else
927 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
928 m_ssaaTexture->create();
929 }
930
931 if (timeBasedAA && !m_temporalAATexture) {
932 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
933 m_temporalAATexture->create();
934 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
935 m_prevTempAATexture->create();
936 }
937
938 // we need to re-render time-based AA not only when AA state changes, but also when resized
939 if (m_aaIsDirty || layerSizeIsDirty)
940 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
941
942 if (m_aaIsDirty) {
943 m_samples = 1;
946 m_samples = qMax(1, int(m_layer->antialiasingQuality));
947 // The Quick3D API exposes high level values such as
948 // Medium, High, VeryHigh instead of direct sample
949 // count values. Therefore, be nice and find a sample
950 // count that's actually supported in case the one
951 // associated by default is not.
952 const QVector<int> supported = rhi->supportedSampleCounts(); // assumed to be sorted
953 if (!supported.contains(m_samples)) {
954 if (!supported.isEmpty()) {
955 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
956 m_samples = it == supported.cend() ? supported.last() : *it;
957 } else {
958 m_samples = 1;
959 }
960 }
961 } else {
962 static bool warned = false;
963 if (!warned) {
964 warned = true;
965 qWarning("Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
966 }
967 }
968 }
969 }
970
971 if (rhiCtx->mainPassViewCount() >= 2) {
972 if (!m_multiViewDepthStencilBuffer) {
973 m_multiViewDepthStencilBuffer = rhi->newTextureArray(QRhiTexture::D24S8, rhiCtx->mainPassViewCount(), renderSize,
974 m_samples, QRhiTexture::RenderTarget);
975 m_multiViewDepthStencilBuffer->create();
976 }
977 } else {
978 if (!m_depthStencilBuffer) {
979 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
980 m_depthStencilBuffer->create();
981 }
982 }
983
984 if (!m_textureRenderTarget) {
987 if (m_samples > 1) {
988 if (rhiCtx->mainPassViewCount() >= 2) {
989 m_msaaMultiViewRenderBuffer = rhi->newTextureArray(textureFormat, rhiCtx->mainPassViewCount(), renderSize, m_samples, QRhiTexture::RenderTarget);
990 m_msaaMultiViewRenderBuffer->create();
991 att.setTexture(m_msaaMultiViewRenderBuffer);
992 } else {
993 // pass in the texture's format (which may be a floating point one!) as the preferred format hint
994 m_msaaRenderBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
995 m_msaaRenderBuffer->create();
996 att.setRenderBuffer(m_msaaRenderBuffer);
997 }
998 att.setResolveTexture(m_texture);
999 } else {
1001 att.setTexture(m_ssaaTexture);
1002 else
1003 att.setTexture(m_texture);
1004 }
1005 att.setMultiViewCount(rhiCtx->mainPassViewCount());
1006 rtDesc.setColorAttachments({ att });
1007 if (m_depthStencilBuffer)
1008 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
1009 if (m_multiViewDepthStencilBuffer)
1010 rtDesc.setDepthTexture(m_multiViewDepthStencilBuffer);
1011
1012 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
1013 m_textureRenderTarget->setName(QByteArrayLiteral("View3D"));
1014 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
1015 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
1016 m_textureRenderTarget->create();
1017 }
1018
1019 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
1020 QRhiColorAttachment att(m_texture);
1021 att.setMultiViewCount(rhiCtx->mainPassViewCount());
1022 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget(QRhiTextureRenderTargetDescription({ att }));
1023 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral("SSAA texture"));
1024 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
1025 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
1026 m_ssaaTextureToTextureRenderTarget->create();
1027 }
1028
1029 if (m_layer->firstEffect) {
1030 if (!m_effectSystem)
1031 m_effectSystem = new QSSGRhiEffectSystem(m_sgContext);
1032 m_effectSystem->setup(renderSize);
1033 } else if (m_effectSystem) {
1034 delete m_effectSystem;
1035 m_effectSystem = nullptr;
1036 }
1037
1038 if (timeBasedAA && !m_temporalAARenderTarget) {
1039 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
1040 m_temporalAARenderTarget->setName(QByteArrayLiteral("Temporal AA texture"));
1041 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
1042 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
1043 m_temporalAARenderTarget->create();
1044 }
1045
1046 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
1047 m_aaIsDirty = false;
1048 }
1049
1050 if (m_renderStats)
1051 m_renderStats->endSync(dumpRenderTimes);
1052
1053 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);
1054}
1055
1057{
1058 if (fboNode)
1059 fboNode->invalidatePending = true;
1060}
1061
1063{
1064 if (m_layer && m_layer->renderData) {
1065 if (const auto &mgr = m_layer->renderData->getShadowMapManager())
1066 mgr->releaseCachedResources();
1067 if (const auto &mgr = m_layer->renderData->getReflectionMapManager())
1068 mgr->releaseCachedResources();
1069 }
1070}
1071
1073{
1074 if (!m_layer || m_layer->renderedCameras.isEmpty())
1075 return std::nullopt;
1076
1077 const QVector2D viewportSize(m_surfaceSize.width(), m_surfaceSize.height());
1078 const QVector2D position(float(pos.x()), float(pos.y()));
1079 const QRectF viewportRect(QPointF{}, QSizeF(m_surfaceSize));
1080
1081 // First invert the y so we are dealing with numbers in a normal coordinate space.
1082 // Second, move into our layer's coordinate space
1083 QVector2D correctCoords(position.x(), viewportSize.y() - position.y());
1084 QVector2D theLocalMouse = QSSGUtils::rect::toRectRelative(viewportRect, correctCoords);
1085 if ((theLocalMouse.x() < 0.0f || theLocalMouse.x() >= viewportSize.x() || theLocalMouse.y() < 0.0f
1086 || theLocalMouse.y() >= viewportSize.y()))
1087 return std::nullopt;
1088
1089 return m_layer->renderedCameras[0]->unproject(theLocalMouse, viewportRect);
1090}
1091
1092QQuick3DSceneRenderer::PickResultList QQuick3DSceneRenderer::syncPick(const QSSGRenderRay &ray)
1093{
1094 if (!m_layer)
1095 return QQuick3DSceneRenderer::PickResultList();
1096
1097 return QSSGRendererPrivate::syncPick(*m_sgContext,
1098 *m_layer,
1099 ray);
1100}
1101
1102QQuick3DSceneRenderer::PickResultList QQuick3DSceneRenderer::syncPickOne(const QSSGRenderRay &ray, QSSGRenderNode *node)
1103{
1104 if (!m_layer)
1105 return QQuick3DSceneRenderer::PickResultList();
1106
1107 return QSSGRendererPrivate::syncPick(*m_sgContext,
1108 *m_layer,
1109 ray,
1110 node);
1111}
1112
1113QQuick3DSceneRenderer::PickResultList QQuick3DSceneRenderer::syncPickSubset(const QSSGRenderRay &ray,
1114 QVarLengthArray<QSSGRenderNode *> subset)
1115{
1116 if (!m_layer)
1117 return QQuick3DSceneRenderer::PickResultList();
1118
1120 *m_sgContext->bufferManager(),
1121 ray,
1122 subset);
1123}
1124
1125QQuick3DSceneRenderer::PickResultList QQuick3DSceneRenderer::syncPickAll(const QSSGRenderRay &ray)
1126{
1127 if (!m_layer)
1128 return QQuick3DSceneRenderer::PickResultList();
1129
1130 return QSSGRendererPrivate::syncPickAll(*m_sgContext,
1131 *m_layer,
1132 ray);
1133}
1134
1136{
1137 QSSGRendererPrivate::setGlobalPickingEnabled(*m_sgContext->renderer(), isEnabled);
1138}
1139
1141{
1142 return m_renderStats;
1143}
1144
1145void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode, bool &aaIsDirty, bool &temporalIsDirty, float &ssaaMultiplier)
1146{
1147 QQuick3DSceneEnvironment *environment = view3D.environment();
1148
1150 if (aaMode != layerNode.antialiasingMode) {
1151 layerNode.antialiasingMode = aaMode;
1152 layerNode.progAAPassIndex = 0;
1153 aaIsDirty = true;
1154 }
1156 if (aaQuality != layerNode.antialiasingQuality) {
1157 layerNode.antialiasingQuality = aaQuality;
1158 ssaaMultiplier = (aaQuality == QSSGRenderLayer::AAQuality::Normal) ? 1.2f :
1159 (aaQuality == QSSGRenderLayer::AAQuality::High) ? 1.5f :
1160 2.0f;
1161 layerNode.ssaaMultiplier = ssaaMultiplier;
1162 aaIsDirty = true;
1163 }
1164
1165 bool temporalAAEnabled = environment->temporalAAEnabled();
1166 if (temporalAAEnabled != layerNode.temporalAAEnabled) {
1167 layerNode.temporalAAEnabled = environment->temporalAAEnabled();
1168 temporalIsDirty = true;
1169
1170 layerNode.tempAAPassIndex = 0;
1171 aaIsDirty = true;
1172 }
1173 layerNode.ssaaEnabled = environment->antialiasingMode()
1175
1176 layerNode.temporalAAStrength = environment->temporalAAStrength();
1177
1178 layerNode.specularAAEnabled = environment->specularAAEnabled();
1179
1180 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1181 layerNode.clearColor = QVector3D(float(environment->clearColor().redF()),
1182 float(environment->clearColor().greenF()),
1183 float(environment->clearColor().blueF()));
1184
1185 layerNode.gridEnabled = environment->gridEnabled();
1186 layerNode.gridScale = environment->gridScale();
1187 layerNode.gridFlags = environment->gridFlags();
1188
1189 layerNode.aoStrength = environment->aoStrength();
1190 layerNode.aoDistance = environment->aoDistance();
1191 layerNode.aoSoftness = environment->aoSoftness();
1192 layerNode.aoEnabled = environment->aoEnabled();
1193 layerNode.aoBias = environment->aoBias();
1194 layerNode.aoSamplerate = environment->aoSampleRate();
1195 layerNode.aoDither = environment->aoDither();
1196
1197 // ### These images will not be registered anywhere
1198 if (environment->lightProbe())
1199 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1200 else
1201 layerNode.lightProbe = nullptr;
1202 if (view3D.environment()->skyBoxCubeMap())
1203 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1204 else
1205 layerNode.skyBoxCubeMap = nullptr;
1206
1207 layerNode.lightProbeSettings.probeExposure = environment->probeExposure();
1208 // Remap the probeHorizon to the expected Range
1209 layerNode.lightProbeSettings.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1210 layerNode.setProbeOrientation(environment->probeOrientation());
1211
1212 layerNode.explicitCameras.clear();
1213 if (!view3D.m_multiViewCameras.isEmpty()) {
1214 for (QQuick3DCamera *camera : std::as_const(view3D.m_multiViewCameras))
1215 layerNode.explicitCameras.append(static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(camera)->spatialNode));
1216 } else if (view3D.camera()) {
1217 layerNode.explicitCameras.append(static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(view3D.camera())->spatialNode));
1218 }
1219
1220 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthTest, environment->depthTestEnabled());
1221 layerNode.layerFlags.setFlag(QSSGRenderLayer::LayerFlag::EnableDepthPrePass, environment->depthPrePassEnabled());
1222
1223 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1224 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1225 if (auto debugSettings = view3D.environment()->debugSettings()) {
1226 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1227 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1228 } else {
1229 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode::None;
1230 layerNode.wireframeMode = false;
1231 }
1232
1233 if (environment->lightmapper()) {
1234 QQuick3DLightmapper *lightmapper = environment->lightmapper();
1235 layerNode.lmOptions.opacityThreshold = lightmapper->opacityThreshold();
1236 layerNode.lmOptions.bias = lightmapper->bias();
1237 layerNode.lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
1238 layerNode.lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
1239 layerNode.lmOptions.indirectLightSamples = lightmapper->samples();
1240 layerNode.lmOptions.indirectLightWorkgroupSize = lightmapper->indirectLightWorkgroupSize();
1241 layerNode.lmOptions.indirectLightBounces = lightmapper->bounces();
1242 layerNode.lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
1243 } else {
1244 layerNode.lmOptions = {};
1245 }
1246
1247 if (environment->fog() && environment->fog()->isEnabled()) {
1248 layerNode.fog.enabled = true;
1249 const QQuick3DFog *fog = environment->fog();
1250 layerNode.fog.color = QSSGUtils::color::sRGBToLinear(fog->color()).toVector3D();
1251 layerNode.fog.density = fog->density();
1252 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1253 layerNode.fog.depthBegin = fog->depthNear();
1254 layerNode.fog.depthEnd = fog->depthFar();
1255 layerNode.fog.depthCurve = fog->depthCurve();
1256 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1257 layerNode.fog.heightMin = fog->leastIntenseY();
1258 layerNode.fog.heightMax = fog->mostIntenseY();
1259 layerNode.fog.heightCurve = fog->heightCurve();
1260 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1261 layerNode.fog.transmitCurve = fog->transmitCurve();
1262 } else {
1263 layerNode.fog.enabled = false;
1264 }
1265}
1266
1267void QQuick3DSceneRenderer::updateLayerNode(QQuick3DViewport *view3D, const QList<QSSGRenderGraphObject *> &resourceLoaders)
1268{
1269 QSSGRenderLayer *layerNode = m_layer;
1270
1271 bool temporalIsDirty = false;
1272 QQuick3DRenderLayerHelpers::updateLayerNodeHelper(*view3D, *m_layer, m_aaIsDirty, temporalIsDirty, m_ssaaMultiplier);
1273
1274 int extraFramesToRender = 0;
1275
1276 if (layerNode->antialiasingMode == QSSGRenderLayer::AAMode::ProgressiveAA) {
1277 // with progressive AA, we need a number of extra frames after the last dirty one
1278 // if we always reset requestedFramesCount when dirty, we will get the extra frames eventually
1279 // +1 since we need a normal frame to start with, and we're not copying that from the screen
1280 extraFramesToRender = int(layerNode->antialiasingQuality) + 1;
1281 } else if (layerNode->temporalAAEnabled) {
1282 // When temporalAA is on and antialiasing mode changes,
1283 // layer needs to be re-rendered (at least) MAX_TEMPORAL_AA_LEVELS times
1284 // to generate temporal antialiasing.
1285 // Also, we need to do an extra render when animation stops
1286 extraFramesToRender = (m_aaIsDirty || temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
1287 }
1288
1289 requestedFramesCount = extraFramesToRender;
1290 // Effects need to be rendered in reverse order as described in the file.
1291 layerNode->firstEffect = nullptr; // We reset the linked list
1292 const auto &effects = view3D->environment()->effectList();
1293 auto rit = effects.crbegin();
1294 const auto rend = effects.crend();
1295 for (; rit != rend; ++rit) {
1297 QSSGRenderEffect *effectNode = static_cast<QSSGRenderEffect *>(p->spatialNode);
1298 if (effectNode) {
1299 if (layerNode->hasEffect(effectNode)) {
1300 qWarning() << "Duplicate effect found, skipping!";
1301 } else {
1302 effectNode->className = (*rit)->metaObject()->className(); //### persistent, but still icky to store a const char* returned from a function
1303 layerNode->addEffect(*effectNode);
1304 }
1305 }
1306 }
1307
1308 // Now that we have the effect list used for rendering, finalize the shader
1309 // code based on the layer (scene.env.) settings.
1310 for (QSSGRenderEffect *effectNode = layerNode->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
1311 effectNode->finalizeShaders(*layerNode, m_sgContext.get());
1312
1313 // ResourceLoaders
1314 layerNode->resourceLoaders.clear();
1315 layerNode->resourceLoaders = resourceLoaders;
1316}
1317
1318void QQuick3DSceneRenderer::removeNodeFromLayer(QSSGRenderNode *node)
1319{
1320 if (!m_layer)
1321 return;
1322
1323 m_layer->removeChild(*node);
1324}
1325
1326void QQuick3DSceneRenderer::addNodeToLayer(QSSGRenderNode *node)
1327{
1328 if (!m_layer)
1329 return;
1330
1331 m_layer->addChild(*node);
1332}
1333
1338
1339namespace {
1340inline QRect convertQtRectToGLViewport(const QRectF &rect, const QSize surfaceSize)
1341{
1342 const int x = int(rect.x());
1343 const int y = surfaceSize.height() - (int(rect.y()) + int(rect.height()));
1344 const int width = int(rect.width());
1345 const int height = int(rect.height());
1346 return QRect(x, y, width, height);
1347}
1348
1349inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1350{
1351 if (rhiCtx->isValid()) {
1353 // Query from the rif because that is available in the sync
1354 // phase (updatePaintNode) already. QSGDefaultRenderContext's
1355 // copies of the rp and cb are not there until the render
1356 // phase of the scenegraph.
1357 int sampleCount = 1;
1358 int viewCount = 1;
1359 QRhiSwapChain *swapchain = window->swapChain();
1360 if (swapchain) {
1361 rhiCtxD->setMainRenderPassDescriptor(swapchain->renderPassDescriptor());
1362 rhiCtxD->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1363 rhiCtxD->setRenderTarget(swapchain->currentFrameRenderTarget());
1364 sampleCount = swapchain->sampleCount();
1365 } else {
1366 QSGRendererInterface *rif = window->rendererInterface();
1367 // no swapchain when using a QQuickRenderControl (redirecting to a texture etc.)
1368 QRhiCommandBuffer *cb = static_cast<QRhiCommandBuffer *>(
1372 if (cb && rt) {
1373 rhiCtxD->setMainRenderPassDescriptor(rt->renderPassDescriptor());
1374 rhiCtxD->setCommandBuffer(cb);
1375 rhiCtxD->setRenderTarget(rt);
1377 if (color0 && color0->texture()) {
1378 sampleCount = color0->texture()->sampleCount();
1380 const QRhiTextureRenderTargetDescription desc = static_cast<QRhiTextureRenderTarget *>(rt)->description();
1381 for (auto it = desc.cbeginColorAttachments(), end = desc.cendColorAttachments(); it != end; ++it) {
1382 if (it->multiViewCount() >= 2) {
1383 viewCount = it->multiViewCount();
1384 break;
1385 }
1386 }
1387 }
1388 }
1389 } else {
1390 qWarning("Neither swapchain nor redirected command buffer and render target are available.");
1391 }
1392 }
1393
1394 // MSAA is out of our control on this path: it is up to the
1395 // QQuickWindow and the scenegraph to set up the swapchain based on the
1396 // QSurfaceFormat's samples(). The only thing we need to do here is to
1397 // pass the sample count to the renderer because it is needed when
1398 // creating graphics pipelines.
1399 rhiCtxD->setMainPassSampleCount(sampleCount);
1400
1401 // The "direct renderer", i.e. the Underlay and Overlay modes are the
1402 // only ones that support multiview rendering. This becomes active when
1403 // the QQuickWindow is redirected into a texture array, typically with
1404 // an array size of 2 (2 views, for the left and right eye). Otherwise,
1405 // when targeting a window or redirected to a 2D texture, this is not
1406 // applicable and the view count is 1.
1407 rhiCtxD->setMainPassViewCount(viewCount);
1408 }
1409}
1410
1411// The alternative to queryMainRenderPassDescriptorAndCommandBuffer()
1412// specifically for the Inline render mode when there is a QSGRenderNode.
1413inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1414{
1417 rhiCtxD->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1418 rhiCtxD->setCommandBuffer(d->m_rt.cb);
1419 rhiCtxD->setRenderTarget(d->m_rt.rt);
1420 rhiCtxD->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1421 rhiCtxD->setMainPassViewCount(1);
1422}
1423
1424} // namespace
1425
1430
1432{
1433 // this is outside the main renderpass
1434
1435 if (!renderer->m_sgContext->rhiContext()->isValid())
1436 return;
1437 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1438
1439 queryInlineRenderPassDescriptorAndCommandBuffer(this, renderer->m_sgContext->rhiContext().get());
1440
1441 qreal dpr = window->effectiveDevicePixelRatio();
1442 const QSizeF itemSize = renderer->surfaceSize() / dpr;
1443 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1444 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1445 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1446
1447 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1448
1450 renderer->rhiPrepare(vp, dpr);
1451 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, renderer->profilingId);
1452}
1453
1455{
1456 Q_UNUSED(state);
1457
1458 const auto &rhiContext = renderer->m_sgContext->rhiContext();
1459
1460 if (rhiContext->isValid()) {
1461 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1462 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1463
1464 queryInlineRenderPassDescriptorAndCommandBuffer(this, renderer->m_sgContext->rhiContext().get());
1465
1467 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1468 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)), renderer->profilingId);
1469 renderer->endFrame();
1470 }
1471}
1472
1476
1477QSGRenderNode::RenderingFlags QQuick3DSGRenderNode::flags() const
1478{
1479 // don't want begin/endExternal() to be called by Quick
1480 return NoExternalRendering;
1481}
1482
1484 : m_renderer(renderer)
1485 , m_window(window)
1486{
1487 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1488 connect(window, &QQuickWindow::beforeRendering, this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1489 if (mode == Underlay)
1490 connect(window, &QQuickWindow::beforeRenderPassRecording, this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1491 else
1492 connect(window, &QQuickWindow::afterRenderPassRecording, this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1493 }
1494}
1495
1497{
1498 delete m_renderer;
1499}
1500
1502{
1503 m_viewport = viewport;
1504}
1505
1507{
1508 if (m_isVisible == visible)
1509 return;
1510 m_isVisible = visible;
1511 m_window->update();
1512}
1513
1515{
1516 renderPending = true;
1517 requestFullUpdate(m_window);
1518}
1519
1521{
1522 // This is called from the QQuick3DViewport's updatePaintNode(), before
1523 // QQuick3DSceneRenderer::synchronize(). It is essential to query things
1524 // such as the view count already here, so that synchronize() can rely on
1525 // mainPassViewCount() for instance. prepare() is too late as that is only
1526 // called on beforeRendering (so after the scenegraph sync phase).
1527 if (m_renderer->m_sgContext->rhiContext()->isValid())
1528 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1529}
1530
1531void QQuick3DSGDirectRenderer::prepare()
1532{
1533 if (!m_isVisible || !m_renderer)
1534 return;
1535
1536 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1537 // this is outside the main renderpass
1538 if (m_renderer->m_postProcessingStack) {
1539 if (renderPending) {
1540 renderPending = false;
1541 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1542 // Set up the main render target again, e.g. the postprocessing
1543 // stack could have clobbered some settings such as the sample count.
1544 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1545 const auto &quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1546 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(), nullptr);
1547 if (m_renderer->requestedFramesCount > 0) {
1548 requestRender();
1549 m_renderer->requestedFramesCount--;
1550 }
1551 }
1552 }
1553 else
1554 {
1555 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1556 if (renderStats) {
1557 renderStats->startRender();
1558 renderStats->startRenderPrepare();
1559 }
1560
1561 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1562 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1563 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1564
1565 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1566 m_renderer->beginFrame();
1567 m_renderer->rhiPrepare(vp, m_window->effectiveDevicePixelRatio());
1568 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1569
1570 if (renderStats)
1571 renderStats->endRenderPrepare();
1572 }
1573 }
1574}
1575
1576void QQuick3DSGDirectRenderer::render()
1577{
1578 if (!m_isVisible || !m_renderer)
1579 return;
1580
1581 const auto &rhiContext = m_renderer->m_sgContext->rhiContext();
1582
1583 if (rhiContext->isValid()) {
1584 // the command buffer is recording the main renderpass at this point
1585
1586 // No m_window->beginExternalCommands() must be done here. When the
1587 // renderer is using the same
1588 // QRhi/QRhiCommandBuffer/QRhiRenderPassDescriptor as the Qt Quick
1589 // scenegraph, there is no difference from the RHI's perspective. There are
1590 // no external (native) commands here.
1591
1592 // Requery the command buffer and co. since Offscreen mode View3Ds may
1593 // have altered these on the context.
1594 if (m_renderer->m_postProcessingStack) {
1595 if (m_rhiTexture) {
1596 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1597 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1598 const auto &renderer = m_renderer->m_sgContext->renderer();
1599 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
1600 cb->debugMarkBegin(QByteArrayLiteral("Post-processing result to main rt"));
1601
1602 // Instead of passing in a flip flag we choose to rely on qsb's
1603 // per-target compilation mode in the fragment shader. (it does UV
1604 // flipping based on QSHADER_ macros) This is just better for
1605 // performance and the shaders are very simple so introducing a
1606 // uniform block and branching dynamically would be an overkill.
1607 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->effectiveDevicePixelRatio());
1608
1609 const auto &shaderCache = m_renderer->m_sgContext->shaderCache();
1610 const auto &shaderPipeline = shaderCache->getBuiltInRhiShaders().getRhiSimpleQuadShader(rhiCtx->mainPassViewCount());
1611
1616 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiContext.get());
1617 QRhiShaderResourceBindings *srb = rhiCtxD->srb(bindings);
1618
1620 ps.viewport = QRhiViewport(float(vp.x()), float(vp.y()), float(vp.width()), float(vp.height()));
1621 ps.samples = rhiCtx->mainPassSampleCount();
1622 ps.viewCount = rhiCtx->mainPassViewCount();
1624 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1625 cb->debugMarkEnd();
1626 }
1627 }
1628 else
1629 {
1630 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1631 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1632
1633 queryMainRenderPassDescriptorAndCommandBuffer(m_window, rhiContext.get());
1634
1635 m_renderer->rhiRender();
1636
1637 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1638 STAT_PAYLOAD(QSSGRhiContextStats::get(*rhiContext)),
1639 m_renderer->profilingId);
1640 m_renderer->endFrame();
1641
1642 if (m_renderer->renderStats())
1643 m_renderer->renderStats()->endRender(dumpRenderTimes);
1644 }
1645 }
1646}
1647
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
float greenF() const noexcept
Returns the green color component of this color.
Definition qcolor.cpp:1643
float redF() const noexcept
Returns the red color component of this color.
Definition qcolor.cpp:1611
float alphaF() const noexcept
Returns the alpha color component of this color.
Definition qcolor.cpp:1497
float blueF() const noexcept
Returns the blue color component of this color.
Definition qcolor.cpp:1675
static QColor fromRgbF(float r, float g, float b, float a=1.0)
Static convenience function that returns a QColor constructed from the RGB color values,...
Definition qcolor.cpp:2427
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtCore
Definition qcoreevent.h:45
Type
This enum type defines the valid event types in Qt.
Definition qcoreevent.h:51
void clear()
Definition qlist.h:434
QRect mapRect(const QRect &rect) const
Maps rect by multiplying this matrix by the corners of rect and then forming a new rectangle from the...
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
\inmodule QtCore\reentrant
Definition qpoint.h:217
\inmodule QtCore\reentrant
Definition qpoint.h:25
bool isHeightEnabled() const
\qmlproperty bool Fog::heightEnabled
float mostIntenseY
float transmitCurve
bool isTransmitEnabled() const
\qmlproperty bool Fog::transmitEnabled
float heightCurve
float leastIntenseY
bool isDepthEnabled() const
\qmlproperty bool Fog::depthEnabled
bool isEnabled() const
\qmltype Fog \inherits Object \inqmlmodule QtQuick3D
std::function< void(BakingStatus, std::optional< QString >, BakingControl *) Callback)
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
QQuick3DObject * parent
\qmlproperty Object3D QtQuick3D::Object3D::parent This property holds the parent of the Object3D in a...
static void updateLayerNodeHelper(const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode, bool &aaIsDirty, bool &temporalIsDirty, float &ssaaMultiplier)
void endSync(bool dump=false)
void setRhiContext(QSSGRhiContext *ctx, QSSGRenderLayer *layer)
void endRender(bool dump=false)
QQuick3DSceneRenderer * renderer()
void setViewport(const QRectF &viewport)
QQuick3DSGDirectRenderer(QQuick3DSceneRenderer *renderer, QQuickWindow *window, QQuick3DSGDirectRendererMode mode=Underlay)
void render(const RenderState *state) override
This function is called by the renderer and should paint this node with directly invoking commands in...
void releaseResources() override
This function is called when all custom graphics resources allocated by this node have to be freed im...
RenderingFlags flags() const override
void prepare() override
Called from the frame preparation phase.
QQuick3DSceneRenderer * renderer
StateFlags changedStates() const override
When the underlying rendering API is OpenGL, this function should return a mask where each bit repres...
QQuick3DDebugSettings * debugSettings
\qmlproperty QtQuick3D::DebugSettings QtQuick3D::SceneEnvironment::debugSettings
QRect scissorRect
\qmlproperty rect QtQuick3D::SceneEnvironment::scissorRect
QQuick3DCubeMapTexture * skyBoxCubeMap
\qmlproperty QtQuick3D::CubeMapTexture QtQuick3D::SceneEnvironment::skyBoxCubeMap
float skyboxBlurAmount
\qmlproperty float QtQuick3D::SceneEnvironment::skyboxBlurAmount
QQuick3DEnvironmentAAModeValues antialiasingMode
virtual const QVector< QQuick3DEffect * > & effectList() const
bool specularAAEnabled
\qmlproperty bool QtQuick3D::SceneEnvironment::specularAAEnabled
QQuick3DEnvironmentTonemapModes tonemapMode
bool aoEnabled
\qmlproperty bool SceneEnvironment::aoEnabled
QQuick3DFog * fog
\qmlproperty QtQuick3D::Fog QtQuick3D::SceneEnvironment::fog
QQuick3DEnvironmentBackgroundTypes backgroundMode
QQuick3DLightmapper * lightmapper
\qmlproperty Lightmapper QtQuick3D::SceneEnvironment::lightmapper
QQuick3DEnvironmentAAQualityValues antialiasingQuality
static QQuick3DWindowAttachment * getOrSetWindowAttachment(QQuickWindow &window)
QRhiTexture * renderToRhiTexture(QQuickWindow *qw)
PickResultList syncPick(const QSSGRenderRay &ray)
QQuick3DSceneRenderer(const std::shared_ptr< QSSGRenderContextInterface > &rci)
void rhiPrepare(const QRect &viewport, qreal displayPixelRatio)
PickResultList syncPickSubset(const QSSGRenderRay &ray, QVarLengthArray< QSSGRenderNode * > subset)
void synchronize(QQuick3DViewport *view3D, const QSize &size, float dpr)
std::optional< QSSGRenderRay > getRayFromViewportPos(const QPointF &pos)
PickResultList syncPickAll(const QSSGRenderRay &ray)
static QSSGRenderLayer::TonemapMode getTonemapMode(const QQuick3DSceneEnvironment &environment)
void setGlobalPickingEnabled(bool isEnabled)
QQuick3DRenderStats * renderStats()
PickResultList syncPickOne(const QSSGRenderRay &ray, QSSGRenderNode *node)
QSSGRenderImage * getRenderImage()
QQuick3DNode * importScene
QQuickShaderEffectSource::Format renderFormat
\qmlproperty enumeration QtQuick3D::View3D::renderFormat
const QList< QQuick3DObject * > & extensionList() const
bool extensionListDirty() const
QQuick3DLightmapBaker * maybeLightmapBaker()
QQuick3DRenderStats * renderStats
QQuick3DNode * scene
QQuick3DSceneEnvironment * environment
QQuick3DCamera * camera
Q_INVOKABLE bool synchronize(QSet< QSSGRenderGraphObject * > &resourceLoaders)
const std::shared_ptr< QSSGRenderContextInterface > & rci() const
QQuickWindow * window() const
void setRci(const std::shared_ptr< QSSGRenderContextInterface > &rciptr)
QQuickWindow * window() const
Returns the window in which this item is rendered.
void update()
Schedules a call to updatePaintNode() for this item.
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
void update()
Schedules the window to render another frame.
void beforeRendering()
\qmlsignal QtQuick::Window::afterSynchronizing()
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:221
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:185
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:242
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:188
\inmodule QtGui
Definition qrhi.h:846
@ Dynamic
Definition qrhi.h:851
@ UniformBuffer
Definition qrhi.h:857
virtual bool create()=0
Creates the corresponding native graphics resources.
\inmodule QtGui
Definition qrhi.h:576
void setTexture(QRhiTexture *tex)
Sets the texture tex.
Definition qrhi.h:583
void setRenderBuffer(QRhiRenderBuffer *rb)
Sets the renderbuffer rb.
Definition qrhi.h:586
void setMultiViewCount(int count)
Sets the view count.
Definition qrhi.h:604
void setResolveTexture(QRhiTexture *tex)
Sets the resolve texture tex.
Definition qrhi.h:595
\inmodule QtGui
Definition qrhi.h:1651
void setPixelSize(const QSize &sz)
Sets the size (in pixels) to sz.
Definition qrhi.h:1116
int sampleCount() const
Definition qrhi.h:1118
virtual bool create()=0
Creates the corresponding native graphics resources.
void setRenderPassDescriptor(QRhiRenderPassDescriptor *desc)
Sets the QRhiRenderPassDescriptor desc for use with this render target.
Definition qrhi.h:1165
QRhiRenderPassDescriptor * renderPassDescriptor() const
Definition qrhi.h:1164
\inmodule QtGui
Definition qrhi.h:1731
void copyTexture(QRhiTexture *dst, QRhiTexture *src, const QRhiTextureCopyDescription &desc=QRhiTextureCopyDescription())
Enqueues a texture-to-texture copy operation from src into dst as described by desc.
Definition qrhi.cpp:9116
@ TextureRenderTarget
Definition qrhi.h:813
void setName(const QByteArray &name)
Sets a name for the object.
Definition qrhi.cpp:3581
\inmodule QtGui
Definition qrhi.h:1030
@ ClampToEdge
Definition qrhi.h:1040
\inmodule QtGui
Definition qrhi.h:1214
\inmodule QtGui
Definition qrhi.h:1549
int sampleCount() const
Definition qrhi.h:1590
virtual QRhiRenderTarget * currentFrameRenderTarget()=0
QRhiRenderPassDescriptor * renderPassDescriptor() const
Definition qrhi.h:1593
virtual QRhiCommandBuffer * currentFrameCommandBuffer()=0
const QRhiColorAttachment * cbeginColorAttachments() const
Definition qrhi.h:634
\inmodule QtGui
Definition qrhi.h:1184
virtual QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor()=0
QRhiResource::Type resourceType() const override
Definition qrhi.cpp:5158
virtual bool create()=0
Creates the corresponding native graphics resources.
QRhiTextureRenderTargetDescription description() const
Definition qrhi.h:1195
\inmodule QtGui
Definition qrhi.h:895
Format format() const
Definition qrhi.h:972
void setFormat(Format fmt)
Sets the requested texture format to fmt.
Definition qrhi.h:973
@ UsedAsTransferSource
Definition qrhi.h:902
@ RenderTarget
Definition qrhi.h:898
int sampleCount() const
Definition qrhi.h:995
virtual bool create()=0
Creates the corresponding native graphics resources.
Format
Specifies the texture format.
Definition qrhi.h:914
@ RGBA32F
Definition qrhi.h:926
@ RGBA16F
Definition qrhi.h:925
void setPixelSize(const QSize &sz)
Sets the texture size, specified in pixels, to sz.
Definition qrhi.h:976
\inmodule QtGui
Definition qrhi.h:85
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
QRhiBuffer * newBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
Definition qrhi.cpp:10508
QRhiTexture * newTextureArray(QRhiTexture::Format format, int arraySize, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10636
bool isYUpInFramebuffer() const
Definition qrhi.cpp:10030
bool isFeatureSupported(QRhi::Feature feature) const
Definition qrhi.cpp:10110
QList< int > supportedSampleCounts() const
Definition qrhi.cpp:10953
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
Definition qrhi.cpp:10535
Implementation backend() const
Definition qrhi.cpp:8651
@ Metal
Definition qrhi.h:1811
QRhiTextureRenderTarget * newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags={})
Definition qrhi.cpp:10682
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10562
@ MultisampleRenderBuffer
Definition qrhi.h:1833
QRhiResourceUpdateBatch * nextResourceUpdateBatch()
Definition qrhi.cpp:9252
@ DirtyMaterial
Definition qsgnode.h:75
@ UsePreprocess
Definition qsgnode.h:52
void markDirty(DirtyState bits)
Notifies all connected renderers that the node has dirty bits.
Definition qsgnode.cpp:624
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:586
void setOwnsTexture(bool owns)
static QSGRenderNodePrivate * get(QSGRenderNode *node)
The QSGRenderNode class represents a set of custom rendering commands targeting the graphics API that...
const QMatrix4x4 * matrix() const
An interface providing access to some of the graphics API specific internals of the scenegraph.
static bool isApiRhiBased(GraphicsApi api)
void setTexture(QSGTexture *texture)
Sets the texture of this texture node to texture.
QSGTexture * texture() const
Returns the texture for this texture node.
void textureChanged()
This signal is emitted when the texture changes.
\inmodule QtQuick
Definition qsgtexture.h:20
static QRhiTexture::Format toRhiFormat(const QSSGRenderTextureFormat format)
QSSGLightmapper::Callback lightmapBakingOutputCallback
const QSSGRenderReflectionMapPtr & getReflectionMapManager() const
const QSSGRenderShadowMapPtr & getShadowMapManager() const
QSSGRenderCameraList renderedCameras
std::function< void(BakingStatus, std::optional< QString >, BakingControl *) Callback)
\inmodule QtQuick3D
static constexpr bool isExtension(Type type) noexcept
static PickResultList syncPickSubset(const QSSGRenderLayer &layer, QSSGBufferManager &bufferManager, const QSSGRenderRay &ray, QVarLengthArray< QSSGRenderNode * > subset)
static PickResultList syncPickAll(const QSSGRenderContextInterface &ctx, const QSSGRenderLayer &layer, const QSSGRenderRay &ray)
static void setGlobalPickingEnabled(QSSGRenderer &renderer, bool isEnabled)
static PickResultList syncPick(const QSSGRenderContextInterface &ctx, const QSSGRenderLayer &layer, const QSSGRenderRay &ray, QSSGRenderNode *target=nullptr)
static QSSGRhiContextPrivate * get(QSSGRhiContext *q)
static QSSGRhiContextStats & get(QSSGRhiContext &rhiCtx)
QSSGRenderLayer * layerKey
QHash< QSSGRenderLayer *, PerLayerInfo > perLayerInfo
static quint64 totalDrawCallCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
\inmodule QtQuick3D
bool isValid() const
int mainPassSampleCount() const
Returns the sample count used in the main render pass.
int mainPassViewCount() const
Returns the multiview count used in the main render pass.
QRhiCommandBuffer * commandBuffer() const
QRhiCommandBuffer::BeginPassFlags commonPassFlags() const
QRhi * rhi() const
QRhiSampler * sampler(const QSSGRhiSamplerDescription &samplerDescription)
QRhiRenderPassDescriptor * mainRenderPassDescriptor() const
QRhiTexture * process(const QSSGRenderEffect &firstEffect, QRhiTexture *inTexture, QRhiTexture *inDepthTexture, QVector2D cameraClipRange)
void setup(QSize outputSize)
static QSSGRenderTextureFormat::Format overriddenOutputFormat(const QSSGRenderEffect *inEffect)
void addUniformBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset=0, int size=0)
void addTexture(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
\inmodule QtCore
Definition qsize.h:208
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QThread * currentThread()
Definition qthread.cpp:1039
bool isEmpty() const
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
constexpr float y() const noexcept
Returns the y coordinate of this point.
Definition qvectornd.h:502
constexpr float x() const noexcept
Returns the x coordinate of this point.
Definition qvectornd.h:501
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
constexpr QVector3D toVector3D() const noexcept
Returns the 3D vector form of this 4D vector, dropping the w coordinate.
Definition qvectornd.h:1011
QQuick3DSceneRenderer * renderer
QSGTexture * texture() const override
Returns a pointer to the texture object.
void preprocess() override
Override this function to do processing on the node before it is rendered.
QCamera * camera
Definition camera.cpp:19
QSet< QString >::iterator it
rect
[4]
else opt state
[0]
QVector3D tonemapFilmic(const QVector3D &c)
QVector3D tonemapHejlDawson(const QVector3D &c)
QVector3D tonemapAces(const QVector3D &c)
QVector3D tonemapLinearToSrgb(const QVector3D &c)
QVector2D toRectRelative(const QRectF &r, const QVector2D &absoluteCoordinates)
Combined button and popup list for selecting options.
@ transparent
Definition qnamespace.h:47
@ color0
Definition qnamespace.h:28
@ DirectConnection
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
#define qWarning
Definition qlogging.h:166
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
GLenum mode
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLuint sampler
GLenum GLenum GLsizei count
GLint GLsizei width
GLenum type
GLenum GLuint texture
GLint GLsizei GLsizei GLenum format
GLint y
const GLubyte * c
const GLfloat * tc
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
#define Q_QUICK3D_PROFILE_START(Type)
#define Q_QUICK3D_PROFILE_END_WITH_ID(Type, Payload, POID)
#define Q_QUICK3D_PROFILE_END_WITH_STRING(Type, Payload, Str)
static QRhiTexture::Format toRhiTextureFormat(QQuickShaderEffectSource::Format format)
static const QVector2D s_ProgressiveAABlendFactors[QSSGLayerRenderData::MAX_AA_LEVELS]
static const QVector2D s_TemporalAABlendFactors
static void bfs(In *inExtension, QList< Out * > &outList)
static bool dumpRenderTimes
QT_BEGIN_NAMESPACE QSSG_prepareFrame_entry
static QVector3D tonemapRgb(const QVector3D &c, QQuick3DSceneEnvironment::QQuick3DEnvironmentTonemapModes tonemapMode)
static void requestFullUpdate(QQuickWindow *window)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
void qsgnode_set_description(QSGNode *node, const QString &description)
Definition qsgnode.cpp:641
#define QSSG_ASSERT(cond, action)
#define QSSGRHICTX_STAT(ctx, f)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define QStringLiteral(str)
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define emit
#define Q_UNUSED(x)
#define Q_TRACE_PREFIX(provider, prefix)
Definition qtrace_p.h:233
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE(x,...)
Definition qtrace_p.h:144
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
unsigned int quint32
Definition qtypes.h:50
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
double qreal
Definition qtypes.h:187
static bool isEmbedded(const QWindow *w)
Definition qwidget.cpp:6612
QList< int > list
[14]
QObject::connect nullptr
QQueue< int > queue
[0]
view viewport() -> scroll(dx, dy, deviceRect)
aWidget window() -> setWindowTitle("New Window Title")
[2]
QHostInfo info
[0]
QSvgRenderer * renderer
[0]
QSSGRenderEffect * m_nextEffect
QSSGRenderImage * skyBoxCubeMap
@ EnableDepthPrePass
True when we render a depth pass before.
QVarLengthArray< QSSGRenderCamera *, 2 > renderedCameras
QList< QSSGRenderExtension * > renderExtensions[size_t(RenderExtensionStage::Count)]
QSSGRenderImage * lightProbe
QSSGRenderLayer::AAMode antialiasingMode
QSSGLayerRenderData * renderData
QSSGRenderLayer::AAQuality antialiasingQuality
void removeImportScene(QSSGRenderNode &rootNode)
void setImportScene(QSSGRenderNode &rootNode)
QSSGRenderEffect * firstEffect
void addChild(QSSGRenderNode &inChild)
void removeChild(QSSGRenderNode &inChild)
static void setShaderPipeline(QSSGRhiGraphicsPipelineState &ps, const QSSGRhiShaderPipeline *pipeline)