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 delete model->particleBuffer;
169 } else if (resource->type == QSSGRenderGraphObject::Type::TextureData) {
170 auto textureData = static_cast<QSSGRenderTextureData *>(resource);
171 bufferManager->releaseTextureData(textureData);
172 } else if (resource->type == QSSGRenderGraphObject::Type::RenderExtension) {
173 auto *rext = static_cast<QSSGRenderExtension *>(resource);
174 bufferManager->releaseExtensionResult(*rext);
175 }
176
177 // ### There might be more types that need to be supported
178
179 delete resource;
180 }
181}
182
183void QSSGRenderer::cleanupResources(QList<QSSGRenderGraphObject *> &resources)
184{
185 cleanupResourcesImpl(*m_contextInterface, resources);
186 resources.clear();
187}
188
189void QSSGRenderer::cleanupResources(QSet<QSSGRenderGraphObject *> &resources)
190{
191 cleanupResourcesImpl(*m_contextInterface, resources);
192 resources.clear();
193}
194
195QSSGLayerRenderData *QSSGRenderer::getOrCreateLayerRenderData(QSSGRenderLayer &layer)
196{
197 if (layer.renderData == nullptr)
198 layer.renderData = new QSSGLayerRenderData(layer, *this);
199
200 return layer.renderData;
201}
202
203void QSSGRenderer::addMaterialDirtyClear(QSSGRenderGraphObject *material)
204{
205 m_materialClearDirty.insert(material);
206}
207
208static QByteArray logPrefix() { return QByteArrayLiteral("mesh default material pipeline-- "); }
209
210
212 QSSGShaderLibraryManager &shaderLibraryManager,
213 QSSGShaderCache &shaderCache,
214 QSSGProgramGenerator &shaderProgramGenerator,
215 const QSSGShaderDefaultMaterialKeyProperties &shaderKeyProperties,
216 const QSSGShaderFeatures &featureSet,
217 QByteArray &shaderString)
218{
219 shaderString = logPrefix();
220 QSSGShaderDefaultMaterialKey theKey(renderable.shaderDescription);
221
222 // This is not a cheap operation. This function assumes that it will not be
223 // hit for every material for every model in every frame (except of course
224 // for materials that got changed). In practice this is ensured by the
225 // cheaper-to-lookup cache in getShaderPipelineForDefaultMaterial().
226 theKey.toString(shaderString, shaderKeyProperties);
227
228 // Check the in-memory, per-QSSGShaderCache (and so per-QQuickWindow)
229 // runtime cache. That may get cleared upon an explicit call to
230 // QQuickWindow::releaseResources(), but will otherwise store all
231 // encountered shader pipelines in any View3D in the window.
232 if (const auto &maybePipeline = shaderCache.tryGetRhiShaderPipeline(shaderString, featureSet))
233 return maybePipeline;
234
235 // Check if there's a pre-built (offline generated) shader for available.
236 const QByteArray qsbcKey = QQsbCollection::EntryDesc::generateSha(shaderString, QQsbCollection::toFeatureSet(featureSet));
237 const QQsbCollection::EntryMap &pregenEntries = shaderLibraryManager.m_preGeneratedShaderEntries;
238 if (!pregenEntries.isEmpty()) {
239 const auto foundIt = pregenEntries.constFind(QQsbCollection::Entry(qsbcKey));
240 if (foundIt != pregenEntries.cend())
241 return shaderCache.newPipelineFromPregenerated(shaderString, featureSet, *foundIt, renderable.material);
242 }
243
244 // Try the persistent (disk-based) cache then.
245 if (const auto &maybePipeline = shaderCache.tryNewPipelineFromPersistentCache(qsbcKey, shaderString, featureSet))
246 return maybePipeline;
247
248 // Otherwise, build new shader code and run the resulting shaders through
249 // the shader conditioning pipeline.
250 const auto &material = static_cast<const QSSGRenderDefaultMaterial &>(renderable.getMaterial());
251 QSSGMaterialVertexPipeline vertexPipeline(shaderProgramGenerator,
252 shaderKeyProperties,
253 material.adapter);
254
256 vertexPipeline,
257 renderable.shaderDescription,
258 shaderKeyProperties,
259 featureSet,
260 renderable.material,
261 renderable.lights,
262 renderable.firstImage,
263 shaderLibraryManager,
264 shaderCache);
265}
266
268 QSSGSubsetRenderable &inRenderable,
269 const QSSGShaderFeatures &inFeatureSet)
270{
271 auto &m_currentLayer = renderer.m_currentLayer;
272 auto &m_generatedShaderString = renderer.m_generatedShaderString;
273 const auto &m_contextInterface = renderer.m_contextInterface;
274 const auto &theCache = m_contextInterface->shaderCache();
275 const auto &shaderProgramGenerator = m_contextInterface->shaderProgramGenerator();
276 const auto &shaderLibraryManager = m_contextInterface->shaderLibraryManager();
277 return QSSGRendererPrivate::generateRhiShaderPipelineImpl(inRenderable, *shaderLibraryManager, *theCache, *shaderProgramGenerator, m_currentLayer->defaultMaterialShaderKeyProperties, inFeatureSet, m_generatedShaderString);
278}
279
281{
282 const bool executeBeginFrame = !(allowRecursion && (m_activeFrameRef++ != 0));
283 if (executeBeginFrame) {
284 m_contextInterface->perFrameAllocator()->reset();
285 QSSGRHICTX_STAT(m_contextInterface->rhiContext().get(), start(&layer));
286 resetResourceCounters(&layer);
287 }
288}
289
291{
292 const bool executeEndFrame = !(allowRecursion && (--m_activeFrameRef != 0));
293 if (executeEndFrame) {
294 cleanupUnreferencedBuffers(&layer);
295
296 // We need to do this endFrame(), as the material nodes might not exist after this!
297 for (auto *matObj : std::as_const(m_materialClearDirty)) {
298 if (matObj->type == QSSGRenderGraphObject::Type::CustomMaterial) {
299 static_cast<QSSGRenderCustomMaterial *>(matObj)->clearDirty();
300 } else if (matObj->type == QSSGRenderGraphObject::Type::DefaultMaterial ||
301 matObj->type == QSSGRenderGraphObject::Type::PrincipledMaterial ||
302 matObj->type == QSSGRenderGraphObject::Type::SpecularGlossyMaterial) {
303 static_cast<QSSGRenderDefaultMaterial *>(matObj)->clearDirty();
304 }
305 }
306 m_materialClearDirty.clear();
307
308 QSSGRHICTX_STAT(m_contextInterface->rhiContext().get(), stop(&layer));
309
310 ++m_frameCount;
311 }
312
313 return executeEndFrame;
314}
315
317 const QSSGRenderLayer &layer,
318 const QSSGRenderRay &ray)
319{
320 const auto &bufferManager = ctx.bufferManager();
322 PickResultList pickResults;
324 getLayerHitObjectList(layer, *bufferManager, ray, isGlobalPickingEnabled, pickResults);
325 // Things are rendered in a particular order and we need to respect that ordering.
326 std::stable_sort(pickResults.begin(), pickResults.end(), [](const QSSGRenderPickResult &lhs, const QSSGRenderPickResult &rhs) {
327 return lhs.m_distanceSq < rhs.m_distanceSq;
328 });
329 return pickResults;
330}
331
333 const QSSGRenderLayer &layer,
334 const QSSGRenderRay &ray,
336{
337 const auto &bufferManager = ctx.bufferManager();
339
341 PickResultList pickResults;
342 if (target)
343 intersectRayWithSubsetRenderable(*bufferManager, ray, *target, pickResults);
344 else
345 getLayerHitObjectList(layer, *bufferManager, ray, isGlobalPickingEnabled, pickResults);
346
347 std::stable_sort(pickResults.begin(), pickResults.end(), [](const QSSGRenderPickResult &lhs, const QSSGRenderPickResult &rhs) {
348 return lhs.m_distanceSq < rhs.m_distanceSq;
349 });
350 return pickResults;
351}
352
354 QSSGBufferManager &bufferManager,
355 const QSSGRenderRay &ray,
356 QVarLengthArray<QSSGRenderNode*> subset)
357{
360
361 for (auto target : subset)
362 intersectRayWithSubsetRenderable(bufferManager, ray, *target, pickResults);
363
364 std::stable_sort(pickResults.begin(), pickResults.end(), [](const QSSGRenderPickResult &lhs, const QSSGRenderPickResult &rhs) {
365 return lhs.m_distanceSq < rhs.m_distanceSq;
366 });
367 return pickResults;
368}
369
371{
372 renderer.m_globalPickingEnabled = isEnabled;
373}
374
379
380const std::unique_ptr<QSSGRhiQuadRenderer> &QSSGRenderer::rhiQuadRenderer() const
381{
382 if (!m_rhiQuadRenderer)
383 m_rhiQuadRenderer = std::make_unique<QSSGRhiQuadRenderer>();
384
385 return m_rhiQuadRenderer;
386}
387
388const std::unique_ptr<QSSGRhiCubeRenderer> &QSSGRenderer::rhiCubeRenderer() const
389{
390 if (!m_rhiCubeRenderer)
391 m_rhiCubeRenderer = std::make_unique<QSSGRhiCubeRenderer>();
392
393 return m_rhiCubeRenderer;
394
395}
396
397void QSSGRenderer::beginLayerRender(QSSGLayerRenderData &inLayer)
398{
399 m_currentLayer = &inLayer;
400}
401void QSSGRenderer::endLayerRender()
402{
403 m_currentLayer = nullptr;
404}
405
406using RenderableList = QVarLengthArray<const QSSGRenderNode *>;
407static void dfs(const QSSGRenderNode &node, RenderableList &renderables)
408{
410 renderables.push_back(&node);
411
412 for (const auto &child : node.children)
413 dfs(child, renderables);
414}
415
417 QSSGBufferManager &bufferManager,
418 const QSSGRenderRay &ray,
419 bool inPickEverything,
420 PickResultList &outIntersectionResult)
421{
422 RenderableList renderables;
423 for (const auto &childNode : layer.children)
424 dfs(childNode, renderables);
425
426 for (int idx = renderables.size() - 1; idx >= 0; --idx) {
427 const auto &pickableObject = renderables.at(idx);
428 if (inPickEverything || pickableObject->getLocalState(QSSGRenderNode::LocalState::Pickable))
429 intersectRayWithSubsetRenderable(bufferManager, ray, *pickableObject, outIntersectionResult);
430 }
431}
432
434 const QSSGRenderRay &inRay,
435 const QSSGRenderNode &node,
436 PickResultList &outIntersectionResultList)
437{
438 // Item2D's requires special handling
439 if (node.type == QSSGRenderGraphObject::Type::Item2D) {
440 const QSSGRenderItem2D &item2D = static_cast<const QSSGRenderItem2D &>(node);
441 intersectRayWithItem2D(inRay, item2D, outIntersectionResultList);
442 return;
443 }
444
445 if (node.type != QSSGRenderGraphObject::Type::Model)
446 return;
447
448 const QSSGRenderModel &model = static_cast<const QSSGRenderModel &>(node);
449
450 // We have to have a guard here, as the meshes are usually loaded on the render thread,
451 // and we assume all meshes are loaded before picking and none are removed, which
452 // is usually true, except for custom geometry which can be updated at any time. So this
453 // guard should really only be locked whenever a custom geometry buffer is being updated
454 // on the render thread. Still naughty though because this can block the render thread.
455 QMutexLocker mutexLocker(bufferManager.meshUpdateMutex());
456 auto mesh = bufferManager.getMeshForPicking(model);
457 if (!mesh)
458 return;
459
460 const auto &subMeshes = mesh->subsets;
461 QSSGBounds3 modelBounds;
462 for (const auto &subMesh : subMeshes)
463 modelBounds.include(subMesh.bounds);
464
465 if (modelBounds.isEmpty())
466 return;
467
468 const bool instancing = model.instancing(); // && instancePickingEnabled
469 int instanceCount = instancing ? model.instanceTable->count() : 1;
470
471 for (int instanceIndex = 0; instanceIndex < instanceCount; ++instanceIndex) {
472
473 QMatrix4x4 modelTransform;
474 if (instancing) {
475 modelTransform = model.globalInstanceTransform * model.instanceTable->getTransform(instanceIndex) * model.localInstanceTransform;
476 } else {
477 modelTransform = model.globalTransform;
478 }
479 auto rayData = QSSGRenderRay::createRayData(modelTransform, inRay);
480
481 auto hit = QSSGRenderRay::intersectWithAABBv2(rayData, modelBounds);
482
483 // If we don't intersect with the model at all, then there's no need to go furher down!
484 if (!hit.intersects())
485 continue;
486
487 // Check each submesh to find the closest intersection point
488 float minRayLength = std::numeric_limits<float>::max();
489 QSSGRenderRay::IntersectionResult intersectionResult;
490 QVector<QSSGRenderRay::IntersectionResult> results;
491
492 int subset = 0;
493 int resultSubset = 0;
494 for (const auto &subMesh : subMeshes) {
496 if (!subMesh.bvhRoot.isNull()) {
497 hit = QSSGRenderRay::intersectWithAABBv2(rayData, subMesh.bvhRoot->boundingData);
498 if (hit.intersects()) {
499 results.clear();
500 inRay.intersectWithBVH(rayData, static_cast<const QSSGMeshBVHNode *>(subMesh.bvhRoot), mesh, results);
501 float subMeshMinRayLength = std::numeric_limits<float>::max();
502 for (const auto &subMeshResult : std::as_const(results)) {
503 if (subMeshResult.rayLengthSquared < subMeshMinRayLength) {
504 result = subMeshResult;
505 subMeshMinRayLength = result.rayLengthSquared;
506 }
507 }
508 }
509 } else {
510 hit = QSSGRenderRay::intersectWithAABBv2(rayData, subMesh.bounds);
511 if (hit.intersects())
513 }
514 if (result.intersects && result.rayLengthSquared < minRayLength) {
515 intersectionResult = result;
516 minRayLength = intersectionResult.rayLengthSquared;
517 resultSubset = subset;
518 }
519 subset++;
520 }
521
522 if (intersectionResult.intersects)
523 outIntersectionResultList.push_back(QSSGRenderPickResult { &model,
524 intersectionResult.rayLengthSquared,
525 intersectionResult.relXY,
526 intersectionResult.scenePosition,
527 intersectionResult.localPosition,
528 intersectionResult.faceNormal,
529 resultSubset,
530 instanceIndex
531 });
532 }
533}
534
535void QSSGRendererPrivate::intersectRayWithItem2D(const QSSGRenderRay &inRay, const QSSGRenderItem2D &item2D, PickResultList &outIntersectionResultList)
536{
537 // Get the plane (and normal) that the item 2D is on
538 const QVector3D p0 = item2D.getGlobalPos();
539 const QVector3D normal = -item2D.getDirection();
540
541 const float d = QVector3D::dotProduct(inRay.direction, normal);
542 float intersectionTime = 0;
543 if (d > 1e-6f) {
544 const QVector3D p0l0 = p0 - inRay.origin;
545 intersectionTime = QVector3D::dotProduct(p0l0, normal) / d;
546 if (intersectionTime >= 0) {
547 // Intersection
548 const QVector3D intersectionPoint = inRay.origin + inRay.direction * intersectionTime;
549 const QMatrix4x4 inverseGlobalTransform = item2D.globalTransform.inverted();
550 const QVector3D localIntersectionPoint = QSSGUtils::mat44::transform(inverseGlobalTransform, intersectionPoint);
551 const QVector2D qmlCoordinate(localIntersectionPoint.x(), -localIntersectionPoint.y());
552 outIntersectionResultList.push_back(QSSGRenderPickResult { &item2D,
553 intersectionTime * intersectionTime,
554 qmlCoordinate,
555 intersectionPoint,
556 localIntersectionPoint,
557 -normal });
558 }
559 }
560}
561
563 QSSGSubsetRenderable &inRenderable,
564 const QSSGShaderFeatures &inFeatureSet)
565{
566 auto *m_currentLayer = renderer.m_currentLayer;
567 QSSG_ASSERT(m_currentLayer != nullptr, return {});
568
569 // This function is the main entry point for retrieving the shaders for a
570 // default material, and is called for every material for every model in
571 // every frame. Therefore, like with custom materials, employ a first level
572 // cache (a simple hash table), with a key that's quick to
573 // generate/hash/compare. Even though there are other levels of caching in
574 // the components that get invoked from here, those may not be suitable
575 // performance wise. So bail out right here as soon as possible.
576 auto &shaderMap = m_currentLayer->shaderMap;
577
579 timer.start();
580
581 QSSGRhiShaderPipelinePtr shaderPipeline;
582
583 // This just references inFeatureSet and inRenderable.shaderDescription -
584 // cheap to construct and is good enough for the find()
586 inFeatureSet,
587 inRenderable.shaderDescription);
588 auto it = shaderMap.find(skey);
589 if (it == shaderMap.end()) {
590 Q_TRACE_SCOPE(QSSG_generateShader);
591 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DGenerateShader);
592 shaderPipeline = QSSGRendererPrivate::generateRhiShaderPipeline(renderer, inRenderable, inFeatureSet);
593 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DGenerateShader, 0, inRenderable.material.profilingId);
594 // make skey useable as a key for the QHash (makes a copy of the materialKey, instead of just referencing)
595 skey.detach();
596 // insert it no matter what, no point in trying over and over again
597 shaderMap.insert(skey, shaderPipeline);
598 } else {
599 shaderPipeline = it.value();
600 }
601
602 if (shaderPipeline != nullptr) {
603 if (m_currentLayer && !m_currentLayer->renderedCameras.isEmpty())
604 m_currentLayer->ensureCachedCameraDatas();
605 }
606
607 const auto &rhiContext = renderer.m_contextInterface->rhiContext();
608 QSSGRhiContextStats::get(*rhiContext).registerMaterialShaderGenerationTime(timer.elapsed());
609
610 return shaderPipeline;
611}
612
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
void clear()
Definition qlist.h:435
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:10810
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:141
void clear()
Definition qset.h:62
const_iterator constFind(const T &value) const
Definition qset.h:162
iterator find(const T &value)
Definition qset.h:160
iterator insert(const T &value)
Definition qset.h:156
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