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
150
151
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
175
176
177
178
179
180
181
182
183
184
185
188
189
190
191
192
193
194
195
198
199
200
201
202
203
204
205
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
229static constexpr float g_vertexData[] = { -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
230 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f };
235void main()
236{
237 qt_inputUV = attr_uv;
238 gl_Position = vec4(attr_pos, 0.0, 1.0);
239}
240)";
243void main()
244{
245 qt_inputUV = attr_uv;
246 qt_inputUV.y = 1.0 - qt_inputUV.y;
247 gl_Position = vec4(attr_pos, 0.0, 1.0);
248}
249)";
252void main()
253{
254 qt_customMain();
255}
256)";
259void MAIN()
260{
261 FRAGCOLOR = vec4(1.0, 0.0, 1.0, 1.0);
262}
263)";
267 static const char *argKey =
"/*%QT_ARGS_MAIN%*/";
268 const int argKeyLen =
int(strlen(argKey));
269 const int argKeyPos = snippet.indexOf(argKey);
271 snippet = snippet.left(argKeyPos) + QByteArrayLiteral(
"inout vec3 VERTEX") + snippet.mid(argKeyPos + argKeyLen);
276QRhiTexture::Format rhiTextureFormatFromTextureDataFormat(QQuick3DTextureData::Format format)
279 case QQuick3DTextureData::RGBA8:
280 return QRhiTexture::Format::RGBA8;
281 case QQuick3DTextureData::RGBA16F:
282 return QRhiTexture::Format::RGBA16F;
283 case QQuick3DTextureData::RGBA32F:
284 return QRhiTexture::Format::RGBA32F;
285 case QQuick3DTextureData::RGBE8:
286 return QRhiTexture::Format::RGBA8;
287 case QQuick3DTextureData::R8:
288 return QRhiTexture::Format::R8;
289 case QQuick3DTextureData::R16:
290 return QRhiTexture::Format::R16;
291 case QQuick3DTextureData::R16F:
292 return QRhiTexture::Format::R16F;
293 case QQuick3DTextureData::R32F:
294 return QRhiTexture::Format::R32F;
296 return QRhiTexture::Format::RGBA8;
298 Q_UNREACHABLE_RETURN(QRhiTexture::Format::RGBA8);
301QByteArray generateFinalVertexShaderCode(QRhi *rhi,
302 QSSGShaderCustomMaterialAdapter::StringPairList uniforms,
303 QSSGShaderCustomMaterialAdapter::StringPairList varyings)
306 const bool doFlip = rhi->isYUpInNDC() && !rhi->isYUpInFramebuffer();
307 QByteArray vertexShader = doFlip ? mainVertexSnippetFlipped : mainVertexSnippet;
309 QSSGShaderCustomMaterialAdapter::ShaderCodeAndMetaData result;
311 QSSGShaderCustomMaterialAdapter::CustomShaderPrepWorkData scratch;
312 QSSGShaderCustomMaterialAdapter::beginPrepareCustomShader(&scratch, &result, vertexShader, QSSGShaderCache::ShaderType::Vertex,
false);
313 QSSGShaderCustomMaterialAdapter::finishPrepareCustomShader(&buf,
316 QSSGShaderCache::ShaderType::Vertex,
323 insertVertexMainArgs(result.first);
324 return result.first + buf;
327QByteArray generateFinalFragmentShaderCode(
const QByteArray &baseFragmentShaderCode,
328 QSSGShaderCustomMaterialAdapter::StringPairList uniforms,
329 QSSGShaderCustomMaterialAdapter::StringPairList varyings)
331 QSSGShaderCustomMaterialAdapter::ShaderCodeAndMetaData result;
333 QSSGShaderCustomMaterialAdapter::CustomShaderPrepWorkData scratch;
334 QSSGShaderCustomMaterialAdapter::beginPrepareCustomShader(&scratch, &result, baseFragmentShaderCode, QSSGShaderCache::ShaderType::Fragment,
false);
335 QSSGShaderCustomMaterialAdapter::finishPrepareCustomShader(&buf,
338 QSSGShaderCache::ShaderType::Fragment,
345 return result.first + buf;
348QSSGRhiShaderPipelinePtr compileShader(QSSGRenderContextInterface *sgContext,
349 const QByteArray &shaderPathKey,
350 const QByteArray &vertexShader,
351 const QByteArray &fragmentShader)
353 QSSGProgramGenerator *generator = sgContext->shaderProgramGenerator().get();
354 QSSGShaderLibraryManager *shaderLib = sgContext->shaderLibraryManager().get();
355 QSSGShaderCache *shaderCache = sgContext->shaderCache().get();
357 generator->beginProgram();
358 auto vertex = generator->getStage(QSSGShaderGeneratorStage::Vertex);
359 vertex->addIncoming(
"attr_pos",
"vec2");
360 vertex->addIncoming(
"attr_uv",
"vec2");
361 vertex->append(vertexShader);
363 generator->getStage(QSSGShaderGeneratorStage::Fragment)->append(fragmentShader);
365 QSSGShaderFeatures features;
366 const QByteArray key = shaderPathKey +
':'
367 + QCryptographicHash::hash(QByteArray(vertexShader + fragmentShader), QCryptographicHash::Algorithm::Sha1)
369 return generator->compileGeneratedRhiShader(key, features, *shaderLib, *shaderCache, QSSGRhiShaderPipeline::UsedWithoutIa, { }, 1,
false);
381 void render(QSSGFrameData &data)
override;
395 QPointer<QQuick3DQuadTextureProvider> m_ext;
397 QSSGRhiShaderResourceBindingList m_srbBindings;
398 QSSGRhiShaderPipelinePtr m_shaderPipeline;
400 std::unique_ptr<QRhiBuffer> m_vertexBuffer;
401 std::unique_ptr<QRhiBuffer> m_indexBuffer;
403 std::unique_ptr<QRhiTexture> m_outputTexture;
404 std::unique_ptr<QRhiTexture> m_outputTextureOld;
405 std::unique_ptr<QRhiTextureRenderTarget> m_renderTarget;
406 std::unique_ptr<QRhiRenderPassDescriptor> m_renderPassDesc;
408 std::unique_ptr<QRhiGraphicsPipeline> m_graphicsPipeline;
409 QRhiShaderResourceBindings* m_srb =
nullptr;
418 QSSGRenderContextInterface *ctxIfx = data.contextInterface();
419 auto bufferManager = ctxIfx->bufferManager().get();
420 QSSGRhiContext *rhiCtx = ctxIfx->rhiContext().get();
424 QSSGExtensionId extensionId = m_ext ? QQuick3DExtensionHelpers::getExtensionId(*m_ext) : QSSGExtensionId { };
425 if (QQuick3DExtensionHelpers::isNull(extensionId))
429 bool needsRebuild =
false;
430 if (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Dimensions)
432 if (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Format)
434 if (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::FragmentShader)
436 if (m_shaderPipeline && !needsRebuild)
437 return dirtyFlag & QQuick3DQuadTextureProvider::Dirty::TrackedProperty;
439 if (!m_shaderPipeline || dirtyFlag & QQuick3DQuadTextureProvider::Dirty::FragmentShader) {
443 for (
const auto &u : std::as_const(propertyUniforms)) {
444 if (u.shaderDataType == QSSGRenderShaderValue::Texture) {
445 QSSGRenderImage *image = u.value.value<QSSGRenderImage *>();
446 const QSSGRenderImageTexture texture = image ? bufferManager->loadRenderImage(image) : QSSGRenderImageTexture { };
447 if (!image || !texture.m_texture) {
453 QByteArray fragmentShaderCode = (!fragmentShaderSource.isEmpty() ? fragmentShaderSource : fallbackFragmentShaderStr)
454 + mainFragmentSnippet;
456 QSSGShaderCustomMaterialAdapter::StringPairList baseUniforms;
457 for (
const auto &u : std::as_const(propertyUniforms))
458 baseUniforms.append({ u.typeName, u.name });
460 baseUniforms.append({
"vec2",
"qt_outputSize" });
462 QSSGShaderCustomMaterialAdapter::StringPairList baseInputOutputs;
463 baseInputOutputs.append({
"vec2",
"qt_inputUV" });
465 QByteArray vertexShader = generateFinalVertexShaderCode(rhiCtx->rhi(), baseUniforms, baseInputOutputs);
466 QByteArray fragmentShader = generateFinalFragmentShaderCode(fragmentShaderCode, baseUniforms, baseInputOutputs);
468 QSSGRenderContextInterface *sgContext = data.contextInterface();
470 m_shaderPipeline = compileShader(sgContext, shaderPathKey, vertexShader, fragmentShader);
473 if (!m_shaderPipeline) {
474 fragmentShaderCode = fallbackFragmentShaderStr + mainFragmentSnippet;
475 fragmentShader = generateFinalFragmentShaderCode(fragmentShaderCode, baseUniforms, baseInputOutputs);
476 m_shaderPipeline = compileShader(sgContext, shaderPathKey, vertexShader, fragmentShader);
480 QRhi *rhi = rhiCtx->rhi();
482 if (!m_outputTexture || dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Dimensions
483 || dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Format) {
495 m_outputTextureOld = std::move(m_outputTexture);
496 m_outputTexture.reset(rhi->newTexture(rhiTextureFormatFromTextureDataFormat(format), QSize(width, height), 1, QRhiTexture::RenderTarget));
497 m_outputTexture->create();
499 m_renderTarget.reset(rhi->newTextureRenderTarget({ m_outputTexture.get() }));
500 m_renderPassDesc.reset(m_renderTarget->newCompatibleRenderPassDescriptor());
501 m_renderTarget->setRenderPassDescriptor(m_renderPassDesc.get());
502 m_renderTarget->create();
504 QSSGRenderExtensionHelpers::registerRenderResult(data, extensionId, m_outputTexture.get());
506 m_graphicsPipeline.reset();
514 QSSGRenderContextInterface *ctxIfx = data.contextInterface();
515 QSSGRhiContext *rhiCtx = ctxIfx->rhiContext().get();
516 if (!rhiCtx || !m_shaderPipeline)
519 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx);
520 QRhi *rhi = rhiCtx->rhi();
522 QSSGRhiDrawCallData *dcd = &rhiCtxD->drawCallData({ (
void *)
this,
nullptr,
nullptr, 0 });
524 const int uniformStride = rhiCtx->rhi()->ubufAligned(m_shaderPipeline->ub0Size());
525 dcd->ubuf = rhiCtx->rhi()->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, uniformStride);
529 const bool trackedPropertyDirty = dirtyFlag & QQuick3DQuadTextureProvider::Dirty::TrackedProperty;
530 const bool dimensionsDirty = dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Dimensions;
531 const bool pipelineDirty = !m_graphicsPipeline || (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::Format)
532 || (dirtyFlag & QQuick3DQuadTextureProvider::Dirty::FragmentShader);
534 const bool srbDirty = pipelineDirty || trackedPropertyDirty || !m_srb;
537 if (trackedPropertyDirty || dimensionsDirty) {
539 char *ubufData = dcd->ubuf->beginFullDynamicBufferUpdateForCurrentFrame();
541 if (trackedPropertyDirty) {
543 m_shaderPipeline->resetExtraTextures();
545 QSSGBufferManager *bufferManager = ctxIfx->bufferManager().get();
547 for (
const auto &u : std::as_const(propertyUniforms)) {
548 m_shaderPipeline->setShaderResources(ubufData, *bufferManager, u.name, u.value, u.shaderDataType);
552 if (dimensionsDirty) {
553 m_shaderPipeline->setUniformValue(ubufData,
"qt_outputSize", QVector2D(width, height), QSSGRenderShaderValue::Vec2);
555 dcd->ubuf->endFullDynamicBufferUpdateForCurrentFrame();
559 if (!m_vertexBuffer && !m_indexBuffer) {
561 m_vertexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, 5 * 4 *
sizeof(
float)));
562 m_vertexBuffer->create();
565 m_indexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, 6 *
sizeof(uint16_t)));
566 m_indexBuffer->create();
567 QRhiResourceUpdateBatch *updates = rhi->nextResourceUpdateBatch();
568 updates->uploadStaticBuffer(m_vertexBuffer.get(),
g_vertexData);
569 updates->uploadStaticBuffer(m_indexBuffer.get(), g_indexData);
570 rhiCtx->commandBuffer()->resourceUpdate(updates);
575 rhiCtxD->releaseCachedSrb(m_srbBindings);
576 m_srbBindings = QSSGRhiShaderResourceBindingList();
577 m_srbBindings.addUniformBuffer(0, QRhiShaderResourceBinding::FragmentStage, dcd->ubuf);
580 int maxSamplerBinding = -1;
581 QVector<QShaderDescription::InOutVariable> samplerVars = m_shaderPipeline->fragmentStage()->shader().description().combinedImageSamplers();
582 for (
const QShaderDescription::InOutVariable &var :
583 m_shaderPipeline->vertexStage()->shader().description().combinedImageSamplers()) {
584 auto it = std::find_if(samplerVars.cbegin(), samplerVars.cend(), [&var](
const QShaderDescription::InOutVariable &v) {
585 return var.binding == v.binding;
587 if (it == samplerVars.cend())
588 samplerVars.append(var);
590 for (
const QShaderDescription::InOutVariable &var : std::as_const(samplerVars))
591 maxSamplerBinding = qMax(maxSamplerBinding, var.binding);
593 if (maxSamplerBinding >= 0) {
595 int customTexCount = m_shaderPipeline->extraTextureCount();
596 for (
int i = 0; i < customTexCount; ++i) {
597 const QSSGRhiTexture &t(m_shaderPipeline->extraTextureAt(i));
598 const int samplerBinding = m_shaderPipeline->bindingForTexture(t.name);
599 if (samplerBinding >= 0) {
600 QRhiSampler *sampler = rhiCtx->sampler(t.samplerDesc);
601 m_srbBindings.addTexture(samplerBinding, QRhiShaderResourceBinding::FragmentStage, t.texture, sampler);
606 m_srb = rhiCtxD->srb(m_srbBindings);
612 m_graphicsPipeline.reset(rhi->newGraphicsPipeline());
613 m_graphicsPipeline->setShaderStages({ *m_shaderPipeline->vertexStage(), *m_shaderPipeline->fragmentStage() });
616 QRhiVertexInputLayout inputLayout;
617 inputLayout.setBindings({ { 5 *
sizeof(
float) } });
618 inputLayout.setAttributes({ { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
619 { 0, 1, QRhiVertexInputAttribute::Float2, 3 *
sizeof(
float) } });
620 m_graphicsPipeline->setVertexInputLayout(inputLayout);
621 m_graphicsPipeline->setShaderResourceBindings(m_srb);
622 m_graphicsPipeline->setRenderPassDescriptor(m_renderPassDesc.get());
624 m_graphicsPipeline->create();
632 const auto &ctxIfx = data.contextInterface();
633 const auto &rhiCtx = ctxIfx->rhiContext();
637 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
638 cb->debugMarkBegin(QByteArrayLiteral(
"Quick3D Quad Texture Provider"));
640 cb->beginPass(m_renderTarget.get(), Qt::transparent, { 1.0f, 0 },
nullptr, rhiCtx->commonPassFlags());
641 cb->setViewport(QRhiViewport(0, 0,
width,
height));
644 cb->setGraphicsPipeline(m_graphicsPipeline.get());
646 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(rhiCtx.get());
647 auto srb = rhiCtxD->srb(m_srbBindings);
648 cb->setShaderResources(srb);
650 QRhiCommandBuffer::VertexInput vb(m_vertexBuffer.get(), 0);
651 cb->setVertexInput(0, 1, &vb, m_indexBuffer.get(), QRhiCommandBuffer::IndexFormat::IndexUInt16);
660 m_outputTextureOld.reset();
664 : QQuick3DTextureProviderExtension(parent)
665 , QQuick3DPropertyChangedTracker(
this, QQuick3DSuperClassInfo<QQuick3DQuadTextureProvider>())
679 if (m_dirtyFlag & Dirty::Dimensions) {
681 n->height = m_height;
684 if (m_dirtyFlag & Dirty::Format)
685 n->format = m_format;
687 if (m_dirtyFlag & Dirty::FragmentShader) {
688 const QQmlContext *context = qmlContext(
this);
689 n->fragmentShaderSource = !m_fragmentShaderCode.isEmpty() ? m_fragmentShaderCode.toUtf8()
690 : !m_fragmentShader.isEmpty() ? QSSGShaderUtils::resolveShader(m_fragmentShader, context, n->shaderPathKey)
694 if (m_dirtyFlag & Dirty::TrackedProperty) {
695 n->propertyUniforms = extractProperties();
698 if (m_dirtyFlag != 0)
699 emit surfaceChanged();
701 n->dirtyFlag = m_dirtyFlag;
711 markDirty(Dirty::TrackedProperty);
722 return m_fragmentShader;
727 if (m_fragmentShader == newFragmentShader)
729 m_fragmentShader = newFragmentShader;
730 emit fragmentShaderChanged();
731 markDirty(Dirty::FragmentShader);
736 return m_fragmentShaderCode;
741 if (m_fragmentShaderCode == newFragmentShaderCode)
743 m_fragmentShaderCode = newFragmentShaderCode;
744 emit fragmentShaderCodeChanged();
745 markDirty(Dirty::FragmentShader);
756 newWidth = qMax(1, newWidth);
757 if (m_width == newWidth)
761 markDirty(Dirty::Dimensions);
771 newHeight = qMax(1, newHeight);
772 if (m_height == newHeight)
774 m_height = newHeight;
775 emit heightChanged();
776 markDirty(Dirty::Dimensions);
786 if (m_format == newFormat)
788 m_format = newFormat;
789 emit formatChanged();
790 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