Qt 6.x
The Qt SDK
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);
57
58static bool dumpRenderTimes = false;
59
60#if QT_CONFIG(qml_debug)
61
62static inline quint64 statDrawCallCount(const QSSGRhiContextStats &stats)
63{
64 quint64 count = 0;
66 for (const auto &pass : info.renderPasses)
69 return count;
70}
71
72#define STAT_PAYLOAD(stats) \
73 (statDrawCallCount(stats) | (quint64(stats.perLayerInfo[stats.layerKey].renderPasses.size()) << 32))
74
75#endif
76
77template <typename In, typename Out>
78static void bfs(In *inExtension, QList<Out *> &outList)
79{
80 outList.clear();
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
107{
108 delete renderer;
109 delete texture();
110}
111
113{
114 renderPending = true;
116}
117
119{
121}
122
124{
125 render();
126}
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()
132{
134 window->update();
135 else
137}
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->m_sgContext->renderer()->rendererRequestsFrames()
173 || renderer->requestedFramesCount > 0) {
176 if (renderer->requestedFramesCount > 0)
177 renderer->requestedFramesCount--;
178 }
179 }
180}
181
183{
184 if (!qFuzzyCompare(window->effectiveDevicePixelRatio(), devicePixelRatio)) {
186 quickFbo->update();
187 }
188}
189
190
191QQuick3DSceneRenderer::QQuick3DSceneRenderer(const std::shared_ptr<QSSGRenderContextInterface> &rci)
192 : m_sgContext(rci)
193{
194 dumpRenderTimes = (qEnvironmentVariableIntValue("QT_QUICK3D_DUMP_RENDERTIMES") > 0);
195}
196
198{
199 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
200 rhiCtx->stats().cleanupLayerInfo(m_layer);
201 delete m_layer;
202
203 delete m_texture;
204
205 releaseAaDependentRhiResources();
206 delete m_effectSystem;
207}
208
209void QQuick3DSceneRenderer::releaseAaDependentRhiResources()
210{
211 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
212 if (!rhiCtx->isValid())
213 return;
214
215 delete m_textureRenderTarget;
216 m_textureRenderTarget = nullptr;
217
218 delete m_textureRenderPassDescriptor;
219 m_textureRenderPassDescriptor = nullptr;
220
221 delete m_depthStencilBuffer;
222 m_depthStencilBuffer = nullptr;
223
224 delete m_msaaRenderBuffer;
225 m_msaaRenderBuffer = nullptr;
226
227 delete m_ssaaTexture;
228 m_ssaaTexture = nullptr;
229
230 delete m_ssaaTextureToTextureRenderTarget;
231 m_ssaaTextureToTextureRenderTarget = nullptr;
232
233 delete m_ssaaTextureToTextureRenderPassDescriptor;
234 m_ssaaTextureToTextureRenderPassDescriptor = nullptr;
235
236 delete m_temporalAATexture;
237 m_temporalAATexture = nullptr;
238 delete m_temporalAARenderTarget;
239 m_temporalAARenderTarget = nullptr;
240 delete m_temporalAARenderPassDescriptor;
241 m_temporalAARenderPassDescriptor = nullptr;
242
243 delete m_prevTempAATexture;
244 m_prevTempAATexture = nullptr;
245}
246
247// Blend factors are in the form of (frame blend factor, accumulator blend factor)
249 QVector2D(0.500000f, 0.500000f), // 1x
250 QVector2D(0.333333f, 0.666667f), // 2x
251 QVector2D(0.250000f, 0.750000f), // 3x
252 QVector2D(0.200000f, 0.800000f), // 4x
253 QVector2D(0.166667f, 0.833333f), // 5x
254 QVector2D(0.142857f, 0.857143f), // 6x
255 QVector2D(0.125000f, 0.875000f), // 7x
256 QVector2D(0.111111f, 0.888889f), // 8x
257};
258
259static const QVector2D s_TemporalAABlendFactors = { 0.5f, 0.5f };
260
262{
263 if (!m_layer)
264 return nullptr;
265
266 QRhiTexture *currentTexture = m_texture; // the result so far
267
268 if (qw) {
269 if (m_renderStats)
270 m_renderStats->startRenderPrepare();
271
272 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
273
274 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
275
276 rhiCtx->setMainRenderPassDescriptor(m_textureRenderPassDescriptor);
277 rhiCtx->setRenderTarget(m_textureRenderTarget);
278
279 QRhiCommandBuffer *cb = nullptr;
280 QRhiSwapChain *swapchain = qw->swapChain();
281 if (swapchain) {
282 cb = swapchain->currentFrameCommandBuffer();
283 rhiCtx->setCommandBuffer(cb);
284 } else {
285 QSGRendererInterface *rif = qw->rendererInterface();
286 cb = static_cast<QRhiCommandBuffer *>(
288 if (cb)
289 rhiCtx->setCommandBuffer(cb);
290 else {
291 qWarning("Neither swapchain nor redirected command buffer are available.");
292 return currentTexture;
293 }
294 }
295
296 // Graphics pipeline objects depend on the MSAA sample count, so the
297 // renderer needs to know the value.
298 rhiCtx->setMainPassSampleCount(m_msaaRenderBuffer ? m_msaaRenderBuffer->sampleCount() : 1);
299
300 int ssaaAdjustedWidth = m_surfaceSize.width();
301 int ssaaAdjustedHeight = m_surfaceSize.height();
303 ssaaAdjustedWidth *= m_ssaaMultiplier;
304 ssaaAdjustedHeight *= m_ssaaMultiplier;
305 }
306
307 Q_TRACE(QSSG_prepareFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
308
309 float dpr = m_sgContext->dpr();
310 const QRect vp = QRect(0, 0, ssaaAdjustedWidth, ssaaAdjustedHeight);
311 beginFrame();
312 rhiPrepare(vp, dpr);
313
314 if (m_renderStats)
315 m_renderStats->endRenderPrepare();
316
317 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, profilingId);
318
319 Q_TRACE(QSSG_prepareFrame_exit);
320
321 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
322 Q_TRACE(QSSG_renderFrame_entry, ssaaAdjustedWidth, ssaaAdjustedHeight);
323
324 QColor clearColor = Qt::transparent;
325 if (m_backgroundMode == QSSGRenderLayer::Background::Color
326 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBoxCubeMap && !m_layer->skyBoxCubeMap)
327 || (m_backgroundMode == QSSGRenderLayer::Background::SkyBox && !m_layer->lightProbe))
328 {
329 // Same logic as with the main render pass and skybox: tonemap
330 // based on tonemapMode (unless it is None), unless there are effects.
331 clearColor = m_layer->firstEffect ? m_linearBackgroundColor : m_tonemappedBackgroundColor;
332 }
333
334 // This is called from the node's preprocess() meaning Qt Quick has not
335 // actually began recording a renderpass. Do our own.
336 cb->beginPass(m_textureRenderTarget, clearColor, { 1.0f, 0 }, nullptr, QSSGRhiContext::commonPassFlags());
337 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
338 QSSGRHICTX_STAT(rhiCtx, beginRenderPass(m_textureRenderTarget));
339 rhiRender();
340 cb->endPass();
341 QSSGRHICTX_STAT(rhiCtx, endRenderPass());
342 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, quint64(ssaaAdjustedWidth) | quint64(ssaaAdjustedHeight) << 32, QByteArrayLiteral("main"));
343
344 const bool temporalAA = m_layer->temporalAAIsActive;
345 const bool progressiveAA = m_layer->progressiveAAIsActive;
346 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
347 QRhi *rhi = rhiCtx->rhi();
348
349 currentTexture = superSamplingAA ? m_ssaaTexture : m_texture;
350
351 // Do effects before antialiasing
352 if (m_effectSystem && m_layer->firstEffect && m_layer->renderedCamera) {
353 const auto &renderer = m_sgContext->renderer();
354 QSSGLayerRenderData *theRenderData = renderer->getOrCreateLayerRenderData(*m_layer);
355 Q_ASSERT(theRenderData);
356 QRhiTexture *theDepthTexture = theRenderData->depthMapPass.rhiDepthTexture.texture;
357 QVector2D cameraClipRange(m_layer->renderedCamera->clipNear, m_layer->renderedCamera->clipFar);
358
359 currentTexture = m_effectSystem->process(*m_layer->firstEffect,
360 currentTexture,
361 theDepthTexture,
362 cameraClipRange);
363 }
364
365 // The only difference between temporal and progressive AA at this point is that tempAA always
366 // uses blend factors of 0.5 and copies currentTexture to m_prevTempAATexture, while progAA uses blend
367 // factors from a table and copies the blend result to m_prevTempAATexture
368
369 if ((progressiveAA || temporalAA) && m_prevTempAATexture) {
370 cb->debugMarkBegin(QByteArrayLiteral("Temporal AA"));
371 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
372 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("Temporal AA"));
373 QRhiTexture *blendResult;
374 uint *aaIndex = progressiveAA ? &m_layer->progAAPassIndex : &m_layer->tempAAPassIndex; // TODO: can we use only one index?
375
376 if (*aaIndex > 0) {
377 if (temporalAA || *aaIndex < quint32(m_layer->antialiasingQuality)) {
378 const auto &renderer = m_sgContext->renderer();
379
380 // The fragment shader relies on per-target compilation and
381 // QSHADER_ macros of qsb, hence no need to communicate a flip
382 // flag from here.
383 const auto &shaderPipeline = renderer->getRhiProgressiveAAShader();
384 QRhiResourceUpdateBatch *rub = nullptr;
385
386 QSSGRhiDrawCallData &dcd(rhiCtx->drawCallData({ m_layer, nullptr, nullptr, 0, QSSGRhiDrawCallDataKey::ProgressiveAA }));
387 QRhiBuffer *&ubuf = dcd.ubuf;
388 const int ubufSize = 2 * sizeof(float);
389 if (!ubuf) {
391 ubuf->create();
392 }
393
394 rub = rhi->nextResourceUpdateBatch();
395 int idx = *aaIndex - 1;
396 const QVector2D *blendFactors = progressiveAA ? &s_ProgressiveAABlendFactors[idx] : &s_TemporalAABlendFactors;
397 rub->updateDynamicBuffer(ubuf, 0, 2 * sizeof(float), blendFactors);
398 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, rub);
399
404 bindings.addTexture(1, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
405 bindings.addTexture(2, QRhiShaderResourceBinding::FragmentStage, m_prevTempAATexture, sampler);
406
407 QRhiShaderResourceBindings *srb = rhiCtx->srb(bindings);
408
410 const QSize textureSize = currentTexture->pixelSize();
411 ps.viewport = QRhiViewport(0, 0, float(textureSize.width()), float(textureSize.height()));
412 ps.shaderPipeline = shaderPipeline.get();
413
414 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_temporalAARenderTarget, QSSGRhiQuadRenderer::UvCoords);
415 blendResult = m_temporalAATexture;
416 } else {
417 blendResult = m_prevTempAATexture;
418 }
419 } else {
420 // For the first frame: no blend, only copy
421 blendResult = currentTexture;
422 }
423
425
426 if (temporalAA || (*aaIndex < quint32(m_layer->antialiasingQuality))) {
427 auto *rub = rhi->nextResourceUpdateBatch();
428 if (progressiveAA)
429 rub->copyTexture(m_prevTempAATexture, blendResult);
430 else
431 rub->copyTexture(m_prevTempAATexture, currentTexture);
432 cb->resourceUpdate(rub);
433 }
434
435 (*aaIndex)++;
436 cb->debugMarkEnd();
437 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("temporal_aa"));
438
439 currentTexture = blendResult;
440 }
441
443 // With supersampling antialiasing we at this point have the
444 // content rendered at a larger size into m_ssaaTexture. Now scale
445 // it down to the expected size into m_texture, using linear
446 // filtering. Unlike in the OpenGL world, there is no
447 // glBlitFramebuffer equivalent available, because APIs like D3D
448 // and Metal have no such operation (the generally supported
449 // texture copy operations are 1:1 copies, without support for
450 // scaling, which is what we would need here). So draw a quad.
451
453 const auto &renderer = m_sgContext->renderer();
454
455 cb->debugMarkBegin(QByteArrayLiteral("SSAA downsample"));
456 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
457
458 Q_TRACE_SCOPE(QSSG_renderPass, QStringLiteral("SSAA downsample"));
459
460 renderer->rhiQuadRenderer()->prepareQuad(rhiCtx, nullptr);
461
462 // Instead of passing in a flip flag we choose to rely on qsb's
463 // per-target compilation mode in the fragment shader. (it does UV
464 // flipping based on QSHADER_ macros) This is just better for
465 // performance and the shaders are very simple so introducing a
466 // uniform block and branching dynamically would be an overkill.
467 const auto &shaderPipeline = renderer->getRhiSupersampleResolveShader();
468
472 bindings.addTexture(0, QRhiShaderResourceBinding::FragmentStage, currentTexture, sampler);
473 QRhiShaderResourceBindings *srb = rhiCtx->srb(bindings);
474
476 ps.viewport = QRhiViewport(0, 0, float(m_surfaceSize.width()), float(m_surfaceSize.height()));
477 ps.shaderPipeline = shaderPipeline.get();
478
479 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiCtx, &ps, srb, m_ssaaTextureToTextureRenderTarget, QSSGRhiQuadRenderer::UvCoords);
480 cb->debugMarkEnd();
481 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("ssaa_downsample"));
482
483 currentTexture = m_texture;
484 }
485 endFrame();
486
487 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
488 STAT_PAYLOAD(m_sgContext->rhiContext()->stats()),
489 profilingId);
490
491 Q_TRACE(QSSG_renderFrame_exit);
492
493 }
494
495 return currentTexture;
496}
497
499{
500 m_sgContext->beginFrame(m_layer);
501}
502
504{
505 m_sgContext->endFrame(m_layer);
506}
507
509{
510 if (!m_layer)
511 return;
512
513 m_sgContext->setDpr(displayPixelRatio);
514
515 m_sgContext->setViewport(viewport);
516
517 m_sgContext->setSceneColor(QColor(Qt::black));
518
519 m_sgContext->prepareLayerForRender(*m_layer);
520 // If sync was called the assumption is that the scene is dirty regardless of what
521 // the scene prep function says, we still should verify that we have a camera before
522 // we call render prep and render.
523 const bool renderReady = (m_layer->renderData->camera != nullptr);
524 if (renderReady) {
525 m_sgContext->rhiPrepare(*m_layer);
526 m_prepared = true;
527 }
528}
529
531{
532 if (m_prepared) {
533 // There is no clearFirst flag - the rendering here does not record a
534 // beginPass() so it never clears on its own.
535
536 m_sgContext->rhiRender(*m_layer);
537 }
538
539 m_prepared = false;
540}
541
543{
544 switch (format) {
546 return QRhiTexture::RGBA8;
551 default:
552 return QRhiTexture::RGBA8;
553 }
554}
555
557{
558 switch (tonemapMode) {
567 default:
568 break;
569 }
570 return c;
571}
572
574{
575 Q_TRACE_SCOPE(QSSG_synchronize, view3D, size, dpr);
576
577 Q_ASSERT(view3D != nullptr); // This is not an option!
578 QSSGRhiContext *rhiCtx = m_sgContext->rhiContext().get();
579 Q_ASSERT(rhiCtx != nullptr);
580
581 bool newRenderStats = false;
582 if (!m_renderStats) {
583 m_renderStats = view3D->renderStats();
584 newRenderStats = true;
585 }
586
587 if (m_renderStats)
588 m_renderStats->startSync();
589
590 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DSynchronizeFrame);
591
592 m_sgContext->setDpr(dpr);
593 bool layerSizeIsDirty = m_surfaceSize != size;
594 m_surfaceSize = size;
595
596 // Synchronize scene managers under this window
597 QSet<QSSGRenderGraphObject *> resourceLoaders;
598 bool requestSharedUpdate = false;
599 if (auto window = view3D->window()) {
600 if (!winAttacment || winAttacment->window() != window)
602
603 if (winAttacment && winAttacment->rci() != m_sgContext)
604 winAttacment->setRci(m_sgContext);
605
606 if (winAttacment)
607 requestSharedUpdate = winAttacment->synchronize(resourceLoaders);
608 }
609
610 // Import scenes used in a multi-window application...
611 QQuick3DNode *importScene = view3D->importScene();
612 if (importScene) {
613 QQuick3DSceneManager *importSceneManager = QQuick3DObjectPrivate::get(importScene)->sceneManager;
614 // If the import scene is used with 3D views under a different window, then we'll
615 // need to trigger updates for those as well.
616 if (auto window = importSceneManager->window(); window && window != view3D->window()) {
617 if (auto winAttacment = importSceneManager->wattached) {
618 // Not the same window but backed by the same rhi?
619 auto rci = winAttacment->rci();
620 const bool inlineSync = (rci && rci->rhi() && (rci->rhi()->thread() == m_sgContext->rhi()->thread()));
621 if (inlineSync) {
622 // Given that we're on the same thread, we can do an immediate sync
623 // (rhi instances can differ, e.g., basic renderloop).
624 winAttacment->synchronize(resourceLoaders);
625 } else if (rci && !window->isExposed()) { // Forced sync of non-exposed windows
626 // Not exposed, so not rendering (playing with fire here)...
627 winAttacment->synchronize(resourceLoaders);
628 } else if (!rci || requestSharedUpdate) {
629 // If there's no RCI for the importscene we'll request an update, which should
630 // mean we only get here once. It also means the update to any secondary windows
631 // will be delayed. Note that calling this function on each sync would cause the
632 // different views to ping-pong for updated forever...
633 winAttacment->requestUpdate();
634 }
635 }
636 }
637 }
638
639 // Generate layer node
640 if (!m_layer)
641 m_layer = new QSSGRenderLayer();
642
643 if (newRenderStats)
644 m_renderStats->setRhiContext(rhiCtx, m_layer);
645
646 // if the list is dirty we rebuild (assumption is that this won't happen frequently).
647 if (view3D->extensionListDirty()) {
648 // All items in the extension list are root items,
649 const auto &extensions = view3D->extensionList();
650 for (const auto &ext : extensions) {
653 if (type == QSSGRenderGraphObject::Type::RenderExtension) {
654 if (auto *renderExt = qobject_cast<QQuick3DRenderExtension *>(ext)) {
655 const auto mode = static_cast<QSSGRenderExtension *>(QQuick3DObjectPrivate::get(renderExt)->spatialNode)->mode();
656 QSSG_ASSERT(size_t(mode) < std::size(m_layer->renderExtensions), continue);
657 auto &list = m_layer->renderExtensions[size_t(mode)];
658 bfs(qobject_cast<QQuick3DRenderExtension *>(ext), list);
659 }
660 }
661 }
662 }
663
664 view3D->clearExtensionListDirty();
665 }
666
667 // Update the layer node properties
668 updateLayerNode(view3D, resourceLoaders.values());
669
670 bool postProcessingNeeded = m_layer->firstEffect;
671 bool postProcessingWasActive = m_effectSystem;
673 if (postProcessingNeeded) {
674 QSSGRenderEffect *lastEffect = m_layer->firstEffect;
675 while (lastEffect->m_nextEffect)
676 lastEffect = lastEffect->m_nextEffect;
677 effectOutputFormatOverride = QSSGRhiEffectSystem::overriddenOutputFormat(lastEffect);
678 }
679 const auto layerTextureFormat = [effectOutputFormatOverride, view3D](QRhi *rhi, bool postProc) {
680 if (effectOutputFormatOverride != QSSGRenderTextureFormat::Unknown)
681 return QSSGBufferManager::toRhiFormat(effectOutputFormatOverride);
682
683 // Our standard choice for the postprocessing input/output textures'
684 // format is a floating point one. (unlike intermediate Buffers, which
685 // default to RGBA8 unless the format is explicitly specified)
686 // This is intentional since a float format allows passing in
687 // non-tonemapped content without colors being clamped when written out
688 // to the render target.
689 //
690 // When it comes to the output, this applies to that too due to
691 // QSSGRhiEffectSystem picking it up unless overridden (with a Buffer
692 // an empty 'name'). Here too a float format gives more flexibility:
693 // the effect may or may not do its own tonemapping and this approach
694 // is compatible with potential future on-screen HDR output support.
695
696 const QRhiTexture::Format preferredPostProcFormat = QRhiTexture::RGBA16F;
697 if (postProc && rhi->isTextureFormatSupported(preferredPostProcFormat))
698 return preferredPostProcFormat;
699
700 const QRhiTexture::Format preferredView3DFormat = toRhiTextureFormat(view3D->renderFormat());
701 if (rhi->isTextureFormatSupported(preferredView3DFormat))
702 return preferredView3DFormat;
703
704 return QRhiTexture::RGBA8;
705 };
706 bool postProcessingStateDirty = postProcessingNeeded != postProcessingWasActive;
707
708 // Store from the layer properties the ones we need to handle ourselves (with the RHI code path)
709 m_backgroundMode = QSSGRenderLayer::Background(view3D->environment()->backgroundMode());
710
711 // This is stateful since we only want to recalculate the tonemapped color
712 // when the color changes, not in every frame.
713 QColor currentUserBackgroundColor = view3D->environment()->clearColor();
714 if (m_userBackgroundColor != currentUserBackgroundColor) {
715 m_userBackgroundColor = currentUserBackgroundColor;
716 m_linearBackgroundColor = color::sRGBToLinearColor(m_userBackgroundColor);
717 const QVector3D tc = tonemapRgb(QVector3D(m_linearBackgroundColor.redF(),
718 m_linearBackgroundColor.greenF(),
719 m_linearBackgroundColor.blueF()),
720 view3D->environment()->tonemapMode());
721 m_tonemappedBackgroundColor = QColor::fromRgbF(tc.x(), tc.y(), tc.z(), m_linearBackgroundColor.alphaF());
722 }
723 m_layer->scissorRect = QRect(view3D->environment()->scissorRect().topLeft() * dpr,
724 view3D->environment()->scissorRect().size() * dpr);
725
726 // Set the root item for the scene to the layer
727 auto rootNode = static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(view3D->scene())->spatialNode);
728 if (rootNode != m_sceneRootNode) {
729 if (m_sceneRootNode)
730 removeNodeFromLayer(m_sceneRootNode);
731
732 if (rootNode)
733 addNodeToLayer(rootNode);
734
735 m_sceneRootNode = rootNode;
736 }
737
738 // Add the referenced scene root node to the layer as well if available
739 QSSGRenderNode *importRootNode = nullptr;
740 if (importScene)
741 importRootNode = static_cast<QSSGRenderNode*>(QQuick3DObjectPrivate::get(importScene)->spatialNode);
742
743 if (importRootNode != m_importRootNode) {
744 if (m_importRootNode)
745 m_layer->removeImportScene(*m_importRootNode);
746
747 if (importRootNode) {
748 // if importScene has the rendered viewport as ancestor, it probably means
749 // "importScene: MyScene { }" type of inclusion.
750 // In this case don't duplicate content by adding it again.
751 QObject *sceneParent = importScene->parent();
752 bool isEmbedded = false;
753 while (sceneParent) {
754 if (sceneParent == view3D) {
755 isEmbedded = true;
756 break;
757 }
758 sceneParent = sceneParent->parent();
759 }
760 if (!isEmbedded)
761 m_layer->setImportScene(*importRootNode);
762 }
763
764 m_importRootNode = importRootNode;
765 }
766
767 if (auto lightmapBaker = view3D->maybeLightmapBaker()) {
768 if (lightmapBaker->m_bakingRequested) {
770
771 QQuick3DLightmapBaker::Callback qq3dCallback = lightmapBaker->m_callback;
772 QQuick3DLightmapBaker::BakingControl *qq3dBakingControl = lightmapBaker->m_bakingControl;
774 [qq3dCallback, qq3dBakingControl](
775 QSSGLightmapper::BakingStatus qssgBakingStatus,
776 std::optional<QString> msg,
777 QSSGLightmapper::BakingControl *qssgBakingControl)
778 {
780 switch (qssgBakingStatus)
781 {
783 break;
786 break;
789 break;
792 break;
795 break;
798 break;
799 }
800
801 qq3dCallback(qq3dBakingStatus, msg, qq3dBakingControl);
802
803 if (qq3dBakingControl->isCancelled() && !qssgBakingControl->cancelled)
804 qssgBakingControl->cancelled = true;
805 };
806
807 m_layer->renderData->lightmapBakingOutputCallback = callback;
808 lightmapBaker->m_bakingRequested = false;
809 }
810 }
811
812 const bool progressiveAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::ProgressiveAA;
813 const bool multiSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::MSAA;
814 const bool temporalAA = m_layer->temporalAAEnabled && !multiSamplingAA;
815 const bool superSamplingAA = m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA;
816 const bool timeBasedAA = progressiveAA || temporalAA;
817 m_postProcessingStack = m_layer->firstEffect || timeBasedAA || superSamplingAA;
818 bool useFBO = view3D->renderMode() == QQuick3DViewport::RenderMode::Offscreen ||
820 && m_postProcessingStack);
821 if (useFBO && rhiCtx->isValid()) {
822 QRhi *rhi = rhiCtx->rhi();
823 const QSize renderSize = superSamplingAA ? m_surfaceSize * m_ssaaMultiplier : m_surfaceSize;
824
825 if (m_texture) {
826 // the size changed, or the AA settings changed, or toggled between some effects - no effect
827 if (layerSizeIsDirty || postProcessingStateDirty) {
828 m_texture->setPixelSize(m_surfaceSize);
829 m_texture->setFormat(layerTextureFormat(rhi, postProcessingNeeded));
830 m_texture->create();
831
832 // If AA settings changed, then we drop and recreate all
833 // resources, otherwise use a lighter path if just the size
834 // changed.
835 if (!m_aaIsDirty) {
836 // A special case: when toggling effects and AA is on,
837 // use the heavier AA path because the renderbuffer for
838 // MSAA and texture for SSAA may need a different
839 // format now since m_texture's format could have
840 // changed between RBGA8 and RGBA16F (due to layerTextureFormat()).
841 if (postProcessingStateDirty && (m_layer->antialiasingMode != QSSGRenderLayer::AAMode::NoAA || temporalAA)) {
842 releaseAaDependentRhiResources();
843 } else {
844 if (m_ssaaTexture) {
845 m_ssaaTexture->setPixelSize(renderSize);
846 m_ssaaTexture->create();
847 }
848 m_depthStencilBuffer->setPixelSize(renderSize);
849 m_depthStencilBuffer->create();
850 if (m_msaaRenderBuffer) {
851 m_msaaRenderBuffer->setPixelSize(renderSize);
852 m_msaaRenderBuffer->create();
853 }
854 // Toggling effects on and off will change the format
855 // (assuming effects default to a floating point
856 // format) and that needs on a different renderpass on
857 // Vulkan. Hence renewing m_textureRenderPassDescriptor as well.
858 if (postProcessingStateDirty) {
859 delete m_textureRenderPassDescriptor;
860 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
861 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
862 }
863 m_textureRenderTarget->create();
864 if (m_ssaaTextureToTextureRenderTarget)
865 m_ssaaTextureToTextureRenderTarget->create();
866
867 if (m_temporalAATexture) {
868 m_temporalAATexture->setPixelSize(renderSize);
869 m_temporalAATexture->create();
870 }
871 if (m_prevTempAATexture) {
872 m_prevTempAATexture->setPixelSize(renderSize);
873 m_prevTempAATexture->create();
874 }
875 if (m_temporalAARenderTarget)
876 m_temporalAARenderTarget->create();
877 }
878 }
879 } else if (m_aaIsDirty && rhi->backend() == QRhi::Metal) { // ### to avoid garbage upon enabling MSAA with macOS 10.14 (why is this needed?)
880 m_texture->create();
881 }
882
883 if (m_aaIsDirty)
884 releaseAaDependentRhiResources();
885 }
886
887 const QRhiTexture::Flags textureFlags = QRhiTexture::RenderTarget
888 | QRhiTexture::UsedAsTransferSource; // transfer source is for progressive/temporal AA
889 const QRhiTexture::Format textureFormat = layerTextureFormat(rhi, postProcessingNeeded);
890
891 if (!m_texture) {
892 m_texture = rhi->newTexture(textureFormat, m_surfaceSize, 1, textureFlags);
893 m_texture->create();
894 }
895
896 if (!m_ssaaTexture && superSamplingAA) {
897 m_ssaaTexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
898 m_ssaaTexture->create();
899 }
900
901 if (timeBasedAA && !m_temporalAATexture) {
902 m_temporalAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
903 m_temporalAATexture->create();
904 m_prevTempAATexture = rhi->newTexture(textureFormat, renderSize, 1, textureFlags);
905 m_prevTempAATexture->create();
906 }
907
908 // we need to re-render time-based AA not only when AA state changes, but also when resized
909 if (m_aaIsDirty || layerSizeIsDirty)
910 m_layer->tempAAPassIndex = m_layer->progAAPassIndex = 0;
911
912 if (m_aaIsDirty) {
913 m_samples = 1;
916 m_samples = qMax(1, int(m_layer->antialiasingQuality));
917 // The Quick3D API exposes high level values such as
918 // Medium, High, VeryHigh instead of direct sample
919 // count values. Therefore, be nice and find a sample
920 // count that's actually supported in case the one
921 // associated by default is not.
922 const QVector<int> supported = rhi->supportedSampleCounts(); // assumed to be sorted
923 if (!supported.contains(m_samples)) {
924 if (!supported.isEmpty()) {
925 auto it = std::lower_bound(supported.cbegin(), supported.cend(), m_samples);
926 m_samples = it == supported.cend() ? supported.last() : *it;
927 } else {
928 m_samples = 1;
929 }
930 }
931 } else {
932 static bool warned = false;
933 if (!warned) {
934 warned = true;
935 qWarning("Multisample renderbuffers are not supported, disabling MSAA for Offscreen View3D");
936 }
937 }
938 }
939 }
940
941 if (!m_depthStencilBuffer) {
942 m_depthStencilBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, renderSize, m_samples);
943 m_depthStencilBuffer->create();
944 }
945
946 if (!m_textureRenderTarget) {
948 if (m_samples > 1) {
949 // pass in the texture's format (which may be a floating point one!) as the preferred format hint
950 m_msaaRenderBuffer = rhi->newRenderBuffer(QRhiRenderBuffer::Color, renderSize, m_samples, {}, m_texture->format());
951 m_msaaRenderBuffer->create();
953 att.setRenderBuffer(m_msaaRenderBuffer);
954 att.setResolveTexture(m_texture);
955 rtDesc.setColorAttachments({ att });
956 } else {
958 rtDesc.setColorAttachments({ m_ssaaTexture });
959 else
960 rtDesc.setColorAttachments({ m_texture });
961 }
962 rtDesc.setDepthStencilBuffer(m_depthStencilBuffer);
963
964 m_textureRenderTarget = rhi->newTextureRenderTarget(rtDesc);
965 m_textureRenderTarget->setName(QByteArrayLiteral("View3D"));
966 m_textureRenderPassDescriptor = m_textureRenderTarget->newCompatibleRenderPassDescriptor();
967 m_textureRenderTarget->setRenderPassDescriptor(m_textureRenderPassDescriptor);
968 m_textureRenderTarget->create();
969 }
970
971 if (!m_ssaaTextureToTextureRenderTarget && m_layer->antialiasingMode == QSSGRenderLayer::AAMode::SSAA) {
972 m_ssaaTextureToTextureRenderTarget = rhi->newTextureRenderTarget({ m_texture });
973 m_ssaaTextureToTextureRenderTarget->setName(QByteArrayLiteral("SSAA texture"));
974 m_ssaaTextureToTextureRenderPassDescriptor = m_ssaaTextureToTextureRenderTarget->newCompatibleRenderPassDescriptor();
975 m_ssaaTextureToTextureRenderTarget->setRenderPassDescriptor(m_ssaaTextureToTextureRenderPassDescriptor);
976 m_ssaaTextureToTextureRenderTarget->create();
977 }
978
979 if (m_layer->firstEffect) {
980 if (!m_effectSystem)
981 m_effectSystem = new QSSGRhiEffectSystem(m_sgContext);
982 m_effectSystem->setup(renderSize);
983 } else if (m_effectSystem) {
984 delete m_effectSystem;
985 m_effectSystem = nullptr;
986 }
987
988 if (timeBasedAA && !m_temporalAARenderTarget) {
989 m_temporalAARenderTarget = rhi->newTextureRenderTarget({ m_temporalAATexture });
990 m_temporalAARenderTarget->setName(QByteArrayLiteral("Temporal AA texture"));
991 m_temporalAARenderPassDescriptor = m_temporalAARenderTarget->newCompatibleRenderPassDescriptor();
992 m_temporalAARenderTarget->setRenderPassDescriptor(m_temporalAARenderPassDescriptor);
993 m_temporalAARenderTarget->create();
994 }
995
996 m_textureNeedsFlip = rhi->isYUpInFramebuffer();
997 m_aaIsDirty = false;
998 }
999
1000 if (m_renderStats)
1001 m_renderStats->endSync(dumpRenderTimes);
1002
1003 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DSynchronizeFrame, quint64(m_surfaceSize.width()) | quint64(m_surfaceSize.height()) << 32, profilingId);
1004}
1005
1007{
1008 if (fboNode)
1009 fboNode->invalidatePending = true;
1010}
1011
1013{
1014 if (m_layer && m_layer->renderData) {
1015 if (const auto &mgr = m_layer->renderData->getShadowMapManager())
1016 mgr->releaseCachedResources();
1017 if (const auto &mgr = m_layer->renderData->getReflectionMapManager())
1018 mgr->releaseCachedResources();
1019 }
1020}
1021
1023{
1024 if (!m_layer || !m_layer->renderedCamera)
1025 return std::nullopt;
1026
1027 const QVector2D viewportSize(m_surfaceSize.width(), m_surfaceSize.height());
1028 const QVector2D position(float(pos.x()), float(pos.y()));
1029 const QRectF viewportRect(QPointF{}, QSizeF(m_surfaceSize));
1030
1031 // First invert the y so we are dealing with numbers in a normal coordinate space.
1032 // Second, move into our layer's coordinate space
1033 QVector2D correctCoords(position.x(), viewportSize.y() - position.y());
1034 QVector2D theLocalMouse = toRectRelative(viewportRect, correctCoords);
1035 if ((theLocalMouse.x() < 0.0f || theLocalMouse.x() >= viewportSize.x() || theLocalMouse.y() < 0.0f
1036 || theLocalMouse.y() >= viewportSize.y()))
1037 return std::nullopt;
1038
1039 return m_layer->renderedCamera->unproject(theLocalMouse, viewportRect);
1040}
1041
1043{
1044 if (!m_layer)
1045 return QSSGRenderPickResult();
1046
1047 return m_sgContext->renderer()->syncPick(*m_layer,
1048 *m_sgContext->bufferManager(),
1049 ray);
1050}
1051
1053{
1054 if (!m_layer)
1055 return QSSGRenderPickResult();
1056
1057 return m_sgContext->renderer()->syncPick(*m_layer,
1058 *m_sgContext->bufferManager(),
1059 ray,
1060 node);
1061}
1062
1064{
1065 if (!m_layer)
1067
1068 return m_sgContext->renderer()->syncPickAll(*m_layer,
1069 *m_sgContext->bufferManager(),
1070 ray);
1071}
1072
1074{
1075 m_sgContext->renderer()->setGlobalPickingEnabled(isEnabled);
1076}
1077
1079{
1080 return m_renderStats;
1081}
1082
1083void QQuick3DRenderLayerHelpers::updateLayerNodeHelper(const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode, bool &aaIsDirty, bool &temporalIsDirty, float &ssaaMultiplier)
1084{
1085 QQuick3DSceneEnvironment *environment = view3D.environment();
1086
1088 if (aaMode != layerNode.antialiasingMode) {
1089 layerNode.antialiasingMode = aaMode;
1090 layerNode.progAAPassIndex = 0;
1091 aaIsDirty = true;
1092 }
1094 if (aaQuality != layerNode.antialiasingQuality) {
1095 layerNode.antialiasingQuality = aaQuality;
1096 ssaaMultiplier = (aaQuality == QSSGRenderLayer::AAQuality::Normal) ? 1.2f :
1097 (aaQuality == QSSGRenderLayer::AAQuality::High) ? 1.5f :
1098 2.0f;
1099 layerNode.ssaaMultiplier = ssaaMultiplier;
1100 aaIsDirty = true;
1101 }
1102
1103 bool temporalAAEnabled = environment->temporalAAEnabled();
1104 if (temporalAAEnabled != layerNode.temporalAAEnabled) {
1105 layerNode.temporalAAEnabled = environment->temporalAAEnabled();
1106 temporalIsDirty = true;
1107
1108 layerNode.tempAAPassIndex = 0;
1109 aaIsDirty = true;
1110 }
1111 layerNode.ssaaEnabled = environment->antialiasingMode()
1113
1114 layerNode.temporalAAStrength = environment->temporalAAStrength();
1115
1116 layerNode.specularAAEnabled = environment->specularAAEnabled();
1117
1118 layerNode.background = QSSGRenderLayer::Background(environment->backgroundMode());
1119 layerNode.clearColor = QVector3D(float(environment->clearColor().redF()),
1120 float(environment->clearColor().greenF()),
1121 float(environment->clearColor().blueF()));
1122
1123 layerNode.gridEnabled = environment->gridEnabled();
1124 layerNode.gridScale = environment->gridScale();
1125 layerNode.gridFlags = environment->gridFlags();
1126
1127 layerNode.aoStrength = environment->aoStrength();
1128 layerNode.aoDistance = environment->aoDistance();
1129 layerNode.aoSoftness = environment->aoSoftness();
1130 layerNode.aoEnabled = environment->aoEnabled();
1131 layerNode.aoBias = environment->aoBias();
1132 layerNode.aoSamplerate = environment->aoSampleRate();
1133 layerNode.aoDither = environment->aoDither();
1134
1135 // ### These images will not be registered anywhere
1136 if (environment->lightProbe())
1137 layerNode.lightProbe = environment->lightProbe()->getRenderImage();
1138 else
1139 layerNode.lightProbe = nullptr;
1140 if (view3D.environment()->skyBoxCubeMap())
1141 layerNode.skyBoxCubeMap = view3D.environment()->skyBoxCubeMap()->getRenderImage();
1142 else
1143 layerNode.skyBoxCubeMap = nullptr;
1144
1145 layerNode.probeExposure = environment->probeExposure();
1146 // Remap the probeHorizon to the expected Range
1147 layerNode.probeHorizon = qMin(environment->probeHorizon() - 1.0f, -0.001f);
1148 layerNode.setProbeOrientation(environment->probeOrientation());
1149
1150 if (view3D.camera())
1151 layerNode.explicitCamera = static_cast<QSSGRenderCamera *>(QQuick3DObjectPrivate::get(view3D.camera())->spatialNode);
1152 else
1153 layerNode.explicitCamera = nullptr;
1154
1157
1158 layerNode.tonemapMode = QQuick3DSceneRenderer::getTonemapMode(*environment);
1159 layerNode.skyboxBlurAmount = environment->skyboxBlurAmount();
1160 if (auto debugSettings = view3D.environment()->debugSettings()) {
1161 layerNode.debugMode = QSSGRenderLayer::MaterialDebugMode(debugSettings->materialOverride());
1162 layerNode.wireframeMode = debugSettings->wireframeEnabled();
1163 } else {
1165 layerNode.wireframeMode = false;
1166 }
1167
1168 if (environment->lightmapper()) {
1169 QQuick3DLightmapper *lightmapper = environment->lightmapper();
1170 layerNode.lmOptions.opacityThreshold = lightmapper->opacityThreshold();
1171 layerNode.lmOptions.bias = lightmapper->bias();
1172 layerNode.lmOptions.useAdaptiveBias = lightmapper->isAdaptiveBiasEnabled();
1173 layerNode.lmOptions.indirectLightEnabled = lightmapper->isIndirectLightEnabled();
1174 layerNode.lmOptions.indirectLightSamples = lightmapper->samples();
1176 layerNode.lmOptions.indirectLightBounces = lightmapper->bounces();
1177 layerNode.lmOptions.indirectLightFactor = lightmapper->indirectLightFactor();
1178 } else {
1179 layerNode.lmOptions = {};
1180 }
1181
1182 if (environment->fog() && environment->fog()->isEnabled()) {
1183 layerNode.fog.enabled = true;
1184 const QQuick3DFog *fog = environment->fog();
1185 layerNode.fog.color = color::sRGBToLinear(fog->color()).toVector3D();
1186 layerNode.fog.density = fog->density();
1187 layerNode.fog.depthEnabled = fog->isDepthEnabled();
1188 layerNode.fog.depthBegin = fog->depthNear();
1189 layerNode.fog.depthEnd = fog->depthFar();
1190 layerNode.fog.depthCurve = fog->depthCurve();
1191 layerNode.fog.heightEnabled = fog->isHeightEnabled();
1192 layerNode.fog.heightMin = fog->leastIntenseY();
1193 layerNode.fog.heightMax = fog->mostIntenseY();
1194 layerNode.fog.heightCurve = fog->heightCurve();
1195 layerNode.fog.transmitEnabled = fog->isTransmitEnabled();
1196 layerNode.fog.transmitCurve = fog->transmitCurve();
1197 } else {
1198 layerNode.fog.enabled = false;
1199 }
1200}
1201
1202void QQuick3DSceneRenderer::updateLayerNode(QQuick3DViewport *view3D, const QList<QSSGRenderGraphObject *> &resourceLoaders)
1203{
1204 QSSGRenderLayer *layerNode = m_layer;
1205
1206 bool temporalIsDirty = false;
1207 QQuick3DRenderLayerHelpers::updateLayerNodeHelper(*view3D, *m_layer, m_aaIsDirty, temporalIsDirty, m_ssaaMultiplier);
1208
1209 int extraFramesToRender = 0;
1210
1212 // with progressive AA, we need a number of extra frames after the last dirty one
1213 // if we always reset requestedFramesCount when dirty, we will get the extra frames eventually
1214 extraFramesToRender = int(layerNode->antialiasingQuality);
1215
1216 // RHI: +1 since we need a normal frame to start with, and we're not copying that from the screen
1217 if (m_sgContext->rhiContext()->isValid())
1218 extraFramesToRender += 1;
1219 } else if (layerNode->temporalAAEnabled) {
1220 // When temporalAA is on and antialiasing mode changes,
1221 // layer needs to be re-rendered (at least) MAX_TEMPORAL_AA_LEVELS times
1222 // to generate temporal antialiasing.
1223 // Also, we need to do an extra render when animation stops
1224 extraFramesToRender = (m_aaIsDirty || temporalIsDirty) ? QSSGLayerRenderData::MAX_TEMPORAL_AA_LEVELS : 1;
1225 }
1226
1227 requestedFramesCount = extraFramesToRender;
1228 // Effects need to be rendered in reverse order as described in the file.
1229 layerNode->firstEffect = nullptr; // We reset the linked list
1230 const auto &effects = view3D->environment()->effectList();
1231 auto rit = effects.crbegin();
1232 const auto rend = effects.crend();
1233 for (; rit != rend; ++rit) {
1235 QSSGRenderEffect *effectNode = static_cast<QSSGRenderEffect *>(p->spatialNode);
1236 if (effectNode) {
1237 if (layerNode->hasEffect(effectNode)) {
1238 qWarning() << "Duplicate effect found, skipping!";
1239 } else {
1240 effectNode->className = (*rit)->metaObject()->className(); //### persistent, but still icky to store a const char* returned from a function
1241 layerNode->addEffect(*effectNode);
1242 }
1243 }
1244 }
1245
1246 // Now that we have the effect list used for rendering, finalize the shader
1247 // code based on the layer (scene.env.) settings.
1248 for (QSSGRenderEffect *effectNode = layerNode->firstEffect; effectNode; effectNode = effectNode->m_nextEffect)
1249 effectNode->finalizeShaders(*layerNode, m_sgContext.get());
1250
1251 // ResourceLoaders
1252 layerNode->resourceLoaders.clear();
1253 layerNode->resourceLoaders = resourceLoaders;
1254}
1255
1256void QQuick3DSceneRenderer::removeNodeFromLayer(QSSGRenderNode *node)
1257{
1258 if (!m_layer)
1259 return;
1260
1261 m_layer->removeChild(*node);
1262}
1263
1264void QQuick3DSceneRenderer::addNodeToLayer(QSSGRenderNode *node)
1265{
1266 if (!m_layer)
1267 return;
1268
1269 m_layer->addChild(*node);
1270}
1271
1272QSGRenderNode::StateFlags QQuick3DSGRenderNode::changedStates() const
1273{
1275}
1276
1277namespace {
1278inline QRect convertQtRectToGLViewport(const QRectF &rect, const QSize surfaceSize)
1279{
1280 const int x = int(rect.x());
1281 const int y = surfaceSize.height() - (int(rect.y()) + int(rect.height()));
1282 const int width = int(rect.width());
1283 const int height = int(rect.height());
1284 return QRect(x, y, width, height);
1285}
1286
1287inline void queryMainRenderPassDescriptorAndCommandBuffer(QQuickWindow *window, QSSGRhiContext *rhiCtx)
1288{
1289 if (rhiCtx->isValid()) {
1290 // Query from the rif because that is available in the sync
1291 // phase (updatePaintNode) already. QSGDefaultRenderContext's
1292 // copies of the rp and cb are not there until the render
1293 // phase of the scenegraph.
1294 int sampleCount = 1;
1295 QRhiSwapChain *swapchain = window->swapChain();
1296 if (swapchain) {
1298 rhiCtx->setCommandBuffer(swapchain->currentFrameCommandBuffer());
1299 rhiCtx->setRenderTarget(swapchain->currentFrameRenderTarget());
1300 sampleCount = swapchain->sampleCount();
1301 } else {
1302 QSGRendererInterface *rif = window->rendererInterface();
1303 // no swapchain when using a QQuickRenderControl (redirecting to a texture etc.)
1304 QRhiCommandBuffer *cb = static_cast<QRhiCommandBuffer *>(
1308 if (cb && rt) {
1310 rhiCtx->setCommandBuffer(cb);
1311 rhiCtx->setRenderTarget(rt);
1313 if (color0 && color0->texture())
1314 sampleCount = color0->texture()->sampleCount();
1315 } else {
1316 qWarning("Neither swapchain nor redirected command buffer and render target are available.");
1317 }
1318 }
1319
1320 // MSAA is out of our control on this path: it is up to the
1321 // QQuickWindow and the scenegraph to set up the swapchain based on the
1322 // QSurfaceFormat's samples(). The only thing we need to do here is to
1323 // pass the sample count to the renderer because it is needed when
1324 // creating graphics pipelines.
1325 rhiCtx->setMainPassSampleCount(sampleCount);
1326 }
1327}
1328
1329// The alternative to queryMainRenderPassDescriptorAndCommandBuffer()
1330// specifically for the Inline render mode when there is a QSGRenderNode.
1331inline void queryInlineRenderPassDescriptorAndCommandBuffer(QSGRenderNode *node, QSSGRhiContext *rhiCtx)
1332{
1334 rhiCtx->setMainRenderPassDescriptor(d->m_rt.rpDesc);
1335 rhiCtx->setCommandBuffer(d->m_rt.cb);
1336 rhiCtx->setRenderTarget(d->m_rt.rt);
1337 rhiCtx->setMainPassSampleCount(d->m_rt.rt->sampleCount());
1338}
1339}
1340
1342{
1343 delete renderer;
1344}
1345
1347{
1348 // this is outside the main renderpass
1349
1350 if (!renderer->m_sgContext->rhiContext()->isValid())
1351 return;
1352 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1353
1354 queryInlineRenderPassDescriptorAndCommandBuffer(this, renderer->m_sgContext->rhiContext().get());
1355
1356 qreal dpr = window->devicePixelRatio();
1357 const QSizeF itemSize = renderer->surfaceSize() / dpr;
1358 QRectF viewport = matrix()->mapRect(QRectF(QPoint(0, 0), itemSize));
1359 viewport = QRectF(viewport.topLeft() * dpr, viewport.size() * dpr);
1360 const QRect vp = convertQtRectToGLViewport(viewport, window->size() * dpr);
1361
1362 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1363
1365 renderer->rhiPrepare(vp, dpr);
1366 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, renderer->profilingId);
1367}
1368
1370{
1371 Q_UNUSED(state);
1372
1373 if (renderer->m_sgContext->rhiContext()->isValid()) {
1374 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1375 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1376
1377 queryInlineRenderPassDescriptorAndCommandBuffer(this, renderer->m_sgContext->rhiContext().get());
1378
1380 renderer->endFrame();
1381 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1382 STAT_PAYLOAD(renderer->m_sgContext->rhiContext()->stats()), renderer->profilingId);
1383 }
1384}
1385
1387{
1388}
1389
1390QSGRenderNode::RenderingFlags QQuick3DSGRenderNode::flags() const
1391{
1392 // don't want begin/endExternal() to be called by Quick
1393 return NoExternalRendering;
1394}
1395
1397 : m_renderer(renderer)
1398 , m_window(window)
1399 , m_mode(mode)
1400{
1401 if (QSGRendererInterface::isApiRhiBased(window->rendererInterface()->graphicsApi())) {
1402 connect(window, &QQuickWindow::beforeRendering, this, &QQuick3DSGDirectRenderer::prepare, Qt::DirectConnection);
1403 if (mode == Underlay)
1404 connect(window, &QQuickWindow::beforeRenderPassRecording, this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1405 else
1406 connect(window, &QQuickWindow::afterRenderPassRecording, this, &QQuick3DSGDirectRenderer::render, Qt::DirectConnection);
1407 }
1408}
1409
1411{
1412 delete m_renderer;
1413}
1414
1416{
1417 m_viewport = viewport;
1418}
1419
1421{
1422 if (m_isVisible == visible)
1423 return;
1424 m_isVisible = visible;
1425 m_window->update();
1426}
1427
1429{
1430 renderPending = true;
1431 requestFullUpdate(m_window);
1432}
1433
1434void QQuick3DSGDirectRenderer::prepare()
1435{
1436 if (!m_isVisible || !m_renderer)
1437 return;
1438
1439 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1440 // this is outside the main renderpass
1441 if (m_renderer->m_postProcessingStack) {
1442 if (renderPending) {
1443 renderPending = false;
1444 m_rhiTexture = m_renderer->renderToRhiTexture(m_window);
1445 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1446 auto quadRenderer = m_renderer->m_sgContext->renderer()->rhiQuadRenderer();
1447 quadRenderer->prepareQuad(m_renderer->m_sgContext->rhiContext().get(), nullptr);
1448 if (m_renderer->m_sgContext->renderer()->rendererRequestsFrames()
1449 || m_renderer->requestedFramesCount > 0) {
1450 requestRender();
1451 if (m_renderer->requestedFramesCount > 0)
1452 m_renderer->requestedFramesCount--;
1453 }
1454 }
1455 }
1456 else
1457 {
1458 QQuick3DRenderStats *renderStats = m_renderer->renderStats();
1459 if (renderStats) {
1460 renderStats->startRender();
1461 renderStats->startRenderPrepare();
1462 }
1463
1464 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DPrepareFrame);
1465 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1466 const QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->devicePixelRatio());
1467
1468 Q_TRACE_SCOPE(QSSG_prepareFrame, vp.width(), vp.height());
1469 m_renderer->beginFrame();
1470 m_renderer->rhiPrepare(vp, m_window->devicePixelRatio());
1471 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DPrepareFrame, quint64(vp.width()) | quint64(vp.height()) << 32, m_renderer->profilingId);
1472
1473 if (renderStats)
1474 renderStats->endRenderPrepare();
1475 }
1476 }
1477}
1478
1479void QQuick3DSGDirectRenderer::render()
1480{
1481 if (!m_isVisible || !m_renderer)
1482 return;
1483
1484 if (m_renderer->m_sgContext->rhiContext()->isValid()) {
1485 // the command buffer is recording the main renderpass at this point
1486
1487 // No m_window->beginExternalCommands() must be done here. When the
1488 // renderer is using the same
1489 // QRhi/QRhiCommandBuffer/QRhiRenderPassDescriptor as the Qt Quick
1490 // scenegraph, there is no difference from the RHI's perspective. There are
1491 // no external (native) commands here.
1492
1493 // Requery the command buffer and co. since Offscreen mode View3Ds may
1494 // have altered these on the context.
1495 if (m_renderer->m_postProcessingStack) {
1496 if (m_rhiTexture) {
1497 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1498 auto rhiCtx = m_renderer->m_sgContext->rhiContext().get();
1499 const auto &renderer = m_renderer->m_sgContext->renderer();
1500
1501 // Instead of passing in a flip flag we choose to rely on qsb's
1502 // per-target compilation mode in the fragment shader. (it does UV
1503 // flipping based on QSHADER_ macros) This is just better for
1504 // performance and the shaders are very simple so introducing a
1505 // uniform block and branching dynamically would be an overkill.
1506 QRect vp = convertQtRectToGLViewport(m_viewport, m_window->size() * m_window->devicePixelRatio());
1507
1508 const auto &shaderPipeline = renderer->getRhiSimpleQuadShader();
1509
1514 QRhiShaderResourceBindings *srb = rhiCtx->srb(bindings);
1515
1517 ps.viewport = QRhiViewport(float(vp.x()), float(vp.y()), float(vp.width()), float(vp.height()));
1518 ps.shaderPipeline = shaderPipeline.get();
1519 renderer->rhiQuadRenderer()->recordRenderQuad(rhiCtx, &ps, srb, rhiCtx->mainRenderPassDescriptor(), QSSGRhiQuadRenderer::UvCoords | QSSGRhiQuadRenderer::PremulBlend);
1520 }
1521 }
1522 else
1523 {
1524 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderFrame);
1525 Q_TRACE_SCOPE(QSSG_renderFrame, 0, 0);
1526
1527 queryMainRenderPassDescriptorAndCommandBuffer(m_window, m_renderer->m_sgContext->rhiContext().get());
1528
1529 m_renderer->rhiRender();
1530 m_renderer->endFrame();
1531
1532 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DRenderFrame,
1533 STAT_PAYLOAD(m_renderer->m_sgContext->rhiContext()->stats()),
1534 m_renderer->profilingId);
1535
1536 if (m_renderer->renderStats())
1537 m_renderer->renderStats()->endRender(dumpRenderTimes);
1538 }
1539 }
1540}
1541
QSSGRhiRenderableTexture rhiDepthTexture
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
Definition qlist.h:74
bool isEmpty() const noexcept
Definition qlist.h:390
T & last()
Definition qlist.h:631
void push_back(parameter_type t)
Definition qlist.h:672
const_iterator cend() const noexcept
Definition qlist.h:614
const_iterator cbegin() const noexcept
Definition qlist.h:613
void clear()
Definition qlist.h:417
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:90
QObject * parent() const
Returns a pointer to the parent object.
Definition qobject.h:311
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
\inmodule QtCore\reentrant
Definition qpoint.h:214
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore
Definition qqueue.h:14
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
QPointer< QQuick3DSceneManager > sceneManager
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
QSSGRenderGraphObject * spatialNode
QQuick3DObject * parent
\qmlproperty Object3D QtQuick3D::Object3D::parent This property holds the parent of the Object3D in a...
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
QPointer< QQuick3DWindowAttachment > wattached
static QQuick3DWindowAttachment * getOrSetWindowAttachment(QQuickWindow &window)
QSSGRenderPickResult syncPickOne(const QSSGRenderRay &ray, QSSGRenderNode *node)
QRhiTexture * renderToRhiTexture(QQuickWindow *qw)
QQuick3DSceneRenderer(const std::shared_ptr< QSSGRenderContextInterface > &rci)
void rhiPrepare(const QRect &viewport, qreal displayPixelRatio)
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()
QSSGRenderPickResult syncPick(const QSSGRenderRay &ray)
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:483
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:238
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
Definition qrect.h:184
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:241
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
Definition qrect.h:187
\inmodule QtGui
Definition qrhi.h:834
@ Dynamic
Definition qrhi.h:839
@ UniformBuffer
Definition qrhi.h:845
virtual bool create()=0
Creates the corresponding native graphics resources.
\inmodule QtGui
Definition qrhi.h:568
void setRenderBuffer(QRhiRenderBuffer *rb)
Sets the renderbuffer rb.
Definition qrhi.h:578
void setResolveTexture(QRhiTexture *tex)
Sets the resolve texture tex.
Definition qrhi.h:587
\inmodule QtGui
Definition qrhi.h:1614
void setPixelSize(const QSize &sz)
Sets the size (in pixels) to sz.
Definition qrhi.h:1093
int sampleCount() const
Definition qrhi.h:1095
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:1142
QRhiRenderPassDescriptor * renderPassDescriptor() const
Definition qrhi.h:1141
\inmodule QtGui
Definition qrhi.h:1694
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:8595
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:8718
void setName(const QByteArray &name)
Sets a name for the object.
Definition qrhi.cpp:3455
\inmodule QtGui
Definition qrhi.h:1007
@ ClampToEdge
Definition qrhi.h:1017
\inmodule QtGui
Definition qrhi.h:1190
\inmodule QtGui
Definition qrhi.h:1513
int sampleCount() const
Definition qrhi.h:1553
virtual QRhiRenderTarget * currentFrameRenderTarget()=0
QRhiRenderPassDescriptor * renderPassDescriptor() const
Definition qrhi.h:1556
virtual QRhiCommandBuffer * currentFrameCommandBuffer()=0
const QRhiColorAttachment * cbeginColorAttachments() const
Definition qrhi.h:626
void setDepthStencilBuffer(QRhiRenderBuffer *renderBuffer)
Sets the renderBuffer for depth-stencil.
Definition qrhi.h:632
void setColorAttachments(std::initializer_list< QRhiColorAttachment > list)
Sets the list of color attachments.
Definition qrhi.h:619
\inmodule QtGui
Definition qrhi.h:1161
virtual QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor()=0
virtual bool create()=0
Creates the corresponding native graphics resources.
QRhiTextureRenderTargetDescription description() const
Definition qrhi.h:1171
\inmodule QtGui
Definition qrhi.h:883
Format format() const
Definition qrhi.h:960
void setFormat(Format fmt)
Sets the requested texture format to fmt.
Definition qrhi.h:961
@ UsedAsTransferSource
Definition qrhi.h:890
@ RenderTarget
Definition qrhi.h:886
virtual bool create()=0
Creates the corresponding native graphics resources.
Format
Specifies the texture format.
Definition qrhi.h:902
@ RGBA32F
Definition qrhi.h:914
@ RGBA16F
Definition qrhi.h:913
QSize pixelSize() const
Definition qrhi.h:963
void setPixelSize(const QSize &sz)
Sets the texture size, specified in pixels, to sz.
Definition qrhi.h:964
\inmodule QtGui
Definition qrhi.h:85
\inmodule QtGui
Definition qrhi.h:1767
QRhiBuffer * newBuffer(QRhiBuffer::Type type, QRhiBuffer::UsageFlags usage, quint32 size)
Definition qrhi.cpp:10079
bool isYUpInFramebuffer() const
Definition qrhi.cpp:9601
bool isFeatureSupported(QRhi::Feature feature) const
Definition qrhi.cpp:9681
QList< int > supportedSampleCounts() const
Definition qrhi.cpp:10516
QRhiRenderBuffer * newRenderBuffer(QRhiRenderBuffer::Type type, const QSize &pixelSize, int sampleCount=1, QRhiRenderBuffer::Flags flags={}, QRhiTexture::Format backingFormatHint=QRhiTexture::UnknownFormat)
Definition qrhi.cpp:10106
Implementation backend() const
Definition qrhi.cpp:8289
@ Metal
Definition qrhi.h:1774
QRhiTextureRenderTarget * newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags={})
Definition qrhi.cpp:10245
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10133
@ MultisampleRenderBuffer
Definition qrhi.h:1795
QRhiResourceUpdateBatch * nextResourceUpdateBatch()
Definition qrhi.cpp:8854
@ 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:622
void setFlag(Flag, bool=true)
Sets the flag f on this node if enabled is true; otherwise clears the flag.
Definition qsgnode.cpp:584
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)
virtual void * getResource(QQuickWindow *window, Resource resource) const
Queries a graphics resource in window.
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
QSSGRenderCamera * camera
const QSSGRenderShadowMapPtr & getShadowMapManager() const
std::function< void(BakingStatus, std::optional< QString >, BakingControl *)> Callback
QSSGRenderLayer * layerKey
void cleanupLayerInfo(QSSGRenderLayer *layer)
QHash< QSSGRenderLayer *, PerLayerInfo > perLayerInfo
static quint64 totalDrawCallCountForPass(const QSSGRhiContextStats::RenderPassInfo &pass)
void setMainPassSampleCount(int samples)
bool isValid() const
void setMainRenderPassDescriptor(QRhiRenderPassDescriptor *rpDesc)
QRhiCommandBuffer * commandBuffer() const
static QRhiCommandBuffer::BeginPassFlags commonPassFlags()
QSSGRhiDrawCallData & drawCallData(const QSSGRhiDrawCallDataKey &key)
QSSGRhiContextStats & stats()
QRhiShaderResourceBindings * srb(const QSSGRhiShaderResourceBindingList &bindings)
QRhi * rhi() const
QRhiSampler * sampler(const QSSGRhiSamplerDescription &samplerDescription)
void setRenderTarget(QRhiRenderTarget *rt)
QRhiRenderPassDescriptor * mainRenderPassDescriptor() const
void setCommandBuffer(QRhiCommandBuffer *cb)
QRhiTexture * process(const QSSGRenderEffect &firstEffect, QRhiTexture *inTexture, QRhiTexture *inDepthTexture, QVector2D cameraClipRange)
void setup(QSize outputSize)
static QSSGRenderTextureFormat::Format overriddenOutputFormat(const QSSGRenderEffect *inEffect)
Definition qset.h:18
QList< T > values() const
Definition qset.h:297
\inmodule QtCore
Definition qsize.h:207
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
static QThread * currentThread()
Definition qthread.cpp:966
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.
QSet< QString >::iterator it
rect
[4]
else opt state
[0]
Q_QUICK3D_EXPORT void updateLayerNodeHelper(const QQuick3DViewport &view3D, QSSGRenderLayer &layerNode, bool &aaIsDirty, bool &temporalIsDirty, float &ssaaMultiplier)
QVector3D tonemapFilmic(const QVector3D &c)
QVector3D tonemapHejlDawson(const QVector3D &c)
QVector3D tonemapAces(const QVector3D &c)
QVector3D tonemapLinearToSrgb(const QVector3D &c)
Combined button and popup list for selecting options.
@ transparent
Definition qnamespace.h:46
@ black
Definition qnamespace.h:29
@ color0
Definition qnamespace.h:27
@ DirectConnection
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:287
#define qWarning
Definition qlogging.h:162
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 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:639
#define QSSG_ASSERT(cond, action)
QVector2D toRectRelative(const QRectF &r, const QVector2D &absoluteCoordinates)
#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:45
unsigned long long quint64
Definition qtypes.h:56
unsigned int uint
Definition qtypes.h:29
double qreal
Definition qtypes.h:92
static bool isEmbedded(const QWindow *w)
Definition qwidget.cpp:6637
QList< int > list
[14]
QFileInfo info(fileName)
[8]
QObject::connect nullptr
QQueue< int > queue
[0]
view viewport() -> scroll(dx, dy, deviceRect)
aWidget window() -> setWindowTitle("New Window Title")
[2]
QSvgRenderer * renderer
[0]
bool contains(const AT &t) const noexcept
Definition qlist.h:44
QSSGRenderRay unproject(const QVector2D &inLayerRelativeMouseCoords, const QRectF &inViewport) const
void finalizeShaders(const QSSGRenderLayer &layer, QSSGRenderContextInterface *renderContext)
QSSGRenderEffect * m_nextEffect
static constexpr bool isExtension(Type type) noexcept
QSSGRenderCamera * explicitCamera
QSSGLightmapperOptions lmOptions
void addEffect(QSSGRenderEffect &inEffect)
QSSGRenderCamera * renderedCamera
struct QSSGRenderLayer::FogOptions fog
QSSGRenderImage * skyBoxCubeMap
@ EnableDepthPrePass
True when we render a depth pass before.
QVector< QSSGRenderGraphObject * > resourceLoaders
QSSGRenderImage * lightProbe
void setProbeOrientation(const QVector3D &angles)
QSSGRenderLayer::AAMode antialiasingMode
MaterialDebugMode debugMode
QSSGLayerRenderData * renderData
QSSGRenderLayer::Background background
TonemapMode tonemapMode
QSSGRenderLayer::AAQuality antialiasingQuality
void removeImportScene(QSSGRenderNode &rootNode)
bool hasEffect(QSSGRenderEffect *inEffect) const
QList< QSSGRenderExtension * > renderExtensions[RenderExtensionMode::Count]
void setImportScene(QSSGRenderNode &rootNode)
QSSGRenderEffect * firstEffect
void addChild(QSSGRenderNode &inChild)
void removeChild(QSSGRenderNode &inChild)
const QSSGRhiShaderPipeline * shaderPipeline
void addUniformBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset, int size)
void addTexture(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)