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
qssgrhicustommaterialsystem.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
6
7#include <QtQuick3DUtils/private/qssgutils_p.h>
8
10#include <QtQuick3DRuntimeRender/private/qssgrenderbuffermanager_p.h>
11#include <QtQuick3DRuntimeRender/private/qssgrendermesh_p.h>
12#include <QtQuick3DRuntimeRender/private/qssgrendercamera_p.h>
13#include <QtQuick3DRuntimeRender/private/qssgrenderlight_p.h>
14#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
15#include <QtQuick3DRuntimeRender/private/qssgrenderableimage_p.h>
16#include <QtQuick3DRuntimeRender/private/qssgvertexpipelineimpl_p.h>
17#include <QtQuick3DRuntimeRender/private/qssglayerrenderdata_p.h>
18#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
19#include <QtQuick3DRuntimeRender/private/qssgruntimerenderlogging_p.h>
20#include <QtQuick3DRuntimeRender/private/qssgrhiparticles_p.h>
21#include <qtquick3d_tracepoints_p.h>
22
23#include <QtCore/qbitarray.h>
24
26
27Q_TRACE_POINT(qtquick3d, QSSG_generateShader_entry)
28Q_TRACE_POINT(qtquick3d, QSSG_generateShader_exit)
29
31
35
37 const QSSGRenderSubset &,
38 QSSGRenderCustomMaterial &inMaterial)
39{
40 return inMaterial.isDirty();
41}
42
47
52
54 const QSSGRenderCustomMaterial &material,
55 QSSGSubsetRenderable &renderable,
56 const QSSGShaderDefaultMaterialKeyProperties &defaultMaterialShaderKeyProperties,
57 const QSSGShaderFeatures &featureSet)
58{
60 timer.start();
61
62 QSSGRhiShaderPipelinePtr shaderPipeline;
63
64 const bool multiView = featureSet.isSet(QSSGShaderFeatures::Feature::DisableMultiView)
65 ? false
66 : defaultMaterialShaderKeyProperties.m_viewCount.getValue(renderable.shaderDescription) >= 2;
69
70 // This just references inFeatureSet and inRenderable.shaderDescription -
71 // cheap to construct and is good enough for the find(). This is the first
72 // level, fast lookup. (equivalent to what
73 // QSSGRenderer::getShaderPipelineForDefaultMaterial does for the
74 // default/principled material)
75 QSSGShaderMapKey skey = QSSGShaderMapKey(shaderPathKey,
76 featureSet,
77 renderable.shaderDescription);
78 auto it = shaderMap.find(skey);
79 if (it == shaderMap.end()) {
80 // NB this key calculation must replicate exactly what the generator does in generateMaterialRhiShader()
81 QByteArray shaderString = shaderPathKey;
82 QSSGShaderDefaultMaterialKey matKey(renderable.shaderDescription);
83 matKey.toString(shaderString, defaultMaterialShaderKeyProperties);
84
85 // Try the persistent (disk-based) cache.
87 shaderPipeline = context->shaderCache()->tryNewPipelineFromPersistentCache(qsbcKey, shaderPathKey, featureSet);
88
89 if (!shaderPipeline) {
90 // Have to generate the shaders and send it all through the shader conditioning pipeline.
91 Q_TRACE_SCOPE(QSSG_generateShader);
92 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DGenerateShader);
93 QSSGMaterialVertexPipeline vertexPipeline(*context->shaderProgramGenerator(),
94 defaultMaterialShaderKeyProperties,
95 material.adapter);
96
97 shaderPipeline = QSSGMaterialShaderGenerator::generateMaterialRhiShader(shaderPathKey,
98 vertexPipeline,
99 renderable.shaderDescription,
100 defaultMaterialShaderKeyProperties,
101 featureSet,
102 renderable.material,
103 renderable.lights,
104 renderable.firstImage,
105 *context->shaderLibraryManager(),
106 *context->shaderCache());
107 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DGenerateShader, 0, material.profilingId);
108 }
109
110 // make skey useable as a key for the QHash (makes a copy of the materialKey, instead of just referencing)
111 skey.detach();
112 // insert it no matter what, no point in trying over and over again
113 shaderMap.insert(skey, shaderPipeline);
114 } else {
115 shaderPipeline = it.value();
116 }
117
118 if (shaderPipeline) {
120 shaderPipeline->resetExtraTextures();
121 }
122
123 QSSGRhiContextStats::get(*context->rhiContext()).registerMaterialShaderGenerationTime(timer.elapsed());
124
125 return shaderPipeline;
126}
127
129 QSSGRhiContext *rhiCtx,
130 const QSSGLayerRenderData &inData,
131 char *ubufData,
133 const QSSGRenderCustomMaterial &material,
134 QSSGSubsetRenderable &renderable,
135 const QSSGRenderCameraList &cameras,
136 const QVector2D *depthAdjust,
137 const QMatrix4x4 *alteredModelViewProjection)
138{
139 QSSGRenderMvpArray alteredMvpList;
140 if (alteredModelViewProjection)
141 alteredMvpList[0] = *alteredModelViewProjection;
142
143 const QMatrix4x4 clipSpaceCorrMatrix = rhiCtx->rhi()->clipSpaceCorrMatrix();
144 QRhiTexture *lightmapTexture = inData.getLightmapTexture(renderable.modelContext);
145
146 const auto &modelNode = renderable.modelContext.model;
147 const QMatrix4x4 &localInstanceTransform(modelNode.localInstanceTransform);
148 const QMatrix4x4 &globalInstanceTransform(modelNode.globalInstanceTransform);
149
150 const auto &defaultMaterialShaderKeyProperties = inData.getDefaultMaterialPropertyTable();
151
152 const QMatrix4x4 &modelMatrix(modelNode.usesBoneTexture() ? QMatrix4x4() : renderable.globalTransform);
153
155 shaderPipeline,
156 ubufData,
157 ps,
158 material,
159 renderable.shaderDescription,
160 defaultMaterialShaderKeyProperties,
161 cameras,
162 alteredModelViewProjection ? alteredMvpList : renderable.modelContext.modelViewProjections,
163 renderable.modelContext.normalMatrix,
164 modelMatrix,
165 clipSpaceCorrMatrix,
166 localInstanceTransform,
167 globalInstanceTransform,
168 toDataView(modelNode.morphWeights),
169 renderable.firstImage,
170 renderable.opacity,
171 inData,
172 renderable.lights,
173 renderable.reflectionProbe,
174 true,
175 renderable.renderableFlags.receivesReflections(),
176 depthAdjust,
177 lightmapTexture);
178}
179
180static const QRhiShaderResourceBinding::StageFlags CUSTOM_MATERIAL_VISIBILITY_ALL =
182
184 QSSGPassKey passKey,
185 QSSGSubsetRenderable &renderable,
186 const QSSGShaderFeatures &featureSet,
187 const QSSGRenderCustomMaterial &material,
188 const QSSGLayerRenderData &layerData,
189 QRhiRenderPassDescriptor *renderPassDescriptor,
190 int samples,
191 int viewCount,
192 QSSGRenderCamera *alteredCamera,
194 QMatrix4x4 *alteredModelViewProjection,
196{
197 QSSGRhiContext *rhiCtx = context->rhiContext().get();
198
199 QRhiGraphicsPipeline::TargetBlend blend; // no blending by default
201 blend.enable = true;
202 blend.srcColor = material.m_srcBlend;
203 blend.srcAlpha = material.m_srcAlphaBlend;
204 blend.dstColor = material.m_dstBlend;
205 blend.dstAlpha = material.m_dstAlphaBlend;
206 }
207
208 const QSSGCullFaceMode cullMode = material.m_cullMode;
209
210 const auto &defaultMaterialShaderKeyProperties = layerData.getDefaultMaterialPropertyTable();
211
212 const bool blendParticles = defaultMaterialShaderKeyProperties.m_blendParticles.getValue(renderable.shaderDescription);
213
214 const auto &shaderPipeline = shadersForCustomMaterial(ps, material, renderable, defaultMaterialShaderKeyProperties, featureSet);
215
216 if (shaderPipeline) {
218 const auto &modelNode = renderable.modelContext.model;
219
220 // NOTE:
221 // - entryIdx should 0 for QSSGRenderTextureCubeFaceNone.
222 // In all other cases the entryIdx is a combination of the cubeface idx and the subset offset, where the lower bits
223 // are the cubeface idx.
224 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
225 const quintptr entryIdx = quintptr(cubeFace != QSSGRenderTextureCubeFaceNone) * (cubeFaceIdx + (quintptr(renderable.subset.offset) << 3));
226 // As the entry might be null we create an entry key consisting of the entry and the material.
227 const auto entryPartA = reinterpret_cast<quintptr>(&material);
228 const auto entryPartB = reinterpret_cast<quintptr>(entry);
229 const void *entryKey = reinterpret_cast<const void *>(entryPartA ^ entryPartB);
230
231 QSSGRhiDrawCallData &dcd = QSSGRhiContextPrivate::get(rhiCtx)->drawCallData({ passKey, &modelNode, entryKey, entryIdx });
232
233 shaderPipeline->ensureCombinedMainLightsUniformBuffer(&dcd.ubuf);
234 char *ubufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
235 if (!alteredCamera) {
236 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, layerData.renderedCameras, nullptr, nullptr);
237 } else {
238 QSSGRenderCameraList cameras({ alteredCamera });
239 updateUniformsForCustomMaterial(*shaderPipeline, rhiCtx, layerData, ubufData, ps, material, renderable, cameras, nullptr, alteredModelViewProjection);
240 }
241 if (blendParticles)
242 QSSGParticleRenderer::updateUniformsForParticleModel(*shaderPipeline, ubufData, &renderable.modelContext.model, renderable.subset.offset);
243 dcd.ubuf->endFullDynamicBufferUpdateForCurrentFrame();
244
245 if (blendParticles)
246 QSSGParticleRenderer::prepareParticlesForModel(*shaderPipeline, rhiCtx, bindings, &renderable.modelContext.model);
247 bool instancing = false;
248 if (!alteredCamera) {
249 const QSSGRenderCameraDataList &cameraDatas(*layerData.renderedCameraData);
250 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, cameraDatas[0].direction, cameraDatas[0].position, renderable.instancingLodMin, renderable.instancingLodMax);
251 } else {
252 instancing = QSSGLayerRenderData::prepareInstancing(rhiCtx, &renderable, alteredCamera->getScalingCorrectDirection(), alteredCamera->getGlobalPos(), renderable.instancingLodMin, renderable.instancingLodMax);
253 }
254
255 ps->samples = samples;
256 ps->viewCount = viewCount;
257
258 ps->cullMode = QSSGRhiHelpers::toCullMode(cullMode);
259
260 ps->targetBlend = blend;
261
263
264 ia = renderable.subset.rhi.ia;
265
266 //### Copied code from default materials
267 int instanceBufferBinding = 0;
268 if (instancing) {
269 // Need to setup new bindings for instanced buffers
270 const quint32 stride = renderable.modelContext.model.instanceTable->stride();
271 QVarLengthArray<QRhiVertexInputBinding, 8> bindings;
272 std::copy(ia.inputLayout.cbeginBindings(),
273 ia.inputLayout.cendBindings(),
274 std::back_inserter(bindings));
275 bindings.append({ stride, QRhiVertexInputBinding::PerInstance });
276 instanceBufferBinding = bindings.size() - 1;
277 ia.inputLayout.setBindings(bindings.cbegin(), bindings.cend());
278 }
279
280 QSSGRhiHelpers::bakeVertexInputLocations(&ia, *shaderPipeline, instanceBufferBinding);
281
282 QRhiResourceUpdateBatch *resourceUpdates = rhiCtx->rhi()->nextResourceUpdateBatch();
283 QRhiTexture *dummyTexture = rhiCtx->dummyTexture({}, resourceUpdates);
284 QRhiTexture *dummyCubeTexture = rhiCtx->dummyTexture(QRhiTexture::CubeMap, resourceUpdates);
285 rhiCtx->commandBuffer()->resourceUpdate(resourceUpdates);
286
287 bindings.addUniformBuffer(0, CUSTOM_MATERIAL_VISIBILITY_ALL, dcd.ubuf, 0, shaderPipeline->ub0Size());
289 shaderPipeline->ub0LightDataOffset(),
290 shaderPipeline->ub0LightDataSize());
291
292 QVector<QShaderDescription::InOutVariable> samplerVars =
293 shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
294 for (const QShaderDescription::InOutVariable &var : shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
295 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(),
296 [&var](const QShaderDescription::InOutVariable &v) { return var.binding == v.binding; });
297 if (it == samplerVars.cend())
298 samplerVars.append(var);
299 }
300
301 int maxSamplerBinding = -1;
302 for (const QShaderDescription::InOutVariable &var : samplerVars)
303 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
304
305 // Will need to set unused image-samplers to something dummy
306 // because the shader code contains all custom property textures,
307 // and not providing a binding for all of them is invalid with some
308 // graphics APIs (and will need a real texture because setting a
309 // null handle or similar is not permitted with some of them so the
310 // srb does not accept null QRhiTextures either; but first let's
311 // figure out what bindings are unused in this frame)
312 QBitArray samplerBindingsSpecified(maxSamplerBinding + 1);
313
314 if (blendParticles)
315 samplerBindingsSpecified.setBit(shaderPipeline->bindingForTexture("qt_particleTexture"));
316
317 // Skinning
318 if (QRhiTexture *boneTexture = layerData.getBonemapTexture(renderable.modelContext)) {
319 int binding = shaderPipeline->bindingForTexture("qt_boneTexture");
320 if (binding >= 0) {
321 QRhiSampler *boneSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
327 });
328 bindings.addTexture(binding,
330 boneTexture,
331 boneSampler);
332 samplerBindingsSpecified.setBit(binding);
333 }
334 }
335
336 // Morphing
337 auto *targetsTexture = renderable.subset.rhi.targetsTexture;
338 if (targetsTexture) {
339 int binding = shaderPipeline->bindingForTexture("qt_morphTargetTexture");
340 if (binding >= 0) {
341 QRhiSampler *targetsSampler = rhiCtx->sampler({ QRhiSampler::Nearest,
347 });
348 bindings.addTexture(binding, QRhiShaderResourceBinding::VertexStage, renderable.subset.rhi.targetsTexture, targetsSampler);
349 samplerBindingsSpecified.setBit(binding);
350 }
351 }
352
353 // Prioritize reflection texture over Light Probe texture because
354 // reflection texture also contains the irradiance and pre filtered
355 // values for the light probe.
357 int reflectionSampler = shaderPipeline->bindingForTexture("qt_reflectionMap");
360 QRhiTexture* reflectionTexture = layerData.getReflectionMapManager()->reflectionMapEntry(renderable.reflectionProbeIndex)->m_rhiPrefilteredCube;
361 if (reflectionSampler >= 0 && reflectionTexture) {
362 bindings.addTexture(reflectionSampler, QRhiShaderResourceBinding::FragmentStage, reflectionTexture, sampler);
363 samplerBindingsSpecified.setBit(reflectionSampler);
364 }
365 } else if (shaderPipeline->lightProbeTexture()) {
366 int binding = shaderPipeline->bindingForTexture("qt_lightProbe", int(QSSGRhiSamplerBindingHints::LightProbe));
367 if (binding >= 0) {
368 samplerBindingsSpecified.setBit(binding);
369 QPair<QSSGRenderTextureCoordOp, QSSGRenderTextureCoordOp> tiling = shaderPipeline->lightProbeTiling();
371 QSSGRhiHelpers::toRhi(tiling.first), QSSGRhiHelpers::toRhi(tiling.second), QRhiSampler::Repeat });
372 bindings.addTexture(binding,
374 shaderPipeline->lightProbeTexture(), sampler);
375 } // else ignore, not an error (for example, an unshaded material's fragment shader will not have this sampler)
376 }
377
378 if (shaderPipeline->screenTexture()) {
379 const int screenTextureBinding = shaderPipeline->bindingForTexture("qt_screenTexture", int(QSSGRhiSamplerBindingHints::ScreenTexture));
380 const int screenTextureArrayBinding = shaderPipeline->bindingForTexture("qt_screenTextureArray", int(QSSGRhiSamplerBindingHints::ScreenTextureArray));
381 if (screenTextureBinding >= 0 || screenTextureArrayBinding >= 0) {
382 // linear min/mag, mipmap filtering depends on the
383 // texture, with SCREEN_TEXTURE there are no mipmaps, but
384 // once SCREEN_MIP_TEXTURE is seen the texture (the same
385 // one) has mipmaps generated.
386 QRhiSampler::Filter mipFilter = shaderPipeline->screenTexture()->flags().testFlag(QRhiTexture::MipMapped)
390 if (screenTextureBinding >= 0) {
391 samplerBindingsSpecified.setBit(screenTextureBinding);
392 bindings.addTexture(screenTextureBinding,
394 shaderPipeline->screenTexture(), sampler);
395 }
396 if (screenTextureArrayBinding >= 0) {
397 samplerBindingsSpecified.setBit(screenTextureArrayBinding);
398 bindings.addTexture(screenTextureArrayBinding,
400 shaderPipeline->screenTexture(), sampler);
401 }
402 } // else ignore, not an error
403 }
404
405 if (shaderPipeline->depthTexture()) {
406 const int depthTextureBinding = shaderPipeline->bindingForTexture("qt_depthTexture", int(QSSGRhiSamplerBindingHints::DepthTexture));
407 const int depthTextureArrayBinding = shaderPipeline->bindingForTexture("qt_depthTextureArray", int(QSSGRhiSamplerBindingHints::DepthTextureArray));
408 if (depthTextureBinding >= 0 || depthTextureArrayBinding >= 0) {
409 // nearest min/mag, no mipmap
412 if (depthTextureBinding >= 0) {
413 samplerBindingsSpecified.setBit(depthTextureBinding);
414 bindings.addTexture(depthTextureBinding,
416 shaderPipeline->depthTexture(), sampler);
417 }
418 if (depthTextureArrayBinding >= 0) {
419 samplerBindingsSpecified.setBit(depthTextureArrayBinding);
420 bindings.addTexture(depthTextureArrayBinding,
422 shaderPipeline->depthTexture(), sampler);
423 }
424 } // else ignore, not an error
425 }
426
427 if (shaderPipeline->ssaoTexture()) {
428 const int ssaoTextureBinding = shaderPipeline->bindingForTexture("qt_aoTexture", int(QSSGRhiSamplerBindingHints::AoTexture));
429 const int ssaoTextureArrayBinding = shaderPipeline->bindingForTexture("qt_aoTextureArray", int(QSSGRhiSamplerBindingHints::AoTextureArray));
430 if (ssaoTextureBinding >= 0 || ssaoTextureArrayBinding >= 0) {
431 // linear min/mag, no mipmap
434 if (ssaoTextureBinding >= 0) {
435 samplerBindingsSpecified.setBit(ssaoTextureBinding);
436 bindings.addTexture(ssaoTextureBinding,
438 shaderPipeline->ssaoTexture(), sampler);
439 }
440 if (ssaoTextureArrayBinding >= 0) {
441 samplerBindingsSpecified.setBit(ssaoTextureArrayBinding);
442 bindings.addTexture(ssaoTextureArrayBinding,
444 shaderPipeline->ssaoTexture(), sampler);
445 }
446 } // else ignore, not an error
447 }
448
449 if (shaderPipeline->lightmapTexture()) {
450 int binding = shaderPipeline->bindingForTexture("qt_lightmap", int(QSSGRhiSamplerBindingHints::LightmapTexture));
451 if (binding >= 0) {
452 samplerBindingsSpecified.setBit(binding);
455 bindings.addTexture(binding,
457 shaderPipeline->lightmapTexture(), sampler);
458 } // else ignore, not an error
459 }
460
461 const int shadowMapCount = shaderPipeline->shadowMapCount();
462 for (int i = 0; i < shadowMapCount; ++i) {
463 QSSGRhiShadowMapProperties &shadowMapProperties(shaderPipeline->shadowMapAt(i));
464 QRhiTexture *texture = shadowMapProperties.shadowMapTexture;
467 const QByteArray &name(shadowMapProperties.shadowMapTextureUniformName);
468 if (shadowMapProperties.cachedBinding < 0)
469 shadowMapProperties.cachedBinding = shaderPipeline->bindingForTexture(name);
470 if (shadowMapProperties.cachedBinding < 0) // may not be used in the shader with unshaded custom materials, that's normal
471 continue;
472 samplerBindingsSpecified.setBit(shadowMapProperties.cachedBinding);
473 bindings.addTexture(shadowMapProperties.cachedBinding,
475 texture,
476 sampler);
477 }
478
479 QSSGRenderableImage *renderableImage = renderable.firstImage;
480 while (renderableImage) {
481 const char *samplerName = QSSGMaterialShaderGenerator::getSamplerName(renderableImage->m_mapType);
482 const int samplerHint = int(renderableImage->m_mapType);
483 int samplerBinding = shaderPipeline->bindingForTexture(samplerName, samplerHint);
484 if (samplerBinding >= 0) {
485 QRhiTexture *texture = renderableImage->m_texture.m_texture;
486 if (samplerBinding >= 0 && texture) {
487 const bool mipmapped = texture->flags().testFlag(QRhiTexture::MipMapped);
488 QSSGRhiSamplerDescription samplerDesc = {
489 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_minFilterType),
490 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_magFilterType),
491 mipmapped ? QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_mipFilterType) : QRhiSampler::None,
492 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_horizontalTilingMode),
493 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_verticalTilingMode),
494 QSSGRhiHelpers::toRhi(renderableImage->m_imageNode.m_depthTilingMode)
495 };
496 rhiCtx->checkAndAdjustForNPoT(texture, &samplerDesc);
497 QRhiSampler *sampler = rhiCtx->sampler(samplerDesc);
498 samplerBindingsSpecified.setBit(samplerBinding);
499 bindings.addTexture(samplerBinding,
502 }
503 } // else this is not necessarily an error, e.g. having metalness/roughness maps with metalness disabled
504 renderableImage = renderableImage->m_nextImage;
505 }
506
507 if (maxSamplerBinding >= 0) {
508 // custom property textures
509 int customTexCount = shaderPipeline->extraTextureCount();
510 for (int i = 0; i < customTexCount; ++i) {
511 QSSGRhiTexture &t(shaderPipeline->extraTextureAt(i));
512 const int samplerBinding = shaderPipeline->bindingForTexture(t.name);
513 if (samplerBinding >= 0) {
514 samplerBindingsSpecified.setBit(samplerBinding);
515 rhiCtx->checkAndAdjustForNPoT(t.texture, &t.samplerDesc);
516 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
517 bindings.addTexture(samplerBinding,
519 t.texture,
520 sampler);
521 }
522 }
523
524 // use a dummy texture for the unused samplers in the shader
527
528 for (const QShaderDescription::InOutVariable &var : samplerVars) {
529 if (!samplerBindingsSpecified.testBit(var.binding)) {
530 QRhiTexture *t = var.type == QShaderDescription::SamplerCube ? dummyCubeTexture : dummyTexture;
531 bindings.addTexture(var.binding, CUSTOM_MATERIAL_VISIBILITY_ALL, t, dummySampler);
532 }
533 }
534 }
535
537
538 // do the same srb lookup acceleration as default materials
539 QRhiShaderResourceBindings *&srb = dcd.srb;
540 bool srbChanged = false;
541 if (!srb || bindings != dcd.bindings) {
542 srb = rhiCtxD->srb(bindings);
543 dcd.bindings = bindings;
544 srbChanged = true;
545 }
546
547 if (cubeFace == QSSGRenderTextureCubeFaceNone)
548 renderable.rhiRenderData.mainPass.srb = srb;
549 else
550 renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx] = srb;
551
552 const auto pipelineKey = QSSGGraphicsPipelineStateKey::create(*ps, renderPassDescriptor, srb);
553 if (dcd.pipeline
554 && !srbChanged
555 && dcd.renderTargetDescriptionHash == pipelineKey.extra.renderTargetDescriptionHash
556 && dcd.renderTargetDescription == pipelineKey.renderTargetDescription
557 && dcd.ps == *ps)
558 {
559 if (cubeFace == QSSGRenderTextureCubeFaceNone)
560 renderable.rhiRenderData.mainPass.pipeline = dcd.pipeline;
561 else
562 renderable.rhiRenderData.reflectionPass.pipeline = dcd.pipeline;
563 } else {
564 if (cubeFace == QSSGRenderTextureCubeFaceNone) {
565 renderable.rhiRenderData.mainPass.pipeline = rhiCtxD->pipeline(pipelineKey,
566 renderPassDescriptor,
567 srb);
568 dcd.pipeline = renderable.rhiRenderData.mainPass.pipeline;
569 } else {
570 renderable.rhiRenderData.reflectionPass.pipeline = rhiCtxD->pipeline(pipelineKey,
571 renderPassDescriptor,
572 srb);
573 dcd.pipeline = renderable.rhiRenderData.reflectionPass.pipeline;
574 }
575
576 dcd.renderTargetDescriptionHash = pipelineKey.extra.renderTargetDescriptionHash;
577 dcd.renderTargetDescription = pipelineKey.renderTargetDescription;
578 dcd.ps = *ps;
579 }
580 }
581}
582
583void QSSGCustomMaterialSystem::setShaderResources(char *ubufData,
584 const QSSGRenderCustomMaterial &inMaterial,
585 const QByteArray &inPropertyName,
586 const QVariant &propertyValue,
587 QSSGRenderShaderValue::Type inPropertyType,
588 QSSGRhiShaderPipeline &shaderPipeline)
589{
590 Q_UNUSED(inMaterial);
591
592 if (inPropertyType == QSSGRenderShaderValue::Texture) {
594 reinterpret_cast<QSSGRenderCustomMaterial::TextureProperty *>(propertyValue.value<void *>());
595 QSSGRenderImage *image = textureProperty->texImage;
596 if (image) {
597 const auto &theBufferManager(context->bufferManager());
598 const QSSGRenderImageTexture texture = theBufferManager->loadRenderImage(image);
599 if (texture.m_texture) {
600 const QSSGRhiTexture t = {
601 inPropertyName,
602 texture.m_texture,
603 { QSSGRhiHelpers::toRhi(textureProperty->minFilterType),
604 QSSGRhiHelpers::toRhi(textureProperty->magFilterType),
605 textureProperty->mipFilterType != QSSGRenderTextureFilterOp::None ? QSSGRhiHelpers::toRhi(textureProperty->mipFilterType) : QRhiSampler::None,
606 QSSGRhiHelpers::toRhi(textureProperty->horizontalClampType),
607 QSSGRhiHelpers::toRhi(textureProperty->verticalClampType),
608 QSSGRhiHelpers::toRhi(textureProperty->zClampType)
609 }
610 };
611 shaderPipeline.addExtraTexture(t);
612 }
613 }
614 } else {
615 shaderPipeline.setUniformValue(ubufData, inPropertyName, propertyValue, inPropertyType);
616 }
617}
618
620 const QSSGRenderCustomMaterial &material,
621 QSSGRhiShaderPipeline &shaderPipeline)
622{
623 const auto &properties = material.m_properties;
624 for (const auto &prop : properties)
625 setShaderResources(ubufData, material, prop.name, prop.value, prop.shaderDataType, shaderPipeline);
626
627 const auto textProps = material.m_textureProperties;
628 for (const auto &prop : textProps)
629 setShaderResources(ubufData, material, prop.name, QVariant::fromValue((void *)&prop), prop.shaderDataType, shaderPipeline);
630}
631
633 QSSGSubsetRenderable &renderable,
634 bool *needsSetViewport,
637{
638 QRhiGraphicsPipeline *ps = renderable.rhiRenderData.mainPass.pipeline;
639 QRhiShaderResourceBindings *srb = renderable.rhiRenderData.mainPass.srb;
640
641 if (cubeFace != QSSGRenderTextureCubeFaceNone) {
642 const auto cubeFaceIdx = QSSGBaseTypeHelpers::indexOfCubeFace(cubeFace);
643 ps = renderable.rhiRenderData.reflectionPass.pipeline;
644 srb = renderable.rhiRenderData.reflectionPass.srb[cubeFaceIdx];
645 }
646
647 if (!ps || !srb)
648 return;
649
650 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderCall);
651 QRhiBuffer *vertexBuffer = renderable.subset.rhi.vertexBuffer->buffer();
652 QRhiBuffer *indexBuffer = renderable.subset.rhi.indexBuffer ? renderable.subset.rhi.indexBuffer->buffer() : nullptr;
653
655 cb->setGraphicsPipeline(ps);
656 cb->setShaderResources(srb);
657
658 if (*needsSetViewport) {
659 cb->setViewport(state.viewport);
660 *needsSetViewport = false;
661 }
662
663 QRhiCommandBuffer::VertexInput vertexBuffers[2];
664 int vertexBufferCount = 1;
665 vertexBuffers[0] = QRhiCommandBuffer::VertexInput(vertexBuffer, 0);
666 quint32 instances = 1;
667 if (renderable.modelContext.model.instancing()) {
668 instances = renderable.modelContext.model.instanceCount();
669 vertexBuffers[1] = QRhiCommandBuffer::VertexInput(renderable.instanceBuffer, 0);
671 }
672 if (indexBuffer) {
673 cb->setVertexInput(0, vertexBufferCount, vertexBuffers, indexBuffer, 0, renderable.subset.rhi.indexBuffer->indexFormat());
674 cb->drawIndexed(renderable.subset.count, instances, renderable.subset.offset);
675 QSSGRHICTX_STAT(rhiCtx, drawIndexed(renderable.subset.count, instances));
676 } else {
677 cb->setVertexInput(0, vertexBufferCount, vertexBuffers);
678 cb->draw(renderable.subset.count, instances, renderable.subset.offset);
679 QSSGRHICTX_STAT(rhiCtx, draw(renderable.subset.count, instances));
680 }
681 Q_QUICK3D_PROFILE_END_WITH_IDS(QQuick3DProfiler::Quick3DRenderCall, (renderable.subset.count | quint64(instances) << 32),
682 QVector<int>({renderable.modelContext.model.profilingId,
683 renderable.material.profilingId}));
684}
685
\inmodule QtCore
Definition qbitarray.h:13
\inmodule QtCore
Definition qbytearray.h:57
\inmodule QtCore
iterator find(const Key &key)
Returns an iterator pointing to the item with the key in the hash.
Definition qhash.h:1291
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
void clear() noexcept(std::is_nothrow_destructible< Node >::value)
Removes all items from the hash and frees up all memory used by it.
Definition qhash.h:951
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
static FeatureSet toFeatureSet(const T &ssgFeatureSet)
\inmodule QtGui
Definition qrhi.h:846
\inmodule QtGui
Definition qrhi.h:1651
void resourceUpdate(QRhiResourceUpdateBatch *resourceUpdates)
Sometimes committing resource updates is necessary or just more convenient without starting a render ...
Definition qrhi.cpp:9384
QPair< QRhiBuffer *, quint32 > VertexInput
Synonym for QPair<QRhiBuffer *, quint32>.
Definition qrhi.h:1680
\inmodule QtGui
Definition qrhi.h:1270
\inmodule QtGui
Definition qrhi.h:1142
\inmodule QtGui
Definition qrhi.h:1731
QRhi * rhi() const
Definition qrhi.cpp:3603
\inmodule QtGui
Definition qrhi.h:1030
Filter
Specifies the minification, magnification, or mipmap filtering.
Definition qrhi.h:1032
@ ClampToEdge
Definition qrhi.h:1040
\inmodule QtGui
Definition qrhi.h:1214
\inmodule QtGui
Definition qrhi.h:895
@ MipMapped
Definition qrhi.h:900
@ CubeMap
Definition qrhi.h:899
Flags flags() const
Definition qrhi.h:992
QMatrix4x4 clipSpaceCorrMatrix() const
Definition qrhi.cpp:10091
QRhiResourceUpdateBatch * nextResourceUpdateBatch()
Definition qrhi.cpp:9252
static constexpr QSSGRenderTextureCubeFaceT indexOfCubeFace(QSSGRenderTextureCubeFace face) noexcept
void updateUniformsForCustomMaterial(QSSGRhiShaderPipeline &shaderPipeline, QSSGRhiContext *rhiCtx, const QSSGLayerRenderData &inData, char *ubufData, QSSGRhiGraphicsPipelineState *ps, const QSSGRenderCustomMaterial &material, QSSGSubsetRenderable &renderable, const QSSGRenderCameraList &cameras, const QVector2D *depthAdjust, const QMatrix4x4 *alteredModelViewProjection)
void rhiRenderRenderable(QSSGRhiContext *rhiCtx, QSSGSubsetRenderable &renderable, bool *needsSetViewport, QSSGRenderTextureCubeFace cubeFace, const QSSGRhiGraphicsPipelineState &state)
void applyRhiShaderPropertyValues(char *ubufData, const QSSGRenderCustomMaterial &inMaterial, QSSGRhiShaderPipeline &shaderPipeline)
void setRenderContextInterface(QSSGRenderContextInterface *inContext)
QSSGRhiShaderPipelinePtr shadersForCustomMaterial(QSSGRhiGraphicsPipelineState *ps, const QSSGRenderCustomMaterial &material, QSSGSubsetRenderable &renderable, const QSSGShaderDefaultMaterialKeyProperties &defaultMaterialShaderKeyProperties, const QSSGShaderFeatures &featureSet)
void rhiPrepareRenderable(QSSGRhiGraphicsPipelineState *ps, QSSGPassKey passKey, QSSGSubsetRenderable &renderable, const QSSGShaderFeatures &featureSet, const QSSGRenderCustomMaterial &material, const QSSGLayerRenderData &layerData, QRhiRenderPassDescriptor *renderPassDescriptor, int samples, int viewCount, QSSGRenderCamera *camera=nullptr, QSSGRenderTextureCubeFace cubeFace=QSSGRenderTextureCubeFaceNone, QMatrix4x4 *modelViewProjection=nullptr, QSSGReflectionMapEntry *entry=nullptr)
bool prepareForRender(const QSSGRenderModel &inModel, const QSSGRenderSubset &inSubset, QSSGRenderCustomMaterial &inMaterial)
static QSSGGraphicsPipelineStateKey create(const QSSGRhiGraphicsPipelineState &state, const QRhiRenderPassDescriptor *rpDesc, const QRhiShaderResourceBindings *srb)
static bool prepareInstancing(QSSGRhiContext *rhiCtx, QSSGSubsetRenderable *renderable, const QVector3D &cameraDirection, const QVector3D &cameraPosition, float minThreshold, float maxThreshold)
static void updateUniformsForParticleModel(QSSGRhiShaderPipeline &shaderPipeline, char *ubufData, const QSSGRenderModel *model, quint32 offset)
static void prepareParticlesForModel(QSSGRhiShaderPipeline &shaderPipeline, QSSGRhiContext *rhiCtx, QSSGRhiShaderResourceBindingList &bindings, const QSSGRenderModel *model)
const std::unique_ptr< QSSGRhiContext > & rhiContext() const
const std::unique_ptr< QSSGProgramGenerator > & shaderProgramGenerator() const
const std::shared_ptr< QSSGShaderLibraryManager > & shaderLibraryManager() const
const std::unique_ptr< QSSGBufferManager > & bufferManager() const
const std::unique_ptr< QSSGShaderCache > & shaderCache() const
static QSSGRhiContextPrivate * get(QSSGRhiContext *q)
static QSSGRhiContextStats & get(QSSGRhiContext &rhiCtx)
\inmodule QtQuick3D
QRhiCommandBuffer * commandBuffer() const
QRhiTexture * dummyTexture(QRhiTexture::Flags flags, QRhiResourceUpdateBatch *rub, const QSize &size=QSize(64, 64), const QColor &fillColor=Qt::black, int arraySize=0)
void checkAndAdjustForNPoT(QRhiTexture *texture, QSSGRhiSamplerDescription *samplerDescription)
Adjusts samplerDescription's tiling and filtering modes based on the pixel size of texture.
QRhi * rhi() const
QRhiSampler * sampler(const QSSGRhiSamplerDescription &samplerDescription)
QRhiGraphicsPipeline::CullMode cullMode
QRhiGraphicsPipeline::TargetBlend targetBlend
void setUniformValue(char *ubufData, const char *name, const QVariant &value, QSSGRenderShaderValue::Type type)
void addExtraTexture(const QSSGRhiTexture &t)
void addUniformBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset=0, int size=0)
void addTexture(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
const_iterator cend() const noexcept
Definition qset.h:142
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:241
\inmodule QtCore
Definition qvariant.h:65
T value() const &
Definition qvariant.h:516
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
QSet< QString >::iterator it
direction
else opt state
[0]
QRhiGraphicsPipeline::CullMode toCullMode(QSSGCullFaceMode cullFaceMode)
void bakeVertexInputLocations(QSSGRhiInputAssemblerState *ia, const QSSGRhiShaderPipeline &shaders, int instanceBufferBinding)
QRhiSampler::Filter toRhi(QSSGRenderTextureFilterOp op)
Combined button and popup list for selecting options.
Definition image.cpp:4
static const QCssKnownValue properties[NumProperties - 1]
@ None
Definition qhash.cpp:531
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLsizei const GLfloat * v
[13]
GLsizei samples
GLuint sampler
const void GLsizei GLsizei stride
GLenum GLuint texture
GLuint name
GLuint entry
GLdouble GLdouble t
Definition qopenglext.h:243
const void GLsizei GLsizei GLint vertexBufferCount
#define Q_QUICK3D_PROFILE_START(Type)
#define Q_QUICK3D_PROFILE_END_WITH_ID(Type, Payload, POID)
#define Q_QUICK3D_PROFILE_END_WITH_IDS(Type, Payload, POIDs)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
QSSGDataView< T > toDataView(const T &type)
std::array< QMatrix4x4, 2 > QSSGRenderMvpArray
QSSGRenderTextureCubeFace
constexpr QSSGRenderTextureCubeFace QSSGRenderTextureCubeFaceNone
#define QSSGRHICTX_STAT(ctx, f)
std::shared_ptr< QSSGRhiShaderPipeline > QSSGRhiShaderPipelinePtr
static const QRhiShaderResourceBinding::StageFlags CUSTOM_MATERIAL_VISIBILITY_ALL
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define Q_UNUSED(x)
#define Q_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
#define Q_TRACE_POINT(provider, tracepoint,...)
Definition qtrace_p.h:232
unsigned int quint32
Definition qtypes.h:50
size_t quintptr
Definition qtypes.h:167
unsigned long long quint64
Definition qtypes.h:61
QTimer * timer
[3]
myFilter draw(painter, QPoint(0, 0), originalPixmap)
QByteArray generateSha() const
static const char * getSamplerName(QSSGRenderableImage::Type type)
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)
static void setRhiMaterialProperties(const QSSGRenderContextInterface &, QSSGRhiShaderPipeline &shaders, char *ubufData, QSSGRhiGraphicsPipelineState *inPipelineState, const QSSGRenderGraphObject &inMaterial, const QSSGShaderDefaultMaterialKey &inKey, const QSSGShaderDefaultMaterialKeyProperties &inProperties, const QSSGRenderCameraList &inCameras, const QSSGRenderMvpArray &inModelViewProjections, const QMatrix3x3 &inNormalMatrix, const QMatrix4x4 &inGlobalTransform, const QMatrix4x4 &clipSpaceCorrMatrix, const QMatrix4x4 &localInstanceTransform, const QMatrix4x4 &globalInstanceTransform, const QSSGDataView< float > &inMorphWeights, QSSGRenderableImage *inFirstImage, float inOpacity, const QSSGLayerRenderData &inRenderProperties, const QSSGShaderLightListView &inLights, const QSSGShaderReflectionProbe &reflectionProbe, bool receivesShadows, bool receivesReflections, const QVector2D *shadowDepthAdjust, QRhiTexture *lightmapTexture)
QRhiGraphicsPipeline::BlendFactor m_srcBlend
QSSGShaderMaterialAdapter * adapter
QRhiGraphicsPipeline::BlendFactor m_dstBlend
QRhiGraphicsPipeline::BlendFactor m_dstAlphaBlend
QRhiGraphicsPipeline::BlendFactor m_srcAlphaBlend
static void setShaderPipeline(QSSGRhiGraphicsPipelineState &ps, const QSSGRhiShaderPipeline *pipeline)
static const InputAssemblerState & get(const QSSGRhiGraphicsPipelineState &ps)
\variable QSSGRhiGraphicsPipelineState::depthFunc
constexpr bool isSet(Feature feature) const
quint32 getValue(QSSGDataView< quint32 > inDataStore) const