Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qssgrendereffect.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
5#include <QtQuick3DRuntimeRender/private/qssgrendereffect_p.h>
6#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
7#include <QtQuick3DRuntimeRender/private/qssgrendercommands_p.h>
8#include "../qssgrendercontextcore.h"
9#include "../rendererimpl/qssglayerrenderdata_p.h"
10
11#include <QtGui/QVector2D>
12#include <QtGui/QVector3D>
13
15
16QSSGRenderEffect::QSSGRenderEffect() : QSSGRenderGraphObject(Type::Effect) {}
17
18QSSGRenderEffect::~QSSGRenderEffect()
19{
20 resetCommands();
21}
22
23void QSSGRenderEffect::setFlag(QSSGRenderEffect::Flags flag, bool enabled)
24{
25 if (enabled)
26 flags |= FlagT(flag);
27 else
28 flags &= ~FlagT(flag);
29}
30
31// Suffix snippets added to the end of the shader strings. These are appended
32// after processing so it must be valid GLSL as-is, no more magic keywords.
33
34static const char *effect_vertex_main_pre =
35 "void main()\n"
36 "{\n"
37 " qt_inputUV = attr_uv;\n"
38 " qt_textureUV = qt_effectTextureMapUV(attr_uv);\n"
39 " vec4 qt_vertPosition = vec4(attr_pos, 1.0);\n"
40 "#if QSHADER_VIEW_COUNT >= 2\n"
41 " qt_viewIndex = gl_ViewIndex;\n"
42 "#else\n"
43 " qt_viewIndex = 0;\n"
44 "#endif\n"
45 " qt_customMain(qt_vertPosition.xyz);\n";
46
47static const char *effect_vertex_main_position =
48 " gl_Position = qt_modelViewProjection * qt_vertPosition;\n";
49
50static const char *effect_vertex_main_post =
51 "}\n";
52
53static const char *effect_fragment_main =
54 "void main()\n"
55 "{\n"
56 " qt_customMain();\n"
57 "}\n";
58
60 "#include \"tonemapping.glsllib\"\n"
61 "void main()\n"
62 "{\n"
63 " qt_customMain();\n"
64 " fragOutput = qt_tonemap(fragOutput);\n"
65 "}\n";
66
67void QSSGRenderEffect::finalizeShaders(const QSSGRenderLayer &layer, QSSGRenderContextInterface *renderContext)
68{
69 Q_UNUSED(layer);
70
71 // this is called on every frame, so do nothing if there are no changes
72 if (!shaderPrepData.valid)
73 return;
74
75 QRhi *rhi = renderContext->rhiContext()->rhi();
76
77 for (int i = 0, ie = shaderPrepData.passes.size(); i != ie; ++i) {
78 const ShaderPrepPassData &pass(shaderPrepData.passes[i]);
79
80 // The fragment shader of the last pass of the last effect may need to
81 // perform the built-in tonemapping.
82 const bool isLastEffect = m_nextEffect == nullptr;
83 const bool isLastPass = i == ie - 1;
84 const bool shouldTonemapIfEnabled = isLastEffect && isLastPass;
85
86 QSSGShaderFeatures features;
87 QByteArray completeVertexShader;
88 QByteArray completeFragmentShader;
89 QByteArray sourceCodeForHash;
90
91 const bool multiview = layer.viewCount >= 2;
92 const int srcIdx = multiview ? QSSGRenderCustomMaterial::MultiViewShaderPathKeyIndex : QSSGRenderCustomMaterial::RegularShaderPathKeyIndex;
93
94 if (!pass.vertexShaderCode[srcIdx].isEmpty()) {
95 QByteArray code = pass.vertexShaderCode[srcIdx];
96 // add the real main(), with or without assigning gl_Position at the end
97 code.append(effect_vertex_main_pre);
98 if (!pass.vertexMetaData[srcIdx].flags.testFlag(QSSGCustomShaderMetaData::OverridesPosition))
99 code.append(effect_vertex_main_position);
100 code.append(effect_vertex_main_post);
101 completeVertexShader = code;
102 sourceCodeForHash += code;
103 }
104
105 if (!pass.fragmentShaderCode[srcIdx].isEmpty()) {
106 QByteArray code = pass.fragmentShaderCode[srcIdx];
107 if (shouldTonemapIfEnabled)
108 code.append(effect_fragment_main_with_tonemapping);
109 else
110 code.append(effect_fragment_main);
111 completeFragmentShader = code;
112 sourceCodeForHash += code;
113 }
114
115 QByteArray shaderPathKey = pass.shaderPathKeyPrefix;
116 shaderPathKey.append(':' + QCryptographicHash::hash(sourceCodeForHash, QCryptographicHash::Algorithm::Sha1).toHex());
117
118 // QSSGRhiEffectSystem will vary the vertex shader code based on this
119 // flag from the QRhi. It is therefore important to capture this in the
120 // cache key as well.
121 shaderPathKey.append(rhi->isYUpInFramebuffer() ? QByteArrayLiteral(":1") : QByteArrayLiteral(":0"));
122
123 if (shouldTonemapIfEnabled) {
124 // This does not always mean there will be tonemapping: if the mode
125 // is TonemapModeNone, then no extra feature defines are set, and
126 // so qt_tonemap() in the shader will not alter the color.
127 const QSSGRenderLayer::TonemapMode tonemapMode = layer.tonemapMode;
128 shaderPathKey.append(':' + QByteArray::number(int(tonemapMode)));
129 QSSGLayerRenderData::setTonemapFeatures(features, tonemapMode);
130 }
131
132 shaderPathKey.append(multiview ? QByteArrayLiteral(":1") : QByteArrayLiteral(":0"));
133
134 // Now that the final shaderPathKey is known, store the source and
135 // related data; it will be retrieved later by the QSSGRhiEffectSystem.
136 if (!completeVertexShader.isEmpty()) {
137 renderContext->shaderLibraryManager()->setShaderSource(shaderPathKey,
138 QSSGShaderCache::ShaderType::Vertex,
139 completeVertexShader,
140 pass.vertexMetaData[srcIdx]);
141 }
142 if (!completeFragmentShader.isEmpty()) {
143 QSSGCustomShaderMetaData metaData = pass.fragmentMetaData[srcIdx];
144 metaData.features = features;
145 renderContext->shaderLibraryManager()->setShaderSource(shaderPathKey,
146 QSSGShaderCache::ShaderType::Fragment,
147 completeFragmentShader,
148 metaData);
149 }
150
151 // and update the command
152 delete commands[pass.bindShaderCmdIndex];
153 commands[pass.bindShaderCmdIndex] = new QSSGBindShader(shaderPathKey);
154 }
155
156 shaderPrepData.valid = false;
157}
158
159void QSSGRenderEffect::resetCommands()
160{
161 qDeleteAll(commands);
162 commands.clear();
163 shaderPrepData.passes.clear();
164}
165
166QT_END_NAMESPACE
static const char * effect_fragment_main_with_tonemapping
static const char * effect_vertex_main_post
static const char * effect_vertex_main_pre
static const char * effect_vertex_main_position
static const char * effect_fragment_main