Qt 6.x
The Qt SDK
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
qssgrhieffectsystem.cpp
Go to the documentation of this file.
1// Copyright (C) 2008-2012 NVIDIA Corporation.
2// Copyright (C) 2020 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
4
5#include <QtQuick3DRuntimeRender/private/qssgrhieffectsystem_p.h>
6#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
7#include <QtQuick3DRuntimeRender/private/qssgrhiquadrenderer_p.h>
8#include <QtQuick3DRuntimeRender/private/qssgrendercontextcore_p.h>
9#include <qtquick3d_tracepoints_p.h>
10
11#include <QtQuick3DUtils/private/qssgassert_p.h>
12
13#include <QtCore/qloggingcategory.h>
14
16
18Q_LOGGING_CATEGORY(lcEffectSystem, "qt.quick3d.effects");
19
21{
22 QRhiTexture *texture = nullptr;
26
29
31 {
32 delete texture;
34 delete renderTarget;
35 }
37};
38
39QSSGRhiEffectSystem::QSSGRhiEffectSystem(const std::shared_ptr<QSSGRenderContextInterface> &sgContext)
40 : m_sgContext(sgContext)
41{
42}
43
45{
46 releaseResources();
47}
48
50{
51 if (outputSize.isEmpty()) {
52 releaseResources();
53 return;
54 }
55 m_outSize = outputSize;
56}
57
58QSSGRhiEffectTexture *QSSGRhiEffectSystem::findTexture(const QByteArray &bufferName)
59{
60 auto findTexture = [bufferName](const QSSGRhiEffectTexture *rt){ return rt->name == bufferName; };
61 const auto foundIt = std::find_if(m_textures.cbegin(), m_textures.cend(), findTexture);
62 QSSGRhiEffectTexture *result = foundIt == m_textures.cend() ? nullptr : *foundIt;
63 return result;
64}
65
66QSSGRhiEffectTexture *QSSGRhiEffectSystem::getTexture(const QByteArray &bufferName,
67 const QSize &size,
69 bool isFinalOutput,
70 const QSSGRenderEffect *inEffect)
71{
72 QSSGRhiEffectTexture *result = findTexture(bufferName);
73 const bool gotMatch = result != nullptr;
74
75 // If not found, look for an unused texture
76 if (!result) {
77 // ### This could be enhanced to try to find a texture with the right
78 // size/format/flags first. It is not essential because the texture will be
79 // recreated below if the size or format does not match, but it would
80 // be more optimal (for Effects with Buffers with sizeMultipliers on
81 // them, or ones that use different formats) to look for a matching
82 // size/format too instead of picking the first unused texture.
83 auto findUnused = [](const QSSGRhiEffectTexture *rt){ return rt->name.isEmpty(); };
84 const auto found = std::find_if(m_textures.cbegin(), m_textures.cend(), findUnused);
85 if (found != m_textures.cend()) {
86 result = *found;
87 result->desc = {};
88 }
89 }
90
91 if (!result) {
93 m_textures.append(result);
94 }
95
96 QRhi *rhi = m_sgContext->rhi();
97 const bool formatChanged = result->texture && result->texture->format() != format;
98 const bool needsRebuild = result->texture && (result->texture->pixelSize() != size || formatChanged);
99
100 QRhiTexture::Flags flags = QRhiTexture::RenderTarget;
101 if (isFinalOutput) // play nice with progressive/temporal AA
103
104 if (!result->texture) {
105 result->texture = rhi->newTexture(format, size, 1, flags);
106 result->texture->create();
107 } else if (needsRebuild) {
108 result->texture->setFlags(flags);
109 result->texture->setPixelSize(size);
110 result->texture->setFormat(format);
111 result->texture->create();
112 }
113
114 if (!result->renderTarget) {
115 result->renderTarget = rhi->newTextureRenderTarget({ result->texture });
117 result->renderTarget->setRenderPassDescriptor(result->renderPassDescriptor);
118 result->renderTarget->create();
119 m_pendingClears.insert(result->renderTarget);
120 } else if (needsRebuild) {
121 if (formatChanged) {
122 delete result->renderPassDescriptor;
123 result->renderPassDescriptor = result->renderTarget->newCompatibleRenderPassDescriptor();
124 result->renderTarget->setRenderPassDescriptor(result->renderPassDescriptor);
125 }
126 result->renderTarget->create();
127 m_pendingClears.insert(result->renderTarget);
128 }
129
130 if (!gotMatch) {
131 QByteArray rtName = inEffect->debugObjectName.toLatin1();
132 rtName += QByteArrayLiteral(" effect pass ");
133 rtName += bufferName;
134 result->renderTarget->setName(rtName);
135 }
136
137 result->name = bufferName;
138 return result;
139}
140
141void QSSGRhiEffectSystem::releaseTexture(QSSGRhiEffectTexture *texture)
142{
143 // Mark as unused by setting the name to empty, unless the Buffer had scene
144 // lifetime on it (then it needs to live on for ever).
145 if (!texture->flags.isSceneLifetime())
146 texture->name = {};
147}
148
149void QSSGRhiEffectSystem::releaseTextures()
150{
151 for (auto *t : std::as_const(m_textures))
152 releaseTexture(t);
153}
154
156 QRhiTexture *inTexture,
157 QRhiTexture *inDepthTexture,
158 QVector2D cameraClipRange)
159{
160 QSSG_ASSERT(m_sgContext != nullptr, return inTexture);
161 const auto &rhiContext = m_sgContext->rhiContext();
162 const auto &renderer = m_sgContext->renderer();
163 QSSG_ASSERT(rhiContext && renderer, return inTexture);
164
165 m_depthTexture = inDepthTexture;
166 m_cameraClipRange = cameraClipRange;
167
168 m_currentUbufIndex = 0;
169 auto *currentEffect = &firstEffect;
170 QSSGRhiEffectTexture firstTex{ inTexture, nullptr, nullptr, {}, {}, {} };
171 auto *latestOutput = doRenderEffect(currentEffect, &firstTex);
172 firstTex.texture = nullptr; // make sure we don't delete inTexture when we go out of scope
173
174 while ((currentEffect = currentEffect->m_nextEffect)) {
175 auto *effectOut = doRenderEffect(currentEffect, latestOutput);
176 releaseTexture(latestOutput);
177 latestOutput = effectOut;
178 }
179
180 releaseTextures();
181 return latestOutput ? latestOutput->texture : nullptr;
182}
183
184void QSSGRhiEffectSystem::releaseResources()
185{
186 qDeleteAll(m_textures);
187 m_textures.clear();
188
189 m_shaderPipelines.clear();
190}
191
193{
195 for (const QSSGRenderEffect::Command &c : inEffect->commands) {
196 QSSGCommand *cmd = c.command;
197 if (cmd->m_type == CommandType::BindTarget) {
198 QSSGBindTarget *targetCmd = static_cast<QSSGBindTarget *>(cmd);
200 ? inEffect->outputFormat : targetCmd->m_outputFormat.format;
201 }
202 }
203 return format;
204}
205
206QSSGRhiEffectTexture *QSSGRhiEffectSystem::doRenderEffect(const QSSGRenderEffect *inEffect,
207 QSSGRhiEffectTexture *inTexture)
208{
209 // Run through the effect commands and render the effect.
210 qCDebug(lcEffectSystem) << "START effect " << inEffect->className;
211 QSSGRhiEffectTexture *finalOutputTexture = nullptr;
212 QSSGRhiEffectTexture *currentOutput = nullptr;
213 QSSGRhiEffectTexture *currentInput = inTexture;
214 for (const QSSGRenderEffect::Command &c : inEffect->commands) {
215 QSSGCommand *theCommand = c.command;
216 qCDebug(lcEffectSystem).noquote() << " >" << theCommand->typeAsString() << "--" << theCommand->debugString();
217
218 switch (theCommand->m_type) {
220 allocateBufferCmd(static_cast<QSSGAllocateBuffer *>(theCommand), inTexture, inEffect);
221 break;
222
224 auto *applyCommand = static_cast<QSSGApplyBufferValue *>(theCommand);
225
226 /*
227 BufferInput { buffer: buf }
228 -> INPUT (qt_inputTexture) in the shader samples the texture for Buffer buf in the pass
229 BufferInput { sampler: "ttt" }
230 -> ttt in the shader samples the input texture for the pass
231 (ttt also needs to be a TextureInput with a Texture{} to get the sampler declared in the shader code,
232 beware that without the BufferInput the behavior would change: ttt would then sample a dummy texture)
233 BufferInput { buffer: buf; sampler: "ttt" }
234 -> ttt in the shader samples the texture for Buffer buf in the pass
235 */
236
237 auto *buffer = applyCommand->m_bufferName.isEmpty() ? inTexture : findTexture(applyCommand->m_bufferName);
238 if (applyCommand->m_samplerName.isEmpty())
239 currentInput = buffer;
240 else
241 addTextureToShaderPipeline(applyCommand->m_samplerName, buffer->texture, buffer->desc);
242 break;
243 }
244
246 applyInstanceValueCmd(static_cast<QSSGApplyInstanceValue *>(theCommand), inEffect);
247 break;
248
250 applyValueCmd(static_cast<QSSGApplyValue *>(theCommand), inEffect);
251 break;
252
254 auto *bindCmd = static_cast<QSSGBindBuffer *>(theCommand);
255 currentOutput = findTexture(bindCmd->m_bufferName);
256 break;
257 }
258
260 bindShaderCmd(static_cast<QSSGBindShader *>(theCommand), inEffect);
261 break;
262
264 auto targetCmd = static_cast<QSSGBindTarget*>(theCommand);
265 // matches overriddenOutputFormat()
267 inEffect->outputFormat : targetCmd->m_outputFormat.format;
268 // f is now either Unknown (common case), or if the effect overrides the output format, then that
271 qCDebug(lcEffectSystem) << " Target format override" << QSSGBaseTypeHelpers::toString(f) << "Effective RHI format" << rhiFormat;
272 // Make sure we use different names for each effect inside one frame
273 QByteArray tmpName = QByteArrayLiteral("__output_").append(QByteArray::number(m_currentUbufIndex));
274 currentOutput = getTexture(tmpName, m_outSize, rhiFormat, true, inEffect);
275 finalOutputTexture = currentOutput;
276 break;
277 }
278
280 renderCmd(currentInput, currentOutput);
281 currentInput = inTexture; // default input for each new pass is defined to be original input
282 break;
283
284 default:
285 qWarning() << "Effect command" << theCommand->typeAsString() << "not implemented";
286 break;
287 }
288 }
289 // TODO: release textures used by this effect now, instead of after processing all the effects
290 qCDebug(lcEffectSystem) << "END effect " << inEffect->className;
291 return finalOutputTexture;
292}
293
294void QSSGRhiEffectSystem::allocateBufferCmd(const QSSGAllocateBuffer *inCmd, QSSGRhiEffectTexture *inTexture, const QSSGRenderEffect *inEffect)
295{
296 // Note: Allocate is used both to allocate new, and refer to buffer created earlier
297 QSize bufferSize(m_outSize * qreal(inCmd->m_sizeMultiplier));
298
302
303 QSSGRhiEffectTexture *buf = getTexture(inCmd->m_name, bufferSize, rhiFormat, false, inEffect);
304 auto filter = toRhi(inCmd->m_filterOp);
305 auto tiling = toRhi(inCmd->m_texCoordOp);
306 buf->desc = { filter, filter, QRhiSampler::None, tiling, tiling, QRhiSampler::Repeat };
307 buf->flags = inCmd->m_bufferFlags;
308}
309
310void QSSGRhiEffectSystem::applyInstanceValueCmd(const QSSGApplyInstanceValue *inCmd, const QSSGRenderEffect *inEffect)
311{
312 if (!m_currentShaderPipeline)
313 return;
314
315 const bool setAll = inCmd->m_propertyName.isEmpty();
316 for (const QSSGRenderEffect::Property &property : std::as_const(inEffect->properties)) {
317 if (setAll || property.name == inCmd->m_propertyName) {
318 m_currentShaderPipeline->setUniformValue(m_currentUBufData, property.name, property.value, property.shaderDataType);
319 //qCDebug(lcEffectSystem) << "setUniformValue" << property.name << toString(property.shaderDataType) << "to" << property.value;
320 }
321 }
322 for (const QSSGRenderEffect::TextureProperty &textureProperty : std::as_const(inEffect->textureProperties)) {
323 if (setAll || textureProperty.name == inCmd->m_propertyName) {
324 bool texAdded = false;
325 QSSGRenderImage *image = textureProperty.texImage;
326 if (image) {
327 const auto &theBufferManager(m_sgContext->bufferManager());
328 const QSSGRenderImageTexture texture = theBufferManager->loadRenderImage(image);
329 if (texture.m_texture) {
331 toRhi(textureProperty.minFilterType),
332 toRhi(textureProperty.magFilterType),
333 textureProperty.mipFilterType != QSSGRenderTextureFilterOp::None ? toRhi(textureProperty.mipFilterType) : QRhiSampler::None,
334 toRhi(textureProperty.horizontalClampType),
335 toRhi(textureProperty.verticalClampType),
337 };
338 addTextureToShaderPipeline(textureProperty.name, texture.m_texture, desc);
339 texAdded = true;
340 }
341 }
342 if (!texAdded) {
343 // Something went wrong, e.g. image file not found. Still need to add a dummy texture for the shader
344 qCDebug(lcEffectSystem) << "Using dummy texture for property" << textureProperty.name;
345 addTextureToShaderPipeline(textureProperty.name, nullptr, {});
346 }
347 }
348 }
349}
350
351void QSSGRhiEffectSystem::applyValueCmd(const QSSGApplyValue *inCmd, const QSSGRenderEffect *inEffect)
352{
353 if (!m_currentShaderPipeline)
354 return;
355
356 const auto &properties = inEffect->properties;
357 const auto foundIt = std::find_if(properties.cbegin(), properties.cend(), [inCmd](const QSSGRenderEffect::Property &prop) {
358 return (prop.name == inCmd->m_propertyName);
359 });
360
361 if (foundIt != properties.cend())
362 m_currentShaderPipeline->setUniformValue(m_currentUBufData, inCmd->m_propertyName, inCmd->m_value, foundIt->shaderDataType);
363 else
364 qWarning() << "Could not find effect property" << inCmd->m_propertyName;
365}
366
367static const char *effect_builtin_textureMapUV =
368 "vec2 qt_effectTextureMapUV(vec2 uv)\n"
369 "{\n"
370 " return uv;\n"
371 "}\n";
372
374 "vec2 qt_effectTextureMapUV(vec2 uv)\n"
375 "{\n"
376 " return vec2(uv.x, 1.0 - uv.y);\n"
377 "}\n";
378
381 QSSGShaderLibraryManager &shaderLib,
382 QSSGShaderCache &shaderCache,
383 bool isYUpInFramebuffer)
384{
385 const auto &key = inCmd.m_shaderPathKey;
386 qCDebug(lcEffectSystem) << " generating new shader pipeline for: " << key;
387
388 generator.beginProgram();
389
390 {
393 // The variation based on isYUpInFramebuffer is captured in 'key' as
394 // well, so it is safe to vary the source code here.
396 vStage->append(src);
397 }
398 {
401 fStage->append(src);
402 }
403
404 return generator.compileGeneratedRhiShader(key,
406 shaderLib,
407 shaderCache,
409}
410
411void QSSGRhiEffectSystem::bindShaderCmd(const QSSGBindShader *inCmd, const QSSGRenderEffect *inEffect)
412{
414 timer.start();
415
416 m_currentTextures.clear();
417 m_pendingClears.clear();
418 m_currentShaderPipeline = nullptr;
419
420 QRhi *rhi = m_sgContext->rhi();
421 const auto &shaderLib = m_sgContext->shaderLibraryManager();
422 const auto &shaderCache = m_sgContext->shaderCache();
423
424 // Now we need a proper unique key (unique in the scene), the filenames are
425 // not sufficient. This means that using the same shader source files in
426 // multiple Effects in the same scene will work. It wouldn't if all those
427 // Effects reused the same QSSGRhiShaderPipeline (i.e. if the only cache
428 // key was the m_shaderPathKey).
430 cacheKey.m_shaderPathKey = inCmd->m_shaderPathKey;
431 cacheKey.m_cmd = quintptr(inCmd);
432 cacheKey.m_ubufIndex = m_currentUbufIndex;
433 cacheKey.updateHashCode();
434
435 // look for a runtime pipeline
436 const auto it = m_shaderPipelines.constFind(cacheKey);
437 if (it != m_shaderPipelines.cend())
438 m_currentShaderPipeline = (*it).get();
439
440 QByteArray qsbcKey;
441 QSSGShaderFeatures features;
442 if (!m_currentShaderPipeline) { // don't spend time if already got the pipeline
443 features = shaderLib->getShaderMetaData(inCmd->m_shaderPathKey, QSSGShaderCache::ShaderType::Fragment).features;
445 }
446
447 // Check if there's a build-time generated entry for this effect
448 if (!m_currentShaderPipeline && !shaderLib->m_preGeneratedShaderEntries.isEmpty()) {
449 const QQsbCollection::EntryMap &pregenEntries = shaderLib->m_preGeneratedShaderEntries;
450 const auto foundIt = pregenEntries.constFind(QQsbCollection::Entry(qsbcKey));
451 if (foundIt != pregenEntries.cend()) {
452 // The result here is always a new QSSGRhiShaderPipeline, which
453 // fulfills the requirements of our local cache (cmd/ubufIndex in
454 // cacheKey, not needed here since the result is a new object).
455 const auto &shader = shaderCache->newPipelineFromPregenerated(inCmd->m_shaderPathKey,
456 features,
457 *foundIt,
458 *inEffect,
460 m_shaderPipelines.insert(cacheKey, shader);
461 m_currentShaderPipeline = shader.get();
462 }
463 }
464
465 if (!m_currentShaderPipeline) {
466 // Try the persistent (disk-based) cache then. The result here is
467 // always a new QSSGRhiShaderPipeline, which fulfills the requirements
468 // of our local cache (cmd/ubufIndex in cacheKey, not needed here since
469 // the result is a new object). Alternatively, the result may be null
470 // if there was no hit.
471 const auto &shaderPipeline = shaderCache->tryNewPipelineFromPersistentCache(qsbcKey,
472 inCmd->m_shaderPathKey,
473 features,
475 if (shaderPipeline) {
476 m_shaderPipelines.insert(cacheKey, shaderPipeline);
477 m_currentShaderPipeline = shaderPipeline.get();
478 }
479 }
480
481 if (!m_currentShaderPipeline) {
482 // Final option, generate the shader pipeline
483 Q_TRACE_SCOPE(QSSG_generateShader);
484 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DGenerateShader);
485 const auto &generator = m_sgContext->shaderProgramGenerator();
486 if (auto stages = buildShaderForEffect(*inCmd, *generator, *shaderLib, *shaderCache, rhi->isYUpInFramebuffer())) {
487 m_shaderPipelines.insert(cacheKey, stages);
488 m_currentShaderPipeline = stages.get();
489 }
490 Q_QUICK3D_PROFILE_END_WITH_ID(QQuick3DProfiler::Quick3DGenerateShader, 0, inEffect->profilingId);
491 }
492
493 const auto &rhiContext = m_sgContext->rhiContext();
494
495 if (m_currentShaderPipeline) {
496 const void *cacheKey1 = reinterpret_cast<const void *>(this);
497 const void *cacheKey2 = reinterpret_cast<const void *>(qintptr(m_currentUbufIndex));
498 QSSGRhiDrawCallData &dcd = rhiContext->drawCallData({ cacheKey1, cacheKey2, nullptr, 0, QSSGRhiDrawCallDataKey::Effects });
499 m_currentShaderPipeline->ensureCombinedMainLightsUniformBuffer(&dcd.ubuf);
500 m_currentUBufData = dcd.ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
501 } else {
502 m_currentUBufData = nullptr;
503 }
504
505 rhiContext->stats().registerEffectShaderGenerationTime(timer.elapsed());
506}
507
508void QSSGRhiEffectSystem::renderCmd(QSSGRhiEffectTexture *inTexture, QSSGRhiEffectTexture *target)
509{
510 if (!m_currentShaderPipeline)
511 return;
512
513 if (!target) {
514 qWarning("No effect render target?");
515 return;
516 }
517
518 addTextureToShaderPipeline(QByteArrayLiteral("qt_inputTexture"), inTexture->texture, inTexture->desc);
519
520 const auto &rhiContext = m_sgContext->rhiContext();
521 const auto &renderer = m_sgContext->renderer();
522
523 QRhiCommandBuffer *cb = rhiContext->commandBuffer();
524 cb->debugMarkBegin(QByteArrayLiteral("Post-processing effect"));
525 Q_QUICK3D_PROFILE_START(QQuick3DProfiler::Quick3DRenderPass);
526
527 for (QRhiTextureRenderTarget *rt : m_pendingClears) {
528 // Effects like motion blur use an accumulator texture that should
529 // start out empty (and they are sampled in the first pass), so such
530 // textures need an explicit clear. It is not applicable for the common
531 // case of outputting into a texture because that will get a clear
532 // anyway when rendering the quad.
533 if (rt != target->renderTarget) {
534 cb->beginPass(rt, Qt::transparent, { 1.0f, 0 }, nullptr, QSSGRhiContext::commonPassFlags());
535 QSSGRHICTX_STAT(rhiContext, beginRenderPass(rt));
536 cb->endPass();
537 QSSGRHICTX_STAT(rhiContext, endRenderPass());
538 }
539 }
540 m_pendingClears.clear();
541
542 const QSize inputSize = inTexture->texture->pixelSize();
543 const QSize outputSize = target->texture->pixelSize();
544 addCommonEffectUniforms(inputSize, outputSize);
545
546 const void *cacheKey1 = reinterpret_cast<const void *>(this);
547 const void *cacheKey2 = reinterpret_cast<const void *>(qintptr(m_currentUbufIndex));
548 QSSGRhiDrawCallData &dcd = rhiContext->drawCallData({ cacheKey1, cacheKey2, nullptr, 0, QSSGRhiDrawCallDataKey::Effects });
550 m_currentUBufData = nullptr;
551
552 QRhiResourceUpdateBatch *rub = rhiContext->rhi()->nextResourceUpdateBatch();
553 renderer->rhiQuadRenderer()->prepareQuad(rhiContext.get(), rub);
554
555 // do resource bindings
556 const QRhiShaderResourceBinding::StageFlags VISIBILITY_ALL =
559 for (const QSSGRhiTexture &rhiTex : m_currentTextures) {
560 int binding = m_currentShaderPipeline->bindingForTexture(rhiTex.name);
561 if (binding < 0) // may not be used in the shader (think qt_inputTexture, it's not given a shader samples INPUT)
562 continue;
563 qCDebug(lcEffectSystem) << " -> texture binding" << binding << "for" << rhiTex.name;
564 // Make sure to bind all samplers even if the texture is missing, otherwise we can get crash on some graphics APIs
565 QRhiTexture *texture = rhiTex.texture ? rhiTex.texture : rhiContext->dummyTexture({}, rub);
566 bindings.addTexture(binding,
568 texture,
569 rhiContext->sampler(rhiTex.samplerDesc));
570 }
571 bindings.addUniformBuffer(0, VISIBILITY_ALL, dcd.ubuf);
572 QRhiShaderResourceBindings *srb = rhiContext->srb(bindings);
573
575 ps.viewport = QRhiViewport(0, 0, float(outputSize.width()), float(outputSize.height()));
576 ps.shaderPipeline = m_currentShaderPipeline;
577
578 renderer->rhiQuadRenderer()->recordRenderQuadPass(rhiContext.get(), &ps, srb, target->renderTarget, QSSGRhiQuadRenderer::UvCoords);
579 m_currentUbufIndex++;
580 cb->debugMarkEnd();
581 Q_QUICK3D_PROFILE_END_WITH_STRING(QQuick3DProfiler::Quick3DRenderPass, 0, QByteArrayLiteral("post_processing_effect"));
582}
583
584void QSSGRhiEffectSystem::addCommonEffectUniforms(const QSize &inputSize, const QSize &outputSize)
585{
586 const auto &rhiContext = m_sgContext->rhiContext();
587 QRhi *rhi = rhiContext->rhi();
588
589 QMatrix4x4 mvp;
590 if (rhi->isYUpInFramebuffer() != rhi->isYUpInNDC())
591 mvp.data()[5] = -1.0f;
592 m_currentShaderPipeline->setUniformValue(m_currentUBufData, "qt_modelViewProjection", mvp, QSSGRenderShaderDataType::Matrix4x4);
593
594 QVector2D size(inputSize.width(), inputSize.height());
595 m_currentShaderPipeline->setUniformValue(m_currentUBufData, "qt_inputSize", size, QSSGRenderShaderDataType::Vec2);
596
597 size = QVector2D(outputSize.width(), outputSize.height());
598 m_currentShaderPipeline->setUniformValue(m_currentUBufData, "qt_outputSize", size, QSSGRenderShaderDataType::Vec2);
599
600 float fc = float(m_sgContext->frameCount());
601 m_currentShaderPipeline->setUniformValue(m_currentUBufData, "qt_frame_num", fc, QSSGRenderShaderDataType::Float);
602
603 // Bames and values for uniforms that are also used by default and/or
604 // custom materials must always match, effects must not deviate.
605
606 m_currentShaderPipeline->setUniformValue(m_currentUBufData, "qt_cameraProperties", m_cameraClipRange, QSSGRenderShaderDataType::Vec2);
607
608 float vp = rhi->isYUpInFramebuffer() ? 1.0f : -1.0f;
609 m_currentShaderPipeline->setUniformValue(m_currentUBufData, "qt_normalAdjustViewportFactor", vp, QSSGRenderShaderDataType::Float);
610
611 const float nearClip = rhi->isClipDepthZeroToOne() ? 0.0f : -1.0f;
612 m_currentShaderPipeline->setUniformValue(m_currentUBufData, "qt_nearClipValue", nearClip, QSSGRenderShaderDataType::Float);
613
614 if (m_depthTexture) {
615 static const QSSGRhiSamplerDescription depthSamplerDesc {
619 };
620 addTextureToShaderPipeline("qt_depthTexture", m_depthTexture, depthSamplerDesc);
621 }
622}
623
624void QSSGRhiEffectSystem::addTextureToShaderPipeline(const QByteArray &name,
626 const QSSGRhiSamplerDescription &samplerDescription)
627{
628 if (!m_currentShaderPipeline)
629 return;
630
633 bool validDescription = samplerDescription.magFilter != QRhiSampler::None;
634
635 // This is a map for a reason: there can be multiple calls to this function
636 // for the same 'name', with a different 'texture', take the last value
637 // into account only.
638 m_currentTextures.insert(name, { name, texture, validDescription ? samplerDescription : defaultDescription});
639}
640
\inmodule QtCore
Definition qbytearray.h:57
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
\inmodule QtCore
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1279
const_iterator cend() const noexcept
Definition qhash.h:1208
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:949
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
The QMatrix4x4 class represents a 4x4 transformation matrix in 3D space.
Definition qmatrix4x4.h:25
float * data()
Returns a pointer to the raw data of this matrix.
static FeatureSet toFeatureSet(const T &ssgFeatureSet)
virtual char * beginFullDynamicBufferUpdateForCurrentFrame()
Definition qrhi.cpp:3844
virtual void endFullDynamicBufferUpdateForCurrentFrame()
To be called when the entire contents of the buffer data has been updated in the memory block returne...
Definition qrhi.cpp:3854
\inmodule QtGui
Definition qrhi.h:1614
\inmodule QtGui
Definition qrhi.h:1119
virtual QRhiRenderPassDescriptor * newCompatibleRenderPassDescriptor() const =0
QRhiRenderPassDescriptor * renderPassDescriptor() const
Definition qrhi.h:1141
\inmodule QtGui
Definition qrhi.h:1694
\inmodule QtGui
Definition qrhi.h:1007
@ ClampToEdge
Definition qrhi.h:1017
\inmodule QtGui
Definition qrhi.h:1190
\inmodule QtGui
Definition qrhi.h:1161
\inmodule QtGui
Definition qrhi.h:883
Format format() const
Definition qrhi.h:960
@ UsedAsTransferSource
Definition qrhi.h:890
@ RenderTarget
Definition qrhi.h:886
virtual bool create()=0
Creates the corresponding native graphics resources.
Format
Specifies the texture format.
Definition qrhi.h:902
QSize pixelSize() const
Definition qrhi.h:963
\inmodule QtGui
Definition qrhi.h:85
\inmodule QtGui
Definition qrhi.h:1767
bool isClipDepthZeroToOne() const
Definition qrhi.cpp:9640
bool isYUpInFramebuffer() const
Definition qrhi.cpp:9601
bool isYUpInNDC() const
Definition qrhi.cpp:9615
QRhiTextureRenderTarget * newTextureRenderTarget(const QRhiTextureRenderTargetDescription &desc, QRhiTextureRenderTarget::Flags flags={})
Definition qrhi.cpp:10245
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10133
static const char * toString(QSSGRenderTextureCubeFace value)
static QRhiTexture::Format toRhiFormat(const QSSGRenderTextureFormat format)
static QRhiCommandBuffer::BeginPassFlags commonPassFlags()
QRhiTexture * process(const QSSGRenderEffect &firstEffect, QRhiTexture *inTexture, QRhiTexture *inDepthTexture, QVector2D cameraClipRange)
void setup(QSize outputSize)
static QSSGRenderTextureFormat::Format overriddenOutputFormat(const QSSGRenderEffect *inEffect)
static QSSGRhiShaderPipelinePtr buildShaderForEffect(const QSSGBindShader &inCmd, QSSGProgramGenerator &generator, QSSGShaderLibraryManager &shaderLib, QSSGShaderCache &shaderCache, bool isYUpInFramebuffer)
QSSGRhiEffectSystem(const std::shared_ptr< QSSGRenderContextInterface > &sgContext)
void setUniformValue(char *ubufData, const char *name, const QVariant &value, QSSGRenderShaderDataType type)
void ensureCombinedMainLightsUniformBuffer(QRhiBuffer **ubuf)
int bindingForTexture(const char *name, int hint=-1)
QSSGCustomShaderMetaData getShaderMetaData(const QByteArray &inShaderPathKey, QSSGShaderCache::ShaderType type)
QByteArray getShaderSource(const QByteArray &inShaderPathKey, QSSGShaderCache::ShaderType type)
const_iterator cend() const noexcept
Definition qset.h:142
void clear()
Definition qset.h:61
const_iterator constFind(const T &value) const
Definition qset.h:161
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qsize.h:25
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:123
QByteArray toLatin1() const &
Definition qstring.h:559
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition qtimer.cpp:208
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
qDeleteAll(list.begin(), list.end())
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ transparent
Definition qnamespace.h:46
Definition image.cpp:4
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
static const QCssKnownValue properties[NumProperties - 1]
@ Repeat
#define qWarning
Definition qlogging.h:162
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLbitfield stages
GLuint64 key
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLsizei const GLubyte * commands
GLfloat GLfloat f
GLenum src
GLenum GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum target
GLbitfield flags
GLenum GLuint texture
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLuint name
GLint GLsizei GLsizei GLenum format
const GLubyte * c
GLuint shader
Definition qopenglext.h:665
GLdouble GLdouble t
Definition qopenglext.h:243
GLuint64EXT * result
[6]
#define Q_QUICK3D_PROFILE_START(Type)
#define Q_QUICK3D_PROFILE_END_WITH_ID(Type, Payload, POID)
#define Q_QUICK3D_PROFILE_END_WITH_STRING(Type, Payload, Str)
#define QSSG_ASSERT(cond, action)
#define QSSGRHICTX_STAT(ctx, f)
std::shared_ptr< QSSGRhiShaderPipeline > QSSGRhiShaderPipelinePtr
QRhiSampler::Filter toRhi(QSSGRenderTextureFilterOp op)
static const char * effect_builtin_textureMapUVFlipped
static const char * effect_builtin_textureMapUV
static QT_BEGIN_NAMESPACE const QRhiShaderResourceBinding::StageFlags 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_TRACE_SCOPE(x,...)
Definition qtrace_p.h:146
@ desc
size_t quintptr
Definition qtypes.h:72
double qreal
Definition qtypes.h:92
ptrdiff_t qintptr
Definition qtypes.h:71
const char property[13]
Definition qwizard.cpp:101
QRandomGenerator generator(sseq)
QObject::connect nullptr
QTimer * timer
[3]
QSvgRenderer * renderer
[0]
QByteArray generateSha() const
QSSGRenderTextureFormat m_format
QSSGRenderTextureFilterOp m_filterOp
QSSGRenderTextureCoordOp m_texCoordOp
QSSGAllocateBufferFlags m_bufferFlags
QSSGRenderTextureFormat m_outputFormat
const char * typeAsString() const
QString debugString() const
QVector< Command > commands
QSSGRenderTextureFormat::Format outputFormat
QVector< Property > properties
QSSGRhiSamplerDescription desc
QRhiRenderPassDescriptor * renderPassDescriptor
QSSGAllocateBufferFlags flags
QRhiTextureRenderTarget * renderTarget
QSSGRhiEffectTexture & operator=(const QSSGRhiEffectTexture &)=delete
const QSSGRhiShaderPipeline * shaderPipeline
QRhiSampler::Filter magFilter
void addUniformBuffer(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiBuffer *buf, int offset, int size)
void addTexture(int binding, QRhiShaderResourceBinding::StageFlags stage, QRhiTexture *tex, QRhiSampler *sampler)
virtual void append(const QByteArray &data)