7#include <QtQuick3DRuntimeRender/private/qssgshadermaterialadapter_p.h>
9#include <ssg/qssgrenderextensions.h>
10#include <ssg/qssgrenderhelpers.h>
11#include <ssg/qssgrendercontextcore.h>
12#include <ssg/qquick3dextensionhelpers.h>
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
173
174
175
176
177
178
179
180
181
182
183
186
187
188
189
190
191
192
193
196
197
198
199
200
201
202
203
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
227static constexpr float g_vertexData[] = { -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
228 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f };
233void main()
234{
235 qt_inputUV = attr_uv;
236 gl_Position = vec4(attr_pos, 0.0, 1.0);
237}
238)";
241void main()
242{
243 qt_inputUV = attr_uv;
244 qt_inputUV.y = 1.0 - qt_inputUV.y;
245 gl_Position = vec4(attr_pos, 0.0, 1.0);
246}
247)";
250void main()
251{
252 qt_customMain();
253}
254)";
257void MAIN()
258{
259 FRAGCOLOR = vec4(1.0, 0.0, 1.0, 1.0);
260}
261)";
265 static const char *argKey =
"/*%QT_ARGS_MAIN%*/";
266 const int argKeyLen =
int(strlen(argKey));
267 const int argKeyPos = snippet.indexOf(argKey);
269 snippet = snippet.left(argKeyPos) + QByteArrayLiteral(
"inout vec3 VERTEX") + snippet.mid(argKeyPos + argKeyLen);
274QRhiTexture::Format rhiTextureFormatFromTextureDataFormat(QQuick3DTextureData::Format format)
277 case QQuick3DTextureData::RGBA8:
278 return QRhiTexture::Format::RGBA8;
279 case QQuick3DTextureData::RGBA16F:
280 return QRhiTexture::Format::RGBA16F;
281 case QQuick3DTextureData::RGBA32F:
282 return QRhiTexture::Format::RGBA32F;
283 case QQuick3DTextureData::RGBE8:
284 return QRhiTexture::Format::RGBA8;
285 case QQuick3DTextureData::R8:
286 return QRhiTexture::Format::R8;
287 case QQuick3DTextureData::R16:
288 return QRhiTexture::Format::R16;
289 case QQuick3DTextureData::R16F:
290 return QRhiTexture::Format::R16F;
291 case QQuick3DTextureData::R32F:
292 return QRhiTexture::Format::R32F;
294 return QRhiTexture::Format::RGBA8;
296 Q_UNREACHABLE_RETURN(QRhiTexture::Format::RGBA8);
299QByteArray generateFinalVertexShaderCode(QRhi *rhi,
300 QSSGShaderCustomMaterialAdapter::StringPairList uniforms,
301 QSSGShaderCustomMaterialAdapter::StringPairList varyings)
304 const bool doFlip = rhi->isYUpInNDC() && !rhi->isYUpInFramebuffer();
305 QByteArray vertexShader = doFlip ? mainVertexSnippetFlipped : mainVertexSnippet;
307 QSSGShaderCustomMaterialAdapter::ShaderCodeAndMetaData result;
309 QSSGShaderCustomMaterialAdapter::CustomShaderPrepWorkData scratch;
310 QSSGShaderCustomMaterialAdapter::beginPrepareCustomShader(&scratch, &result, vertexShader, QSSGShaderCache::ShaderType::Vertex,
false);
311 QSSGShaderCustomMaterialAdapter::finishPrepareCustomShader(&buf,
314 QSSGShaderCache::ShaderType::Vertex,
321 insertVertexMainArgs(result.first);
322 return result.first + buf;
325QByteArray generateFinalFragmentShaderCode(
const QByteArray &baseFragmentShaderCode,
326 QSSGShaderCustomMaterialAdapter::StringPairList uniforms,
327 QSSGShaderCustomMaterialAdapter::StringPairList varyings)
329 QSSGShaderCustomMaterialAdapter::ShaderCodeAndMetaData result;
331 QSSGShaderCustomMaterialAdapter::CustomShaderPrepWorkData scratch;
332 QSSGShaderCustomMaterialAdapter::beginPrepareCustomShader(&scratch, &result, baseFragmentShaderCode, QSSGShaderCache::ShaderType::Fragment,
false);
333 QSSGShaderCustomMaterialAdapter::finishPrepareCustomShader(&buf,
336 QSSGShaderCache::ShaderType::Fragment,
343 return result.first + buf;
346QSSGRhiShaderPipelinePtr compileShader(QSSGRenderContextInterface *sgContext,
347 const QByteArray &shaderPathKey,
348 const QByteArray &vertexShader,
349 const QByteArray &fragmentShader)
351 QSSGProgramGenerator *generator = sgContext->shaderProgramGenerator().get();
352 QSSGShaderLibraryManager *shaderLib = sgContext->shaderLibraryManager().get();
353 QSSGShaderCache *shaderCache = sgContext->shaderCache().get();
355 generator->beginProgram();
356 auto vertex = generator->getStage(QSSGShaderGeneratorStage::Vertex);
357 vertex->addIncoming(
"attr_pos",
"vec2");
358 vertex->addIncoming(
"attr_uv",
"vec2");
359 vertex->append(vertexShader);
361 generator->getStage(QSSGShaderGeneratorStage::Fragment)->append(fragmentShader);
363 QSSGShaderFeatures features;
364 const QByteArray key = shaderPathKey +
':'
365 + QCryptographicHash::hash(QByteArray(vertexShader + fragmentShader), QCryptographicHash::Algorithm::Sha1)
367 return generator->compileGeneratedRhiShader(key, features, *shaderLib, *shaderCache, QSSGRhiShaderPipeline::UsedWithoutIa, { }, 1,
false);
379 void render(QSSGFrameData &data)
override;
393 QPointer<QQuick3DQuadTextureProvider> m_ext;
395 QSSGRhiShaderResourceBindingList m_srbBindings;
396 QSSGRhiShaderPipelinePtr m_shaderPipeline;
398 std::unique_ptr<QRhiBuffer> m_vertexBuffer;
399 std::unique_ptr<QRhiBuffer> m_indexBuffer;
401 std::unique_ptr<QRhiTexture> m_outputTexture;
402 std::unique_ptr<QRhiTexture> m_outputTextureOld;
403 std::unique_ptr<QRhiTextureRenderTarget> m_renderTarget;
404 std::unique_ptr<QRhiRenderPassDescriptor> m_renderPassDesc;
406 std::unique_ptr<QRhiGraphicsPipeline> m_graphicsPipeline;
407 QRhiShaderResourceBindings* m_srb =
nullptr;
416 QSSGRenderContextInterface *ctxIfx = data.contextInterface();
417 auto bufferManager = ctxIfx->bufferManager().get();
418 QSSGRhiContext *rhiCtx = ctxIfx->rhiContext().get();
422 QSSGExtensionId extensionId = m_ext ? QQuick3DExtensionHelpers::getExtensionId(*m_ext) : QSSGExtensionId { };
423 if (QQuick3DExtensionHelpers::isNull(extensionId))
427 bool needsRebuild =
false;
428 if (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Dimensions)
430 if (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Format)
432 if (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::FragmentShader)
434 if (m_shaderPipeline && !needsRebuild)
435 return dirtyFlag & QQuick3DQuadTextureProvider::Dirty::TrackedProperty;
437 if (!m_shaderPipeline || dirtyFlag & QQuick3DQuadTextureProvider::Dirty::FragmentShader) {
441 for (
const auto &u : std::as_const(propertyUniforms)) {
442 if (u.shaderDataType == QSSGRenderShaderValue::Texture) {
443 QSSGRenderImage *image = u.value.value<QSSGRenderImage *>();
444 const QSSGRenderImageTexture texture = image ? bufferManager->loadRenderImage(image) : QSSGRenderImageTexture { };
445 if (!image || !texture.m_texture) {
451 QByteArray fragmentShaderCode = (!fragmentShaderSource.isEmpty() ? fragmentShaderSource : fallbackFragmentShaderStr)
452 + mainFragmentSnippet;
454 QSSGShaderCustomMaterialAdapter::StringPairList baseUniforms;
455 for (
const auto &u : std::as_const(propertyUniforms))
456 baseUniforms.append({ u.typeName, u.name });
458 baseUniforms.append({
"vec2",
"qt_outputSize" });
460 QSSGShaderCustomMaterialAdapter::StringPairList baseInputOutputs;
461 baseInputOutputs.append({
"vec2",
"qt_inputUV" });
463 QByteArray vertexShader = generateFinalVertexShaderCode(rhiCtx->rhi(), baseUniforms, baseInputOutputs);
464 QByteArray fragmentShader = generateFinalFragmentShaderCode(fragmentShaderCode, baseUniforms, baseInputOutputs);
466 QSSGRenderContextInterface *sgContext = data.contextInterface();
468 m_shaderPipeline = compileShader(sgContext, shaderPathKey, vertexShader, fragmentShader);
471 if (!m_shaderPipeline) {
472 fragmentShaderCode = fallbackFragmentShaderStr + mainFragmentSnippet;
473 fragmentShader = generateFinalFragmentShaderCode(fragmentShaderCode, baseUniforms, baseInputOutputs);
474 m_shaderPipeline = compileShader(sgContext, shaderPathKey, vertexShader, fragmentShader);
478 QRhi *rhi = rhiCtx->rhi();
480 if (!m_outputTexture || dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Dimensions
481 || dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Format) {
493 m_outputTextureOld = std::move(m_outputTexture);
494 m_outputTexture.reset(rhi->newTexture(rhiTextureFormatFromTextureDataFormat(format), QSize(width, height), 1, QRhiTexture::RenderTarget));
495 m_outputTexture->create();
497 m_renderTarget.reset(rhi->newTextureRenderTarget({ m_outputTexture.get() }));
498 m_renderPassDesc.reset(m_renderTarget->newCompatibleRenderPassDescriptor());
499 m_renderTarget->setRenderPassDescriptor(m_renderPassDesc.get());
500 m_renderTarget->create();
502 QSSGRenderExtensionHelpers::registerRenderResult(data, extensionId, m_outputTexture.get());
504 m_graphicsPipeline.reset();
512 QSSGRenderContextInterface *ctxIfx = data.contextInterface();
513 QSSGRhiContext *rhiCtx = ctxIfx->rhiContext().get();
514 if (!rhiCtx || !m_shaderPipeline)
517 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
518 QRhi *rhi = rhiCtx->rhi();
520 QSSGRhiDrawCallData *dcd = &rhiCtxD->drawCallData({ (
void *)
this,
nullptr,
nullptr, 0 });
522 const int uniformStride = rhiCtx->rhi()->ubufAligned(m_shaderPipeline->ub0Size());
523 dcd->ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, uniformStride);
527 const bool trackedPropertyDirty = dirtyFlag & QQuick3DQuadTextureProvider::Dirty::TrackedProperty;
528 const bool dimensionsDirty = dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Dimensions;
529 const bool pipelineDirty = !m_graphicsPipeline || (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Format)
530 || (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::FragmentShader);
532 const bool srbDirty = pipelineDirty || trackedPropertyDirty || !m_srb;
535 if (trackedPropertyDirty || dimensionsDirty) {
537 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
539 if (trackedPropertyDirty) {
541 m_shaderPipeline->resetExtraTextures();
543 QSSGBufferManager *bufferManager = ctxIfx->bufferManager().get();
545 for (
const auto &u : std::as_const(propertyUniforms)) {
546 m_shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
550 if (dimensionsDirty) {
551 m_shaderPipeline->setUniformValue(ubufData,
"qt_outputSize", QVector2D(width, height), QSSGRenderShaderValue::Vec2);
553 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
557 if (!m_vertexBuffer && !m_indexBuffer) {
559 m_vertexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, 5 * 4 *
sizeof(
float)));
560 m_vertexBuffer->create();
563 m_indexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, 6 *
sizeof(uint16_t)));
564 m_indexBuffer->create();
565 QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
566 updates->uploadStaticBuffer(m_vertexBuffer.get(),
g_vertexData);
567 updates->uploadStaticBuffer(m_indexBuffer.get(), g_indexData);
568 rhiCtx->commandBuffer()->resourceUpdate(updates);
573 rhiCtxD->releaseCachedSrb(m_srbBindings);
574 m_srbBindings = QSSGRhiShaderResourceBindingList();
575 m_srbBindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, dcd->ubuf);
578 int maxSamplerBinding = -1;
579 QVector<QShaderDescription::InOutVariable> samplerVars = m_shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
580 for (
const QShaderDescription::InOutVariable &var :
581 m_shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
582 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(), [&var](
const QShaderDescription::InOutVariable &v) {
583 return var.binding == v.binding;
585 if (it == samplerVars.cend())
586 samplerVars.append(var);
588 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
589 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
591 if (maxSamplerBinding >= 0) {
593 int customTexCount = m_shaderPipeline->extraTextureCount();
594 for (
int i = 0; i < customTexCount; ++i) {
595 const QSSGRhiTexture &t(m_shaderPipeline->extraTextureAt(i));
596 const int samplerBinding = m_shaderPipeline->bindingForTexture(t.name);
597 if (samplerBinding >= 0) {
598 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
599 m_srbBindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, t.texture, sampler);
604 m_srb = rhiCtxD->srb(m_srbBindings);
610 m_graphicsPipeline.reset(rhi->newGraphicsPipeline());
611 m_graphicsPipeline->setShaderStages({ *m_shaderPipeline->vertexStage(), *m_shaderPipeline->fragmentStage() });
614 QRhiVertexInputLayout inputLayout;
615 inputLayout.setBindings({ { 5 *
sizeof(
float) } });
616 inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
617 { 0, 1, QRhiVertexInputAttribute::Float2, 3 *
sizeof(
float) } });
618 m_graphicsPipeline->setVertexInputLayout(inputLayout);
619 m_graphicsPipeline->setShaderResourceBindings(m_srb);
620 m_graphicsPipeline->setRenderPassDescriptor(m_renderPassDesc.get());
622 m_graphicsPipeline->create();
630 const auto &ctxIfx = data.contextInterface();
631 const auto &rhiCtx = ctxIfx->rhiContext();
635 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
636 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D Quad Texture Provider"));
638 cb->beginPass(m_renderTarget.get(), Qt::transparent, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
639 cb->setViewport(QRhiViewport(0, 0,
width,
height));
642 cb->setGraphicsPipeline(m_graphicsPipeline.get());
644 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
645 auto srb = rhiCtxD->srb(m_srbBindings);
646 cb->setShaderResources(srb);
648 QRhiCommandBuffer::VertexInput vb(m_vertexBuffer.get(), 0);
649 cb->setVertexInput(0, 1, &vb, m_indexBuffer.get(), QRhiCommandBuffer::IndexFormat::IndexUInt16);
658 m_outputTextureOld.reset();
662 : QQuick3DTextureProviderExtension(parent)
663 , QQuick3DPropertyChangedTracker(
this, QQuick3DSuperClassInfo<QQuick3DQuadTextureProvider>())
677 if (m_dirtyFlag & Dirty::Dimensions) {
679 n->height = m_height;
682 if (m_dirtyFlag & Dirty::Format)
683 n->format = m_format;
685 if (m_dirtyFlag & Dirty::FragmentShader) {
686 const QQmlContext *context = qmlContext(
this);
687 n->fragmentShaderSource = !m_fragmentShaderCode.isEmpty() ? m_fragmentShaderCode.toUtf8()
688 : !m_fragmentShader.isEmpty() ? QSSGShaderUtils::resolveShader(m_fragmentShader, context, n->shaderPathKey)
692 if (m_dirtyFlag & Dirty::TrackedProperty) {
693 n->propertyUniforms = extractProperties();
696 if (m_dirtyFlag != 0)
697 emit surfaceChanged();
699 n->dirtyFlag = m_dirtyFlag;
709 markDirty(Dirty::TrackedProperty);
720 return m_fragmentShader;
725 if (m_fragmentShader == newFragmentShader)
727 m_fragmentShader = newFragmentShader;
728 emit fragmentShaderChanged();
729 markDirty(Dirty::FragmentShader);
734 return m_fragmentShaderCode;
739 if (m_fragmentShaderCode == newFragmentShaderCode)
741 m_fragmentShaderCode = newFragmentShaderCode;
742 emit fragmentShaderCodeChanged();
743 markDirty(Dirty::FragmentShader);
754 newWidth = qMax(1, newWidth);
755 if (m_width == newWidth)
759 markDirty(Dirty::Dimensions);
769 newHeight = qMax(1, newHeight);
770 if (m_height == newHeight)
772 m_height = newHeight;
773 emit heightChanged();
774 markDirty(Dirty::Dimensions);
784 if (m_format == newFormat)
786 m_format = newFormat;
787 emit formatChanged();
788 markDirty(Dirty::Format);
QSSGQuadTextureProvider(QQuick3DQuadTextureProvider *ext)
void render(QSSGFrameData &data) override
Record the render pass.
QList< QSSGBaseTypeProperty > propertyUniforms
QQuick3DQuadTextureProvider::DirtyT dirtyFlag
void prepareRender(QSSGFrameData &data) override
Prepare data for rendering.
QByteArray fragmentShaderSource
void resetForFrame() override
Called each time a new frame starts.
bool prepareData(QSSGFrameData &data) override
Called after scene data is collected, but before any render data or rendering in the current frame ha...
~QSSGQuadTextureProvider() override
QQuick3DTextureData::Format format
Combined button and popup list for selecting options.
static const QByteArray mainVertexSnippet
static const QByteArray mainFragmentSnippet
static const QByteArray fallbackFragmentShaderStr
static constexpr uint16_t g_indexData[]
static QT_BEGIN_NAMESPACE constexpr float g_vertexData[]
\qmltype QuadTextureProvider \nativetype QQuick3DQuadTextureProvider \inqmlmodule QtQuick3D....
static void insertVertexMainArgs(QByteArray &snippet)
static const QByteArray mainVertexSnippetFlipped