1 | // Copyright (C) 2019 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qsgmaterial.h" |
5 | #include "qsgrenderer_p.h" |
6 | #include "qsgmaterialshader_p.h" |
7 | #include <QtCore/QFile> |
8 | |
9 | QT_BEGIN_NAMESPACE |
10 | |
11 | /*! |
12 | \class QSGMaterialShader |
13 | \brief The QSGMaterialShader class represents a graphics API independent shader program. |
14 | \inmodule QtQuick |
15 | \ingroup qtquick-scenegraph-materials |
16 | \since 5.14 |
17 | |
18 | QSGMaterialShader represents a combination of vertex and fragment shaders, |
19 | data that define the graphics pipeline state changes, and logic that |
20 | updates graphics resources, such as uniform buffers and textures. |
21 | |
22 | \note All classes with QSG prefix should be used solely on the scene graph's |
23 | rendering thread. See \l {Scene Graph and Rendering} for more information. |
24 | |
25 | The QSGMaterial and QSGMaterialShader form a tight relationship. For one |
26 | scene graph (including nested graphs), there is one unique |
27 | QSGMaterialShader instance that encapsulates the shaders and other data |
28 | the scene graph uses to render an object with that material. Each |
29 | QSGGeometryNode can have a unique QSGMaterial that defines how the graphics |
30 | pipeline must be configured while drawing the node. An instance of |
31 | QSGMaterialShader is never created explicitly by the user, it will be |
32 | created on demand by the scene graph through QSGMaterial::createShader(). |
33 | The scene graph creates an instance of QSGMaterialShader by calling the |
34 | QSGMaterial::createShader() method, ensuring that there is only one |
35 | instance of each shader implementation. |
36 | |
37 | In Qt 5, QSGMaterialShader was tied to OpenGL. It was built directly on |
38 | QOpenGLShaderProgram and had functions like \c updateState() that could |
39 | issue arbitrary OpenGL commands. This is no longer the case in Qt 6. |
40 | QSGMaterialShader is not strictly data-oriented, meaning it provides data |
41 | (shaders and the desired pipeline state changes) together with logic that |
42 | updates data in a uniform buffer. Graphics API access is not provided. This |
43 | means that a QSGMaterialShader cannot make OpenGL, Vulkan, Metal, or Direct |
44 | 3D calls on its own. Together with the unified shader management, this |
45 | allows a QSGMaterialShader to be written once, and be functional with any of |
46 | the supported graphics APIs at run time. |
47 | |
48 | The shaders set by calling the protected setShaderFileName() function |
49 | control what material does with the vertex data from the geometry, and how |
50 | the fragments are shaded. A QSGMaterialShader will typically set a vertex |
51 | and a fragment shader during construction. Changing the shaders afterwards |
52 | may not lead to the desired effect and must be avoided. |
53 | |
54 | In Qt 6, the default approach is to ship \c{.qsb} files with the application, |
55 | typically embedded via the resource system, and referenced when calling |
56 | setShaderFileName(). The \c{.qsb} files are generated offline, or at latest |
57 | at application build time, from Vulkan-style GLSL source code using the \c |
58 | qsb tool from the Qt Shader Tools module. |
59 | |
60 | There are three virtuals that can be overridden. These provide the data, or |
61 | the logic to generate the data, for uniform buffers, textures, and pipeline |
62 | state changes. |
63 | |
64 | updateUniformData() is the function that is most commonly reimplemented in |
65 | subclasses. This function is expected to update the contents of a |
66 | QByteArray that will then be exposed to the shaders as a uniform buffer. |
67 | Any QSGMaterialShader that has a uniform block in its vertex or fragment |
68 | shader must reimplement updateUniformData(). |
69 | |
70 | updateSampledImage() is relevant when the shader code samples textures. The |
71 | function will be invoked for each sampler (or combined image sampler, in |
72 | APIs where relevant), giving it the option to specify which QSGTexture |
73 | should be exposed to the shader. |
74 | |
75 | The shader pipeline state changes are less often used. One use case is |
76 | materials that wish to use a specific blend mode. The relevant function is |
77 | updateGraphicsPipelineState(). This function is not called unless the |
78 | QSGMaterialShader has opted in by setting the flag |
79 | UpdatesGraphicsPipelineState. The task of the function is to update the |
80 | GraphicsPipelineState struct instance that is passed to it with the |
81 | desired changes. Currently only blending and culling-related features are |
82 | available, other states cannot be controlled by materials. |
83 | |
84 | A minimal example, that also includes texture support, could be the |
85 | following. Here we assume that Material is the QSGMaterial that creates an |
86 | instance of Shader in its \l{QSGMaterial::createShader()}{createShader()}, |
87 | and that it holds a QSGTexture we want to sample in the fragment shader. The |
88 | vertex shader relies only on the modelview-projection matrix. |
89 | |
90 | \code |
91 | class Shader : public QSGMaterialShader |
92 | { |
93 | public: |
94 | Shader() |
95 | { |
96 | setShaderFileName(VertexStage, QLatin1String(":/materialshader.vert.qsb")); |
97 | setShaderFileName(FragmentStage, QLatin1String(":/materialshader.frag.qsb")); |
98 | } |
99 | |
100 | bool updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *) |
101 | { |
102 | bool changed = false; |
103 | QByteArray *buf = state.uniformData(); |
104 | if (state.isMatrixDirty()) { |
105 | const QMatrix4x4 m = state.combinedMatrix(); |
106 | memcpy(buf->data(), m.constData(), 64); |
107 | changed = true; |
108 | } |
109 | return changed; |
110 | } |
111 | |
112 | void updateSampledImage(RenderState &, int binding, QSGTexture **texture, QSGMaterial *newMaterial, QSGMaterial *) |
113 | { |
114 | Material *mat = static_cast<Material *>(newMaterial); |
115 | if (binding == 1) |
116 | *texture = mat->texture(); |
117 | } |
118 | }; |
119 | \endcode |
120 | |
121 | The Vulkan-style GLSL source code for the shaders could look like the |
122 | following. These are expected to be preprocessed offline using the \c qsb |
123 | tool, which generates the \c{.qsb} files referenced in the Shader() |
124 | constructor. |
125 | |
126 | \badcode |
127 | #version 440 |
128 | layout(location = 0) in vec4 aVertex; |
129 | layout(location = 1) in vec2 aTexCoord; |
130 | layout(location = 0) out vec2 vTexCoord; |
131 | layout(std140, binding = 0) uniform buf { |
132 | mat4 qt_Matrix; |
133 | } ubuf; |
134 | out gl_PerVertex { vec4 gl_Position; }; |
135 | void main() { |
136 | gl_Position = ubuf.qt_Matrix * aVertex; |
137 | vTexCoord = aTexCoord; |
138 | } |
139 | \endcode |
140 | |
141 | \badcode |
142 | #version 440 |
143 | layout(location = 0) in vec2 vTexCoord; |
144 | layout(location = 0) out vec4 fragColor; |
145 | layout(binding = 1) uniform sampler2D srcTex; |
146 | void main() { |
147 | vec4 c = texture(srcTex, vTexCoord); |
148 | fragColor = vec4(c.rgb * 0.5, 1.0); |
149 | } |
150 | \endcode |
151 | |
152 | \note All classes with QSG prefix should be used solely on the scene graph's |
153 | rendering thread. See \l {Scene Graph and Rendering} for more information. |
154 | |
155 | \sa QSGMaterial, {Scene Graph - Custom Material}, {Scene Graph - Two Texture Providers}, {Scene Graph - Graph} |
156 | */ |
157 | |
158 | /*! |
159 | \enum QSGMaterialShader::Flag |
160 | Flag values to indicate special material properties. |
161 | |
162 | \value UpdatesGraphicsPipelineState Setting this flag enables calling |
163 | updateGraphicsPipelineState(). |
164 | */ |
165 | |
166 | QShader QSGMaterialShaderPrivate::loadShader(const QString &filename) |
167 | { |
168 | QFile f(filename); |
169 | if (!f.open(flags: QIODevice::ReadOnly)) { |
170 | qWarning() << "Failed to find shader" << filename; |
171 | return QShader(); |
172 | } |
173 | return QShader::fromSerialized(data: f.readAll()); |
174 | } |
175 | |
176 | void QSGMaterialShaderPrivate::clearCachedRendererData() |
177 | { |
178 | for (int i = 0; i < MAX_SHADER_RESOURCE_BINDINGS; ++i) |
179 | textureBindingTable[i].clear(); |
180 | for (int i = 0; i < MAX_SHADER_RESOURCE_BINDINGS; ++i) |
181 | samplerBindingTable[i].clear(); |
182 | } |
183 | |
184 | static inline QRhiShaderResourceBinding::StageFlags toSrbStage(QShader::Stage stage) |
185 | { |
186 | switch (stage) { |
187 | case QShader::VertexStage: |
188 | return QRhiShaderResourceBinding::VertexStage; |
189 | case QShader::FragmentStage: |
190 | return QRhiShaderResourceBinding::FragmentStage; |
191 | default: |
192 | Q_UNREACHABLE(); |
193 | break; |
194 | } |
195 | return { }; |
196 | } |
197 | |
198 | void QSGMaterialShaderPrivate::prepare(QShader::Variant vertexShaderVariant) |
199 | { |
200 | ubufBinding = -1; |
201 | ubufSize = 0; |
202 | ubufStages = { }; |
203 | memset(s: static_cast<void *>(combinedImageSamplerBindings), c: 0, n: sizeof(combinedImageSamplerBindings)); |
204 | memset(s: static_cast<void *>(combinedImageSamplerCount), c: 0, n: sizeof(combinedImageSamplerCount)); |
205 | vertexShader = fragmentShader = nullptr; |
206 | masterUniformData.clear(); |
207 | |
208 | clearCachedRendererData(); |
209 | |
210 | for (QShader::Stage stage : { QShader::VertexStage, QShader::FragmentStage }) { |
211 | auto it = shaderFileNames.find(key: stage); |
212 | if (it != shaderFileNames.end()) { |
213 | QString fn = *it; |
214 | const QShader s = loadShader(filename: *it); |
215 | if (!s.isValid()) |
216 | continue; |
217 | shaders[stage] = ShaderStageData(s); |
218 | // load only once, subsequent prepare() calls will have it all in shaders already |
219 | shaderFileNames.erase(it); |
220 | } |
221 | } |
222 | |
223 | auto vsIt = shaders.find(key: QShader::VertexStage); |
224 | if (vsIt != shaders.end()) { |
225 | vsIt->shaderVariant = vertexShaderVariant; |
226 | vsIt->vertexInputLocations.clear(); |
227 | vsIt->qt_order_attrib_location = -1; |
228 | |
229 | const QShaderDescription desc = vsIt->shader.description(); |
230 | const QVector<QShaderDescription::InOutVariable> vertexInputs = desc.inputVariables(); |
231 | for (const QShaderDescription::InOutVariable &v : vertexInputs) { |
232 | if (vertexShaderVariant == QShader::BatchableVertexShader |
233 | && v.name == QByteArrayLiteral("_qt_order" )) { |
234 | vsIt->qt_order_attrib_location = v.location; |
235 | } else { |
236 | vsIt->vertexInputLocations.append(t: v.location); |
237 | } |
238 | } |
239 | |
240 | if (vsIt->vertexInputLocations.contains(t: vsIt->qt_order_attrib_location)) { |
241 | qWarning(msg: "Vertex input clash in rewritten (batchable) vertex shader at input location %d. " |
242 | "Vertex shaders must avoid using this location." , vsIt->qt_order_attrib_location); |
243 | } |
244 | } |
245 | |
246 | for (auto it = shaders.begin(); it != shaders.end(); ++it) { |
247 | const QShaderDescription desc = it->shader.description(); |
248 | |
249 | const QVector<QShaderDescription::UniformBlock> ubufs = desc.uniformBlocks(); |
250 | const int ubufCount = ubufs.size(); |
251 | if (ubufCount > 1) { |
252 | qWarning(msg: "Multiple uniform blocks found in shader. " |
253 | "This should be avoided as Qt Quick supports only one." ); |
254 | } |
255 | for (int i = 0; i < ubufCount; ++i) { |
256 | const QShaderDescription::UniformBlock &ubuf(ubufs[i]); |
257 | if (ubufBinding == -1 && ubuf.binding >= 0) { |
258 | ubufBinding = ubuf.binding; |
259 | ubufSize = ubuf.size; |
260 | ubufStages |= toSrbStage(stage: it->shader.stage()); |
261 | masterUniformData.fill(c: '\0', size: ubufSize); |
262 | } else if (ubufBinding == ubuf.binding && ubuf.binding >= 0) { |
263 | if (ubuf.size > ubufSize) { |
264 | ubufSize = ubuf.size; |
265 | masterUniformData.fill(c: '\0', size: ubufSize); |
266 | } |
267 | ubufStages |= toSrbStage(stage: it->shader.stage()); |
268 | } else { |
269 | qWarning(msg: "Uniform block %s (binding %d) ignored" , ubuf.blockName.constData(), |
270 | ubuf.binding); |
271 | } |
272 | } |
273 | |
274 | const QVector<QShaderDescription::InOutVariable> imageSamplers = desc.combinedImageSamplers(); |
275 | const int imageSamplersCount = imageSamplers.size(); |
276 | for (int i = 0; i < imageSamplersCount; ++i) { |
277 | const QShaderDescription::InOutVariable &var(imageSamplers[i]); |
278 | |
279 | if (var.binding < 0) |
280 | continue; |
281 | |
282 | if (var.binding < MAX_SHADER_RESOURCE_BINDINGS) { |
283 | combinedImageSamplerBindings[var.binding] |= toSrbStage(stage: it->shader.stage()); |
284 | |
285 | int count = 1; |
286 | for (int dim : var.arrayDims) |
287 | count *= dim; |
288 | |
289 | combinedImageSamplerCount[var.binding] = count; |
290 | } else { |
291 | qWarning(msg: "Encountered invalid combined image sampler (%s) binding %d" , |
292 | var.name.constData(), var.binding); |
293 | } |
294 | } |
295 | |
296 | if (it.key() == QShader::VertexStage) |
297 | vertexShader = &it.value(); |
298 | else if (it.key() == QShader::FragmentStage) |
299 | fragmentShader = &it.value(); |
300 | } |
301 | |
302 | if (vertexShader && vertexShaderVariant == QShader::BatchableVertexShader && vertexShader->qt_order_attrib_location == -1) |
303 | qWarning(msg: "No rewriter-inserted attribute found, this should not happen." ); |
304 | } |
305 | |
306 | /*! |
307 | Constructs a new QSGMaterialShader. |
308 | */ |
309 | QSGMaterialShader::QSGMaterialShader() |
310 | : d_ptr(new QSGMaterialShaderPrivate(this)) |
311 | { |
312 | } |
313 | |
314 | /*! |
315 | \internal |
316 | */ |
317 | QSGMaterialShader::QSGMaterialShader(QSGMaterialShaderPrivate &dd) |
318 | : d_ptr(&dd) |
319 | { |
320 | } |
321 | |
322 | /*! |
323 | \internal |
324 | */ |
325 | QSGMaterialShader::~QSGMaterialShader() |
326 | { |
327 | } |
328 | |
329 | // We have our own enum as QShader is not initially public. Internally |
330 | // everything works with QShader::Stage however. So convert. |
331 | static inline QShader::Stage toShaderStage(QSGMaterialShader::Stage stage) |
332 | { |
333 | switch (stage) { |
334 | case QSGMaterialShader::VertexStage: |
335 | return QShader::VertexStage; |
336 | case QSGMaterialShader::FragmentStage: |
337 | return QShader::FragmentStage; |
338 | default: |
339 | Q_UNREACHABLE_RETURN(QShader::VertexStage); |
340 | } |
341 | } |
342 | |
343 | /*! |
344 | Sets the \a shader for the specified \a stage. |
345 | */ |
346 | void QSGMaterialShader::setShader(Stage stage, const QShader &shader) |
347 | { |
348 | Q_D(QSGMaterialShader); |
349 | d->shaders[toShaderStage(stage)] = QSGMaterialShaderPrivate::ShaderStageData(shader); |
350 | } |
351 | |
352 | /*! |
353 | Sets the \a filename for the shader for the specified \a stage. |
354 | |
355 | The file is expected to contain a serialized QShader. |
356 | */ |
357 | void QSGMaterialShader::setShaderFileName(Stage stage, const QString &filename) |
358 | { |
359 | Q_D(QSGMaterialShader); |
360 | d->shaderFileNames[toShaderStage(stage)] = filename; |
361 | } |
362 | |
363 | /*! |
364 | \return the currently set flags for this material shader. |
365 | */ |
366 | QSGMaterialShader::Flags QSGMaterialShader::flags() const |
367 | { |
368 | Q_D(const QSGMaterialShader); |
369 | return d->flags; |
370 | } |
371 | |
372 | /*! |
373 | Sets the \a flags on this material shader if \a on is true; |
374 | otherwise clears the specified flags. |
375 | */ |
376 | void QSGMaterialShader::setFlag(Flags flags, bool on) |
377 | { |
378 | Q_D(QSGMaterialShader); |
379 | if (on) |
380 | d->flags |= flags; |
381 | else |
382 | d->flags &= ~flags; |
383 | } |
384 | |
385 | /*! |
386 | Sets the \a flags for this material shader. |
387 | */ |
388 | void QSGMaterialShader::setFlags(Flags flags) |
389 | { |
390 | Q_D(QSGMaterialShader); |
391 | d->flags = flags; |
392 | } |
393 | |
394 | /*! |
395 | Returns the number of elements in the combined image sampler variable at \a |
396 | binding. This value is introspected from the shader code. The variable may |
397 | be an array, and may have more than one dimension. |
398 | |
399 | The count reflects the total number of combined image sampler items in the |
400 | variable. In the following example, the count for \c{srcA} is 1, \c{srcB} |
401 | is 4, and \c{srcC} is 6. |
402 | |
403 | \badcode |
404 | layout (binding = 0) uniform sampler2D srcA; |
405 | layout (binding = 1) uniform sampler2D srcB[4]; |
406 | layout (binding = 2) uniform sampler2D srcC[2][3]; |
407 | \endcode |
408 | |
409 | This count is the number of QSGTexture pointers in the texture parameter |
410 | of \l{QSGMaterialShader::updateSampledImage}. |
411 | |
412 | \sa QSGMaterialShader::updateSampledImage |
413 | \since 6.4 |
414 | */ |
415 | int QSGMaterialShader::combinedImageSamplerCount(int binding) const |
416 | { |
417 | Q_D(const QSGMaterialShader); |
418 | |
419 | if (binding >= 0 && binding < d->MAX_SHADER_RESOURCE_BINDINGS) |
420 | return d->combinedImageSamplerCount[binding]; |
421 | |
422 | return 0; |
423 | } |
424 | |
425 | /*! |
426 | This function is called by the scene graph to get the contents of the |
427 | shader program's uniform buffer updated. The implementation is not expected |
428 | to perform any real graphics operations, it is merely responsible for |
429 | copying data to the QByteArray returned from RenderState::uniformData(). |
430 | The scene graph takes care of making that buffer visible in the shaders. |
431 | |
432 | The current rendering \a state is passed from the scene graph. If the state |
433 | indicates that any relevant state is dirty, the implementation must update |
434 | the appropriate region in the buffer data that is accessible via |
435 | RenderState::uniformData(). When a state, such as, matrix or opacity, is |
436 | not dirty, there is no need to touch the corresponding region since the |
437 | data is persistent. |
438 | |
439 | The return value must be \c true whenever any change was made to the uniform data. |
440 | |
441 | The subclass specific state, such as the color of a flat color material, |
442 | should be extracted from \a newMaterial to update the relevant regions in |
443 | the buffer accordingly. |
444 | |
445 | \a oldMaterial can be used to minimize buffer changes (which are typically |
446 | memcpy calls) when updating material states. When \a oldMaterial is null, |
447 | this shader was just activated. |
448 | */ |
449 | bool QSGMaterialShader::updateUniformData(RenderState &state, |
450 | QSGMaterial *newMaterial, |
451 | QSGMaterial *oldMaterial) |
452 | { |
453 | Q_UNUSED(state); |
454 | Q_UNUSED(newMaterial); |
455 | Q_UNUSED(oldMaterial); |
456 | return false; |
457 | } |
458 | |
459 | /*! |
460 | This function is called by the scene graph to prepare use of sampled images |
461 | in the shader, typically in the form of combined image samplers. |
462 | |
463 | \a binding is the binding number of the sampler. The function is called for |
464 | each combined image sampler variable in the shader code associated with the |
465 | QSGMaterialShader. |
466 | |
467 | \a{texture} is an array of QSGTexture pointers. The number of elements in |
468 | the array matches the number of elements in the image sampler variable |
469 | specified in the shader code. This variable may be an array, and may have |
470 | more than one dimension. The number of elements in the array may be |
471 | found via \l{QSGMaterialShader::combinedImageSamplerCount} |
472 | |
473 | When an element in \a{texture} is null, it must be set to a valid |
474 | QSGTexture pointer before returning. When non-null, it is up to the |
475 | material to decide if a new \c{QSGTexture *} is stored to it, or if it |
476 | updates some parameters on the already known QSGTexture. The ownership of |
477 | the QSGTexture is not transferred. |
478 | |
479 | The current rendering \a state is passed from the scene graph. Where |
480 | relevant, it is up to the material to trigger enqueuing texture data |
481 | uploads via QSGTexture::commitTextureOperations(). |
482 | |
483 | The subclass specific state can be extracted from \a newMaterial. |
484 | |
485 | \a oldMaterial can be used to minimize changes. When \a oldMaterial is null, |
486 | this shader was just activated. |
487 | |
488 | \sa QSGMaterialShader::combinedImageSamplerCount |
489 | */ |
490 | void QSGMaterialShader::updateSampledImage(RenderState &state, |
491 | int binding, |
492 | QSGTexture **texture, |
493 | QSGMaterial *newMaterial, |
494 | QSGMaterial *oldMaterial) |
495 | { |
496 | Q_UNUSED(state); |
497 | Q_UNUSED(binding); |
498 | Q_UNUSED(texture); |
499 | Q_UNUSED(newMaterial); |
500 | Q_UNUSED(oldMaterial); |
501 | } |
502 | |
503 | /*! |
504 | This function is called by the scene graph to enable the material to |
505 | provide a custom set of graphics state. The set of states that are |
506 | customizable by material is limited to blending and related settings. |
507 | |
508 | \note This function is only called when the UpdatesGraphicsPipelineState |
509 | flag was enabled via setFlags(). By default it is not set, and so this |
510 | function is never called. |
511 | |
512 | The return value must be \c true whenever a change was made to any of the |
513 | members in \a ps. |
514 | |
515 | \note The contents of \a ps is not persistent between invocations of this |
516 | function. |
517 | |
518 | The current rendering \a state is passed from the scene graph. |
519 | |
520 | The subclass specific state can be extracted from \a newMaterial. When \a |
521 | oldMaterial is null, this shader was just activated. |
522 | */ |
523 | bool QSGMaterialShader::updateGraphicsPipelineState(RenderState &state, GraphicsPipelineState *ps, |
524 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
525 | { |
526 | Q_UNUSED(state); |
527 | Q_UNUSED(ps); |
528 | Q_UNUSED(newMaterial); |
529 | Q_UNUSED(oldMaterial); |
530 | return false; |
531 | } |
532 | |
533 | /*! |
534 | \class QSGMaterialShader::RenderState |
535 | |
536 | \brief Encapsulates the current rendering state during a call to |
537 | QSGMaterialShader::updateUniformData() and the other \c update type of |
538 | functions. |
539 | |
540 | \inmodule QtQuick |
541 | \since 5.14 |
542 | |
543 | The render state contains a number of accessors that the shader needs to |
544 | respect in order to conform to the current state of the scene graph. |
545 | */ |
546 | |
547 | /*! |
548 | \enum QSGMaterialShader::RenderState::DirtyState |
549 | |
550 | \value DirtyMatrix Used to indicate that the matrix has changed and must be |
551 | updated. |
552 | |
553 | \value DirtyOpacity Used to indicate that the opacity has changed and must |
554 | be updated. |
555 | |
556 | \value DirtyCachedMaterialData Used to indicate that the cached material |
557 | state has changed and must be updated. |
558 | |
559 | \value DirtyAll Used to indicate that everything needs to be updated. |
560 | */ |
561 | |
562 | /*! |
563 | \fn bool QSGMaterialShader::RenderState::isMatrixDirty() const |
564 | |
565 | Returns \c true if the dirtyStates() contain the dirty matrix state, |
566 | otherwise returns \c false. |
567 | */ |
568 | |
569 | /*! |
570 | \fn bool QSGMaterialShader::RenderState::isOpacityDirty() const |
571 | |
572 | Returns \c true if the dirtyStates() contains the dirty opacity state, |
573 | otherwise returns \c false. |
574 | */ |
575 | |
576 | /*! |
577 | \fn QSGMaterialShader::RenderState::DirtyStates QSGMaterialShader::RenderState::dirtyStates() const |
578 | |
579 | Returns which rendering states that have changed and needs to be updated |
580 | for geometry rendered with this material to conform to the current |
581 | rendering state. |
582 | */ |
583 | |
584 | /*! |
585 | \class QSGMaterialShader::GraphicsPipelineState |
586 | |
587 | \brief Describes state changes that the material wants to apply to the |
588 | currently active graphics pipeline state. |
589 | |
590 | \inmodule QtQuick |
591 | \since 5.14 |
592 | |
593 | Unlike QSGMaterialShader, directly issuing state change commands with the |
594 | underlying graphics API is not possible with QSGMaterialShader. This is |
595 | mainly because the concept of individually changeable states is considered |
596 | deprecated and not supported with modern graphics APIs. |
597 | |
598 | Therefore, it is up to QSGMaterialShader to expose a data structure with |
599 | the set of supported states, which the material can change in its |
600 | updatePipelineState() implementation, if there is one. The scenegraph will |
601 | then internally apply these changes to the active graphics pipeline state, |
602 | then rolling them back as appropriate. |
603 | |
604 | When updateGraphicsPipelineState() is called, the struct has all members |
605 | set to a valid value to reflect the renderer's current state. Not changing |
606 | any values (or not reimplementing the function) indicates that the material |
607 | is fine with the defaults (which are dynamic however, depending on |
608 | QSGMaterial flags, for example). |
609 | */ |
610 | |
611 | /*! |
612 | \enum QSGMaterialShader::GraphicsPipelineState::BlendFactor |
613 | \since 5.14 |
614 | |
615 | \value Zero |
616 | \value One |
617 | \value SrcColor |
618 | \value OneMinusSrcColor |
619 | \value DstColor |
620 | \value OneMinusDstColor |
621 | \value SrcAlpha |
622 | \value OneMinusSrcAlpha |
623 | \value DstAlpha |
624 | \value OneMinusDstAlpha |
625 | \value ConstantColor |
626 | \value OneMinusConstantColor |
627 | \value ConstantAlpha |
628 | \value OneMinusConstantAlpha |
629 | \value SrcAlphaSaturate |
630 | \value Src1Color |
631 | \value OneMinusSrc1Color |
632 | \value Src1Alpha |
633 | \value OneMinusSrc1Alpha |
634 | */ |
635 | |
636 | /*! |
637 | \enum QSGMaterialShader::GraphicsPipelineState::ColorMaskComponent |
638 | \since 5.14 |
639 | |
640 | \value R |
641 | \value G |
642 | \value B |
643 | \value A |
644 | */ |
645 | |
646 | /*! |
647 | \enum QSGMaterialShader::GraphicsPipelineState::CullMode |
648 | \since 5.14 |
649 | |
650 | \value CullNone |
651 | \value CullFront |
652 | \value CullBack |
653 | */ |
654 | |
655 | /*! |
656 | \enum QSGMaterialShader::GraphicsPipelineState::PolygonMode |
657 | \since 6.4 |
658 | \brief Specifies the polygon rasterization mode |
659 | |
660 | Polygon Mode (Triangle Fill Mode in Metal, Fill Mode in D3D) specifies |
661 | the fill mode used when rasterizing polygons. Polygons may be drawn as |
662 | solids (Fill), or as a wire mesh (Line). |
663 | |
664 | \warning OpenGL ES does not support the \c{Line} polygon mode. OpenGL ES |
665 | will rasterize all polygons as filled no matter what polygon mode is set. |
666 | Using \c{Line} will make your application non-portable. |
667 | |
668 | \value Fill The interior of the polygon is filled (default) |
669 | \value Line Boundary edges of the polygon are drawn as line segments. |
670 | */ |
671 | |
672 | /*! |
673 | \variable QSGMaterialShader::GraphicsPipelineState::blendEnable |
674 | \since 5.14 |
675 | \brief Enables blending. |
676 | |
677 | \note Changing this flag should be done with care, and is best avoided. |
678 | Rather, materials should always use the QSGMaterial::Blend flag to indicate |
679 | that they wish to use blending. Changing this value from false to true for |
680 | a material that did not declare QSGMaterial::Blend can lead to unexpected |
681 | visual results. |
682 | */ |
683 | |
684 | /*! |
685 | \variable QSGMaterialShader::GraphicsPipelineState::srcColor |
686 | \since 5.14 |
687 | \brief Source blending factor, either RGB or RGBA depending on separateBlendFactors. |
688 | */ |
689 | |
690 | /*! |
691 | \variable QSGMaterialShader::GraphicsPipelineState::dstColor |
692 | \since 5.14 |
693 | \brief Destination blending factor, either RGB or RGBA depending on separateBlendFactors. |
694 | */ |
695 | |
696 | /*! |
697 | \variable QSGMaterialShader::GraphicsPipelineState::colorWrite |
698 | \since 5.14 |
699 | \brief Color write mask. |
700 | */ |
701 | |
702 | /*! |
703 | \variable QSGMaterialShader::GraphicsPipelineState::blendConstant |
704 | \since 5.14 |
705 | \brief Blend constant applicable when a blending factor is set to use a constant value. |
706 | */ |
707 | |
708 | /*! |
709 | \variable QSGMaterialShader::GraphicsPipelineState::cullMode |
710 | \since 5.14 |
711 | \brief Cull mode. |
712 | */ |
713 | |
714 | /*! |
715 | \variable QSGMaterialShader::GraphicsPipelineState::polygonMode |
716 | \since 6.4 |
717 | \brief Polygon rasterization mode. |
718 | */ |
719 | |
720 | /*! |
721 | \variable QSGMaterialShader::GraphicsPipelineState::separateBlendFactors |
722 | \since 6.5 |
723 | \brief Indicates that alpha blending factors are specified separately. |
724 | |
725 | False by default, meaning both RGB and alpha blending factors are defined |
726 | by srcColor and dstColor. When set to true, the alpha blending factors are |
727 | taken from srcAlpha and dstAlpha instead, and srcColor and dstColor applies |
728 | only to RGB. |
729 | */ |
730 | |
731 | /*! |
732 | \variable QSGMaterialShader::GraphicsPipelineState::srcAlpha |
733 | \since 6.5 |
734 | \brief Source alpha blending factor. |
735 | |
736 | Applies only when separateBlendFactors is set to true. |
737 | */ |
738 | |
739 | /*! |
740 | \variable QSGMaterialShader::GraphicsPipelineState::dstAlpha |
741 | \since 6.5 |
742 | \brief Destination alpha blending factor. |
743 | |
744 | Applies only when separateBlendFactors is set to true. |
745 | */ |
746 | |
747 | /*! |
748 | Returns the accumulated opacity to be used for rendering. |
749 | */ |
750 | float QSGMaterialShader::RenderState::opacity() const |
751 | { |
752 | Q_ASSERT(m_data); |
753 | return float(static_cast<const QSGRenderer *>(m_data)->currentOpacity()); |
754 | } |
755 | |
756 | /*! |
757 | Returns the modelview determinant to be used for rendering. |
758 | */ |
759 | float QSGMaterialShader::RenderState::determinant() const |
760 | { |
761 | Q_ASSERT(m_data); |
762 | return float(static_cast<const QSGRenderer *>(m_data)->determinant()); |
763 | } |
764 | |
765 | /*! |
766 | Returns the matrix combined of modelview matrix and project matrix. |
767 | */ |
768 | QMatrix4x4 QSGMaterialShader::RenderState::combinedMatrix() const |
769 | { |
770 | Q_ASSERT(m_data); |
771 | return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix(); |
772 | } |
773 | |
774 | /*! |
775 | Returns the ratio between physical pixels and device-independent pixels |
776 | to be used for rendering. |
777 | */ |
778 | float QSGMaterialShader::RenderState::devicePixelRatio() const |
779 | { |
780 | Q_ASSERT(m_data); |
781 | return float(static_cast<const QSGRenderer *>(m_data)->devicePixelRatio()); |
782 | } |
783 | |
784 | /*! |
785 | Returns the model view matrix. |
786 | |
787 | If the material has the RequiresFullMatrix flag set, this is guaranteed to |
788 | be the complete transform matrix calculated from the scenegraph. |
789 | |
790 | However, if this flag is not set, the renderer may choose to alter this |
791 | matrix. For example, it may pre-transform vertices on the CPU and set this |
792 | matrix to identity. |
793 | |
794 | In a situation such as the above, it is still possible to retrieve the |
795 | actual matrix determinant by setting the RequiresDeterminant flag in the |
796 | material and calling the determinant() accessor. |
797 | */ |
798 | QMatrix4x4 QSGMaterialShader::RenderState::modelViewMatrix() const |
799 | { |
800 | Q_ASSERT(m_data); |
801 | return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix(); |
802 | } |
803 | |
804 | /*! |
805 | Returns the projection matrix. |
806 | */ |
807 | QMatrix4x4 QSGMaterialShader::RenderState::projectionMatrix() const |
808 | { |
809 | Q_ASSERT(m_data); |
810 | return static_cast<const QSGRenderer *>(m_data)->currentProjectionMatrix(); |
811 | } |
812 | |
813 | /*! |
814 | Returns the viewport rect of the surface being rendered to. |
815 | */ |
816 | QRect QSGMaterialShader::RenderState::viewportRect() const |
817 | { |
818 | Q_ASSERT(m_data); |
819 | return static_cast<const QSGRenderer *>(m_data)->viewportRect(); |
820 | } |
821 | |
822 | /*! |
823 | Returns the device rect of the surface being rendered to |
824 | */ |
825 | QRect QSGMaterialShader::RenderState::deviceRect() const |
826 | { |
827 | Q_ASSERT(m_data); |
828 | return static_cast<const QSGRenderer *>(m_data)->deviceRect(); |
829 | } |
830 | |
831 | /*! |
832 | Returns a pointer to the data for the uniform (constant) buffer in the |
833 | shader. Uniform data must only be updated from |
834 | QSGMaterialShader::updateUniformData(). The return value is null in the |
835 | other reimplementable functions, such as, |
836 | QSGMaterialShader::updateSampledImage(). |
837 | |
838 | \note It is strongly recommended to declare the uniform block with \c |
839 | std140 in the shader, and to carefully study the standard uniform block |
840 | layout as described in section 7.6.2.2 of the OpenGL specification. It is |
841 | up to the QSGMaterialShader implementation to ensure data gets placed |
842 | at the right location in this QByteArray, taking alignment requirements |
843 | into account. Shader code translated to other shading languages is expected |
844 | to use the same offsets for block members, even when the target language |
845 | uses different packing rules by default. |
846 | |
847 | \note Avoid copying from C++ POD types, such as, structs, in order to |
848 | update multiple members at once, unless it has been verified that the |
849 | layouts of the C++ struct and the GLSL uniform block match. |
850 | */ |
851 | QByteArray *QSGMaterialShader::RenderState::uniformData() |
852 | { |
853 | Q_ASSERT(m_data); |
854 | return static_cast<const QSGRenderer *>(m_data)->currentUniformData(); |
855 | } |
856 | |
857 | /*! |
858 | Returns a resource update batch to which upload and copy operatoins can be |
859 | queued. This is typically used by |
860 | QSGMaterialShader::updateSampledImage() to enqueue texture image |
861 | content updates. |
862 | */ |
863 | QRhiResourceUpdateBatch *QSGMaterialShader::RenderState::resourceUpdateBatch() |
864 | { |
865 | Q_ASSERT(m_data); |
866 | return static_cast<const QSGRenderer *>(m_data)->currentResourceUpdateBatch(); |
867 | } |
868 | |
869 | /*! |
870 | Returns the current QRhi. |
871 | */ |
872 | QRhi *QSGMaterialShader::RenderState::rhi() |
873 | { |
874 | Q_ASSERT(m_data); |
875 | return static_cast<const QSGRenderer *>(m_data)->currentRhi(); |
876 | } |
877 | |
878 | QT_END_NAMESPACE |
879 | |