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
qssgrenderer.cpp
Go to the documentation of this file.
1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2019 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#include "qssgrenderer_p.h"
6
7#include <QtQuick3DRuntimeRender/private/qssgrenderitem2d_p.h>
9#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
10#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
11#include <QtQuick3DRuntimeRender/private/qssgrenderimage_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
14#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
15#include <QtQuick3DRuntimeRender/private/qssgrhicustommaterialsystem_p.h>
16#include <QtQuick3DRuntimeRender/private/qssgrendershadercodegenerator_p.h>
17#include <QtQuick3DRuntimeRender/private/qssgrenderdefaultmaterialshadergenerator_p.h>
18#include <QtQuick3DRuntimeRender/private/qssgperframeallocator_p.h>
19#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
20#include <QtQuick3DRuntimeRender/private/qssgrendertexturedata_p.h>
21#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
22#include <QtQuick3DRuntimeRender/private/qssgrhiparticles_p.h>
23#include <QtQuick3DRuntimeRender/private/qssgvertexpipelineimpl_p.h>
26
27#include <QtQuick3DUtils/private/qquick3dprofiler_p.h>
28#include <QtQuick3DUtils/private/qssgdataref_p.h>
29#include <QtQuick3DUtils/private/qssgutils_p.h>
30#include <QtQuick3DUtils/private/qssgassert_p.h>
31#include <qtquick3d_tracepoints_p.h>
32
33#include <QtCore/QMutexLocker>
34#include <QtCore/QBitArray>
35
36#include <cstdlib>
37#include <algorithm>
38#include <limits>
39
40/*
41 Rendering is done is several steps, these are:
42
43 1. \l{QSSGRenderer::beginFrame(){beginFrame()} - set's up the renderer to start a new frame.
44
45 2. Now that the renderer is reset, values for the \l{QSSGRenderer::setViewport}{viewport}, \l{QSSGRenderer::setDpr}{dpr},
46 \l{QSSGRenderer::setScissorRect}{scissorRect} etc. should be updated.
47
48 3. \l{QSSGRenderer::prepareLayerForRender()} - At this stage the scene tree will be traversed
49 and state for the renderer needed to render gets collected. This includes, but is not limited to,
50 calculating global transforms, loading of meshes, preparing materials and setting up the rendering
51 steps needed for the frame (opaque and transparent pass etc.)
52 If the there are custom \l{QQuick3DRenderExtension}{render extensions} added to to \l{View3D::extensions}{View3D}
53 then they will get their first chance to modify or react to the collected data here.
54 If the users have implemented the virtual function \l{QSSGRenderExtension::prepareData()}{prepareData} it will be
55 called after all active nodes have been collected and had their global data updated, but before any mesh or material
56 has been loaded.
57
58 4. \l{QSSGRenderer::rhiPrepare()} - Starts rendering necessary sub-scenes and prepare resources.
59 Sub-scenes, or sub-passes that are to be done in full, will be done at this stage.
60
61 5. \l{QSSGRenderer::rhiRender()} - Renders the scene to the main target.
62
63 6. \l{QSSGRenderer::endFrame()} - Marks the frame as done and cleans-up dirty states and
64 uneeded resources.
65*/
66
68
71
72void QSSGRenderer::releaseCachedResources()
73{
74 m_rhiQuadRenderer.reset();
75 m_rhiCubeRenderer.reset();
76}
77
79
81{
82 m_contextInterface = nullptr;
83 releaseCachedResources();
84}
85
86void QSSGRenderer::cleanupUnreferencedBuffers(QSSGRenderLayer *inLayer)
87{
88 // Now check for unreferenced buffers and release them if necessary
89 m_contextInterface->bufferManager()->cleanupUnreferencedBuffers(m_frameCount, inLayer);
90}
91
92void QSSGRenderer::resetResourceCounters(QSSGRenderLayer *inLayer)
93{
94 m_contextInterface->bufferManager()->resetUsageCounters(m_frameCount, inLayer);
95}
96
98{
99 QSSGLayerRenderData *theRenderData = getOrCreateLayerRenderData(inLayer);
100 Q_ASSERT(theRenderData);
101 beginLayerRender(*theRenderData);
102 theRenderData->resetForFrame();
103 theRenderData->prepareForRender();
104 endLayerRender();
105 return theRenderData->layerPrepResult.flags.wasDirty();
106}
107
108// Phase 1: prepare. Called when the renderpass is not yet started on the command buffer.
110{
111 QSSGLayerRenderData *theRenderData = getOrCreateLayerRenderData(inLayer);
112 QSSG_ASSERT(theRenderData && !theRenderData->renderedCameras.isEmpty(), return);
113
114 const auto layerPrepResult = theRenderData->layerPrepResult;
115 if (layerPrepResult.isLayerVisible()) {
117 QSSGRhiContext *rhiCtx = contextInterface()->rhiContext().get();
118 QSSG_ASSERT(rhiCtx->isValid() && rhiCtx->rhi()->isRecordingFrame(), return);
119 theRenderData->maybeBakeLightmap();
120 beginLayerRender(*theRenderData);
121 // Process active passes. "PreMain" passes are individual passes
122 // that does can and should be done in the rhi prepare phase.
123 // It is assumed that passes are sorted in the list with regards to
124 // execution order.
125 const auto &activePasses = theRenderData->activePasses;
126 for (const auto &pass : activePasses) {
127 pass->renderPrep(*this, *theRenderData);
128 if (pass->passType() == QSSGRenderPass::Type::Standalone)
129 pass->renderPass(*this);
130 }
131
132 endLayerRender();
133 }
134}
135
136// Phase 2: render. Called within an active renderpass on the command buffer.
138{
139 QSSGLayerRenderData *theRenderData = getOrCreateLayerRenderData(inLayer);
140 QSSG_ASSERT(theRenderData && !theRenderData->renderedCameras.isEmpty(), return);
141 if (theRenderData->layerPrepResult.isLayerVisible()) {
142 beginLayerRender(*theRenderData);
143 const auto &activePasses = theRenderData->activePasses;
144 for (const auto &pass : activePasses) {
145 if (pass->passType() == QSSGRenderPass::Type::Main || pass->passType() == QSSGRenderPass::Type::Extension)
146 pass->renderPass(*this);
147 }
148 endLayerRender();
149 }
150}
151
152template<typename Container>
153static void cleanupResourcesImpl(const QSSGRenderContextInterface &rci, const Container &resources)
154{
155 const auto &rhiCtx = rci.rhiContext();
156 if (!rhiCtx->isValid())
157 return;
158
159 const auto &bufferManager = rci.bufferManager();
160
161 for (const auto &resource : resources) {
162 if (resource->type == QSSGRenderGraphObject::Type::Geometry) {
163 auto geometry = static_cast<QSSGRenderGeometry*>(resource);
164 bufferManager->releaseGeometry(geometry);
165 } else if (resource->type == QSSGRenderGraphObject::Type::Model) {
166 auto model = static_cast<QSSGRenderModel*>(resource);
167 QSSGRhiContextPrivate::get(rhiCtx.get())->cleanupDrawCallData(model);
168 } else if (resource->type == QSSGRenderGraphObject::Type::TextureData) {
169 auto textureData = static_cast<QSSGRenderTextureData *>(resource);
170 bufferManager->releaseTextureData(textureData);
171 } else if (resource->type == QSSGRenderGraphObject::Type::RenderExtension) {
172 auto *rext = static_cast<QSSGRenderExtension *>(resource);
173 bufferManager->releaseExtensionResult(*rext);
174 }
175
176 // ### There might be more types that need to be supported
177
178 delete resource;
179 }
180}
181
182void QSSGRenderer::cleanupResources(QList<QSSGRenderGraphObject *> &resources)
183{
184 cleanupResourcesImpl(*m_contextInterface, resources);
185 resources.clear();
186}
187
188void QSSGRenderer::cleanupResources(QSet<QSSGRenderGraphObject *> &resources)
189{
190 cleanupResourcesImpl(*m_contextInterface, resources);
191 resources.clear();
192}
193
194QSSGLayerRenderData *QSSGRenderer::getOrCreateLayerRenderData(QSSGRenderLayer &layer)
195{
196 if (layer.renderData == nullptr)
197 layer.renderData = new QSSGLayerRenderData(layer, *this);
198
199 return layer.renderData;
200}
201
202void QSSGRenderer::addMaterialDirtyClear(QSSGRenderGraphObject *material)
203{
204 m_materialClearDirty.insert(material);
205}
206
207static QByteArray logPrefix() { return QByteArrayLiteral("mesh default material pipeline-- "); }
208
209
211 QSSGShaderLibraryManager &shaderLibraryManager,
212 QSSGShaderCache &shaderCache,
213 QSSGProgramGenerator &shaderProgramGenerator,
214 const QSSGShaderDefaultMaterialKeyProperties &shaderKeyProperties,
215 const QSSGShaderFeatures &featureSet,
216 QByteArray &shaderString)
217{
218 shaderString = logPrefix();
219 QSSGShaderDefaultMaterialKey theKey(renderable.shaderDescription);
220
221 // This is not a cheap operation. This function assumes that it will not be
222 // hit for every material for every model in every frame (except of course
223 // for materials that got changed). In practice this is ensured by the
224 // cheaper-to-lookup cache in getShaderPipelineForDefaultMaterial().
225 theKey.toString(shaderString, shaderKeyProperties);
226
227 // Check the in-memory, per-QSSGShaderCache (and so per-QQuickWindow)
228 // runtime cache. That may get cleared upon an explicit call to
229 // QQuickWindow::releaseResources(), but will otherwise store all
230 // encountered shader pipelines in any View3D in the window.
231 if (const auto &maybePipeline = shaderCache.tryGetRhiShaderPipeline(shaderString, featureSet))
232 return maybePipeline;
233
234 // Check if there's a pre-built (offline generated) shader for available.
235 const QByteArray qsbcKey = QQsbCollection::EntryDesc::generateSha(shaderString, QQsbCollection::toFeatureSet(featureSet));
236 const QQsbCollection::EntryMap &pregenEntries = shaderLibraryManager.m_preGeneratedShaderEntries;
237 if (!pregenEntries.isEmpty()) {
238 const auto foundIt = pregenEntries.constFind(QQsbCollection::Entry(qsbcKey));
239 if (foundIt != pregenEntries.cend())
240 return shaderCache.newPipelineFromPregenerated(shaderString, featureSet, *foundIt, renderable.material);
241 }
242
243 // Try the persistent (disk-based) cache then.
244 if (const auto &maybePipeline = shaderCache.tryNewPipelineFromPersistentCache(qsbcKey, shaderString, featureSet))
245 return maybePipeline;
246
247 // Otherwise, build new shader code and run the resulting shaders through
248 // the shader conditioning pipeline.
249 const auto &material = static_cast<const QSSGRenderDefaultMaterial &>(renderable.getMaterial());
250 QSSGMaterialVertexPipeline vertexPipeline(shaderProgramGenerator,
251 shaderKeyProperties,
252 material.adapter);
253
255 vertexPipeline,
256 renderable.shaderDescription,
257 shaderKeyProperties,
258 featureSet,
259 renderable.material,
260 renderable.lights,
261 renderable.firstImage,
262 shaderLibraryManager,
263 shaderCache);
264}
265
267 QSSGSubsetRenderable &inRenderable,
268 const QSSGShaderFeatures &inFeatureSet)
269{
270 auto &m_currentLayer = renderer.m_currentLayer;
271 auto &m_generatedShaderString = renderer.m_generatedShaderString;
272 const auto &m_contextInterface = renderer.m_contextInterface;
273 const auto &theCache = m_contextInterface->shaderCache();
274 const auto &shaderProgramGenerator = m_contextInterface->shaderProgramGenerator();
275 const auto &shaderLibraryManager = m_contextInterface->shaderLibraryManager();
276 return QSSGRendererPrivate::generateRhiShaderPipelineImpl(inRenderable, *shaderLibraryManager, *theCache, *shaderProgramGenerator, m_currentLayer->defaultMaterialShaderKeyProperties, inFeatureSet, m_generatedShaderString);
277}
278
280{
281 const bool executeBeginFrame = !(allowRecursion && (m_activeFrameRef++ != 0));
282 if (executeBeginFrame) {
283 m_contextInterface->perFrameAllocator()->reset();
284 QSSGRHICTX_STAT(m_contextInterface->rhiContext().get(), start(&layer));
285 resetResourceCounters(&layer);
286 }
287}
288
290{
291 const bool executeEndFrame = !(allowRecursion && (--m_activeFrameRef != 0));
292 if (executeEndFrame) {
293 cleanupUnreferencedBuffers(&layer);
294
295 // We need to do this endFrame(), as the material nodes might not exist after this!
296 for (auto *matObj : std::as_const(m_materialClearDirty)) {
297 if (matObj->type == QSSGRenderGraphObject::Type::CustomMaterial) {
298 static_cast<QSSGRenderCustomMaterial *>(matObj)->clearDirty();
299 } else if (matObj->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
300 matObj->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
301 matObj->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial) {
302 static_cast<QSSGRenderDefaultMaterial *>(matObj)->clearDirty();
303 }
304 }
305 m_materialClearDirty.clear();
306
307 QSSGRHICTX_STAT(m_contextInterface->rhiContext().get(), stop(&layer));
308
309 ++m_frameCount;
310 }
311
312 return executeEndFrame;
313}
314
316 const QSSGRenderLayer &layer,
317 const QSSGRenderRay &ray)
318{
319 const auto &bufferManager = ctx.bufferManager();
321 PickResultList pickResults;
323 getLayerHitObjectList(layer, *bufferManager, ray, isGlobalPickingEnabled, pickResults);
324 // Things are rendered in a particular order and we need to respect that ordering.
325 std::stable_sort(pickResults.begin(), pickResults.end(), [](const QSSGRenderPickResult &lhs, const QSSGRenderPickResult &rhs) {
326 return lhs.m_distanceSq < rhs.m_distanceSq;
327 });
328 return pickResults;
329}
330
332 const QSSGRenderLayer &layer,
333 const QSSGRenderRay &ray,
335{
336 const auto &bufferManager = ctx.bufferManager();
338
340 PickResultList pickResults;
341 if (target)
342 intersectRayWithSubsetRenderable(*bufferManager, ray, *target, pickResults);
343 else
344 getLayerHitObjectList(layer, *bufferManager, ray, isGlobalPickingEnabled, pickResults);
345
346 std::stable_sort(pickResults.begin(), pickResults.end(), [](const QSSGRenderPickResult &lhs, const QSSGRenderPickResult &rhs) {
347 return lhs.m_distanceSq < rhs.m_distanceSq;
348 });
349 return pickResults;
350}
351
353 QSSGBufferManager &bufferManager,
354 const QSSGRenderRay &ray,
355 QVarLengthArray<QSSGRenderNode*> subset)
356{
359
360 for (auto target : subset)
361 intersectRayWithSubsetRenderable(bufferManager, ray, *target, pickResults);
362
363 std::stable_sort(pickResults.begin(), pickResults.end(), [](const QSSGRenderPickResult &lhs, const QSSGRenderPickResult &rhs) {
364 return lhs.m_distanceSq < rhs.m_distanceSq;
365 });
366 return pickResults;
367}
368
370{
371 renderer.m_globalPickingEnabled = isEnabled;
372}
373
378
379const std::unique_ptr<QSSGRhiQuadRenderer> &QSSGRenderer::rhiQuadRenderer() const
380{
381 if (!m_rhiQuadRenderer)
382 m_rhiQuadRenderer = std::make_unique<QSSGRhiQuadRenderer>();
383
384 return m_rhiQuadRenderer;
385}
386
387const std::unique_ptr<QSSGRhiCubeRenderer> &QSSGRenderer::rhiCubeRenderer() const
388{
389 if (!m_rhiCubeRenderer)
390 m_rhiCubeRenderer = std::make_unique<QSSGRhiCubeRenderer>();
391
392 return m_rhiCubeRenderer;
393
394}
395
396void QSSGRenderer::beginLayerRender(QSSGLayerRenderData &inLayer)
397{
398 m_currentLayer = &inLayer;
399}
400void QSSGRenderer::endLayerRender()
401{
402 m_currentLayer = nullptr;
403}
404
405using RenderableList = QVarLengthArray<const QSSGRenderNode *>;
406static void dfs(const QSSGRenderNode &node, RenderableList &renderables)
407{
409 renderables.push_back(&node);
410
411 for (const auto &child : node.children)
412 dfs(child, renderables);
413}
414
416 QSSGBufferManager &bufferManager,
417 const QSSGRenderRay &ray,
418 bool inPickEverything,
419 PickResultList &outIntersectionResult)
420{
421 RenderableList renderables;
422 for (const auto &childNode : layer.children)
423 dfs(childNode, renderables);
424
425 for (int idx = renderables.size() - 1; idx >= 0; --idx) {
426 const auto &pickableObject = renderables.at(idx);
427 if (inPickEverything || pickableObject->getLocalState(QSSGRenderNode::LocalState::Pickable))
428 intersectRayWithSubsetRenderable(bufferManager, ray, *pickableObject, outIntersectionResult);
429 }
430}
431
433 const QSSGRenderRay &inRay,
434 const QSSGRenderNode &node,
435 PickResultList &outIntersectionResultList)
436{
437 // Item2D's requires special handling
438 if (node.type == QSSGRenderGraphObject::Type::Item2D) {
439 const QSSGRenderItem2D &item2D = static_cast<const QSSGRenderItem2D &>(node);
440 intersectRayWithItem2D(inRay, item2D, outIntersectionResultList);
441 return;
442 }
443
444 if (node.type != QSSGRenderGraphObject::Type::Model)
445 return;
446
447 const QSSGRenderModel &model = static_cast<const QSSGRenderModel &>(node);
448
449 // We have to have a guard here, as the meshes are usually loaded on the render thread,
450 // and we assume all meshes are loaded before picking and none are removed, which
451 // is usually true, except for custom geometry which can be updated at any time. So this
452 // guard should really only be locked whenever a custom geometry buffer is being updated
453 // on the render thread. Still naughty though because this can block the render thread.
454 QMutexLocker mutexLocker(bufferManager.meshUpdateMutex());
455 auto mesh = bufferManager.getMeshForPicking(model);
456 if (!mesh)
457 return;
458
459 const auto &subMeshes = mesh->subsets;
460 QSSGBounds3 modelBounds;
461 for (const auto &subMesh : subMeshes)
462 modelBounds.include(subMesh.bounds);
463
464 if (modelBounds.isEmpty())
465 return;
466
467 const bool instancing = model.instancing(); // && instancePickingEnabled
468 int instanceCount = instancing ? model.instanceTable->count() : 1;
469
470 for (int instanceIndex = 0; instanceIndex < instanceCount; ++instanceIndex) {
471
472 QMatrix4x4 modelTransform;
473 if (instancing) {
474 modelTransform = model.globalInstanceTransform * model.instanceTable->getTransform(instanceIndex) * model.localInstanceTransform;
475 } else {
476 modelTransform = model.globalTransform;
477 }
478 auto rayData = QSSGRenderRay::createRayData(modelTransform, inRay);
479
480 auto hit = QSSGRenderRay::intersectWithAABBv2(rayData, modelBounds);
481
482 // If we don't intersect with the model at all, then there's no need to go furher down!
483 if (!hit.intersects())
484 continue;
485
486 // Check each submesh to find the closest intersection point
487 float minRayLength = std::numeric_limits<float>::max();
488 QSSGRenderRay::IntersectionResult intersectionResult;
489 QVector<QSSGRenderRay::IntersectionResult> results;
490
491 int subset = 0;
492 int resultSubset = 0;
493 for (const auto &subMesh : subMeshes) {
495 if (!subMesh.bvhRoot.isNull()) {
496 hit = QSSGRenderRay::intersectWithAABBv2(rayData, subMesh.bvhRoot->boundingData);
497 if (hit.intersects()) {
498 results.clear();
499 inRay.intersectWithBVH(rayData, static_cast<const QSSGMeshBVHNode *>(subMesh.bvhRoot), mesh, results);
500 float subMeshMinRayLength = std::numeric_limits<float>::max();
501 for (const auto &subMeshResult : std::as_const(results)) {
502 if (subMeshResult.rayLengthSquared < subMeshMinRayLength) {
503 result = subMeshResult;
504 subMeshMinRayLength = result.rayLengthSquared;
505 }
506 }
507 }
508 } else {
509 hit = QSSGRenderRay::intersectWithAABBv2(rayData, subMesh.bounds);
510 if (hit.intersects())
512 }
513 if (result.intersects && result.rayLengthSquared < minRayLength) {
514 intersectionResult = result;
515 minRayLength = intersectionResult.rayLengthSquared;
516 resultSubset = subset;
517 }
518 subset++;
519 }
520
521 if (intersectionResult.intersects)
522 outIntersectionResultList.push_back(QSSGRenderPickResult { &model,
523 intersectionResult.rayLengthSquared,
524 intersectionResult.relXY,
525 intersectionResult.scenePosition,
526 intersectionResult.localPosition,
527 intersectionResult.faceNormal,
528 resultSubset,
529 instanceIndex
530 });
531 }
532}
533
534void QSSGRendererPrivate::intersectRayWithItem2D(const QSSGRenderRay &inRay, const QSSGRenderItem2D &item2D, PickResultList &outIntersectionResultList)
535{
536 // Get the plane (and normal) that the item 2D is on
537 const QVector3D p0 = item2D.getGlobalPos();
538 const QVector3D normal = -item2D.getDirection();
539
540 const float d = QVector3D::dotProduct(inRay.direction, normal);
541 float intersectionTime = 0;
542 if (d > 1e-6f) {
543 const QVector3D p0l0 = p0 - inRay.origin;
544 intersectionTime = QVector3D::dotProduct(p0l0, normal) / d;
545 if (intersectionTime >= 0) {
546 // Intersection
547 const QVector3D intersectionPoint = inRay.origin + inRay.direction * intersectionTime;
548 const QMatrix4x4 inverseGlobalTransform = item2D.globalTransform.inverted();
549 const QVector3D localIntersectionPoint = QSSGUtils::mat44::transform(inverseGlobalTransform, intersectionPoint);
550 const QVector2D qmlCoordinate(localIntersectionPoint.x(), -localIntersectionPoint.y());
551 outIntersectionResultList.push_back(QSSGRenderPickResult { &item2D,
552 intersectionTime * intersectionTime,
553 qmlCoordinate,
554 intersectionPoint,
555 localIntersectionPoint,
556 -normal });
557 }
558 }
559}
560
562 QSSGSubsetRenderable &inRenderable,
563 const QSSGShaderFeatures &inFeatureSet)
564{
565 auto *m_currentLayer = renderer.m_currentLayer;
566 QSSG_ASSERT(m_currentLayer != nullptr, return {});
567
568 // This function is the main entry point for retrieving the shaders for a
569 // default material, and is called for every material for every model in
570 // every frame. Therefore, like with custom materials, employ a first level
571 // cache (a simple hash table), with a key that's quick to
572 // generate/hash/compare. Even though there are other levels of caching in
573 // the components that get invoked from here, those may not be suitable
574 // performance wise. So bail out right here as soon as possible.
575 auto &shaderMap = m_currentLayer->shaderMap;
576
578 timer.start();
579
580 QSSGRhiShaderPipelinePtr shaderPipeline;
581
582 // This just references inFeatureSet and inRenderable.shaderDescription -
583 // cheap to construct and is good enough for the find()
585 inFeatureSet,
586 inRenderable.shaderDescription);
587 auto it = shaderMap.find(skey);
588 if (it == shaderMap.end()) {
589 Q_TRACE_SCOPE(QSSG_generateShader);
590 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DGenerateShader);
591 shaderPipeline = QSSGRendererPrivate::generateRhiShaderPipeline(renderer, inRenderable, inFeatureSet);
592 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DGenerateShader, 0, inRenderable.material.profilingId);
593 // make skey useable as a key for the QHash (makes a copy of the materialKey, instead of just referencing)
594 skey.detach();
595 // insert it no matter what, no point in trying over and over again
596 shaderMap.insert(skey, shaderPipeline);
597 } else {
598 shaderPipeline = it.value();
599 }
600
601 if (shaderPipeline != nullptr) {
602 if (m_currentLayer && !m_currentLayer->renderedCameras.isEmpty())
603 m_currentLayer->ensureCachedCameraDatas();
604 }
605
606 const auto &rhiContext = renderer.m_contextInterface->rhiContext();
607 QSSGRhiContextStats::get(*rhiContext).registerMaterialShaderGenerationTime(timer.elapsed());
608
609 return shaderPipeline;
610}
611
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
void clear()
Definition qlist.h:434
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
QMatrix4x4 inverted(bool *invertible=nullptr) const
Returns the inverse of this matrix.
\inmodule QtCore
Definition qmutex.h:313
static FeatureSet toFeatureSet(const T &ssgFeatureSet)
bool isRecordingFrame() const
Definition qrhi.cpp:10802
Class representing 3D range or axis aligned bounding box.
void include(const QVector3D &v)
expands the volume to include v
QSSGRenderMesh * getMeshForPicking(const QSSGRenderModel &model) const
const std::unique_ptr< QSSGRhiContext > & rhiContext() const
const std::unique_ptr< QSSGBufferManager > & bufferManager() const
\inmodule QtQuick3D
static constexpr bool isRenderable(Type type) noexcept
static PickResultList syncPickSubset(const QSSGRenderLayer &layer, QSSGBufferManager &bufferManager, const QSSGRenderRay &ray, QVarLengthArray< QSSGRenderNode * > subset)
static void setRenderContextInterface(QSSGRenderer &renderer, QSSGRenderContextInterface *ctx)
static PickResultList syncPickAll(const QSSGRenderContextInterface &ctx, const QSSGRenderLayer &layer, const QSSGRenderRay &ray)
static void intersectRayWithItem2D(const QSSGRenderRay &inRay, const QSSGRenderItem2D &item2D, PickResultList &outIntersectionResultList)
static void intersectRayWithSubsetRenderable(QSSGBufferManager &bufferManager, const QSSGRenderRay &inRay, const QSSGRenderNode &node, PickResultList &outIntersectionResultList)
static QSSGRhiShaderPipelinePtr generateRhiShaderPipeline(QSSGRenderer &renderer, QSSGSubsetRenderable &inRenderable, const QSSGShaderFeatures &inFeatureSet)
static bool isGlobalPickingEnabled(const QSSGRenderer &renderer)
static void getLayerHitObjectList(const QSSGRenderLayer &layer, QSSGBufferManager &bufferManager, const QSSGRenderRay &ray, bool inPickEverything, PickResultList &outIntersectionResult)
static QSSGRhiShaderPipelinePtr generateRhiShaderPipelineImpl(QSSGSubsetRenderable &renderable, QSSGShaderLibraryManager &shaderLibraryManager, QSSGShaderCache &shaderCache, QSSGProgramGenerator &shaderProgramGenerator, const QSSGShaderDefaultMaterialKeyProperties &shaderKeyProperties, const QSSGShaderFeatures &featureSet, QByteArray &shaderString)
static void setGlobalPickingEnabled(QSSGRenderer &renderer, bool isEnabled)
static QSSGRhiShaderPipelinePtr getShaderPipelineForDefaultMaterial(QSSGRenderer &renderer, QSSGSubsetRenderable &inRenderable, const QSSGShaderFeatures &inFeatureSet)
static PickResultList syncPick(const QSSGRenderContextInterface &ctx, const QSSGRenderLayer &layer, const QSSGRenderRay &ray, QSSGRenderNode *target=nullptr)
bool prepareLayerForRender(QSSGRenderLayer &inLayer)
void rhiRender(QSSGRenderLayer &inLayer)
friend class QSSGLayerRenderData
const std::unique_ptr< QSSGRhiQuadRenderer > & rhiQuadRenderer() const
void rhiPrepare(QSSGRenderLayer &inLayer)
void cleanupResources(QList< QSSGRenderGraphObject * > &resources)
bool endFrame(QSSGRenderLayer &layer, bool allowRecursion=true)
void beginFrame(QSSGRenderLayer &layer, bool allowRecursion=true)
const std::unique_ptr< QSSGRhiCubeRenderer > & rhiCubeRenderer() const
QSSGRenderContextInterface * contextInterface() const
static QSSGRhiContextPrivate * get(QSSGRhiContext *q)
static QSSGRhiContextStats & get(QSSGRhiContext &rhiCtx)
\inmodule QtQuick3D
bool isValid() const
QRhi * rhi() const
QSSGRhiShaderPipelinePtr tryGetRhiShaderPipeline(const QByteArray &inKey, const QSSGShaderFeatures &inFeatures)
QSSGRhiShaderPipelinePtr newPipelineFromPregenerated(const QByteArray &inKey, const QSSGShaderFeatures &inFeatures, QQsbCollection::Entry entry, const QSSGRenderGraphObject &obj, QSSGRhiShaderPipeline::StageFlags stageFlags={})
QSSGRhiShaderPipelinePtr tryNewPipelineFromPersistentCache(const QByteArray &qsbcKey, const QByteArray &inKey, const QSSGShaderFeatures &inFeatures, QSSGRhiShaderPipeline::StageFlags stageFlags={})
QQsbCollection::EntryMap m_preGeneratedShaderEntries
iterator end()
Definition qset.h:140
void clear()
Definition qset.h:61
const_iterator constFind(const T &value) const
Definition qset.h:161
iterator find(const T &value)
Definition qset.h:159
iterator insert(const T &value)
Definition qset.h:155
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:241
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
static constexpr float dotProduct(QVector3D v1, QVector3D v2) noexcept
Returns the dot product of v1 and v2.
Definition qvectornd.h:770
EGLContext ctx
QSet< QString >::iterator it
QVector3D Q_QUICK3DUTILS_EXPORT transform(const QMatrix4x4 &m, const QVector3D &v)
Definition qssgutils.cpp:86
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
static int instanceCount
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT layer
GLenum target
GLuint start
GLuint64EXT * result
[6]
#define Q_QUICK3D_PROFILE_START(Type)
#define Q_QUICK3D_PROFILE_END_WITH_ID(Type, Payload, POID)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QSSG_ASSERT(cond, action)
static void cleanupResourcesImpl(const QSSGRenderContextInterface &rci, const Container &resources)
static void dfs(const QSSGRenderNode &node, RenderableList &renderables)
static QByteArray logPrefix()
QVarLengthArray< const QSSGRenderNode * > RenderableList
#define QSSGRHICTX_STAT(ctx, f)
std::shared_ptr< QSSGRhiShaderPipeline > QSSGRhiShaderPipelinePtr
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
QSqlQueryModel * model
[16]
QTimer * timer
[3]
QLayoutItem * child
[0]
QSvgRenderer * renderer
[0]
QByteArray generateSha() const
static QSSGRhiShaderPipelinePtr generateMaterialRhiShader(const QByteArray &inShaderKeyPrefix, QSSGMaterialVertexPipeline &vertexGenerator, const QSSGShaderDefaultMaterialKey &key, const QSSGShaderDefaultMaterialKeyProperties &inProperties, const QSSGShaderFeatures &inFeatureSet, const QSSGRenderGraphObject &inMaterial, const QSSGShaderLightListView &inLights, QSSGRenderableImage *inFirstImage, QSSGShaderLibraryManager &shaderLibraryManager, QSSGShaderCache &theCache)
QVector< QSSGRenderSubset > subsets
static IntersectionResult createIntersectionResult(const RayData &data, const HitResult &hit)
static RayData createRayData(const QMatrix4x4 &globalTransform, const QSSGRenderRay &ray)
static HitResult intersectWithAABBv2(const RayData &data, const QSSGBounds3 &bounds)
const QSSGRenderSubset & subset
const QSSGRenderGraphObject & material