1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2019 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQuick module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qsgmaterial.h" |
41 | #include "qsgrenderer_p.h" |
42 | #include "qsgmaterialrhishader_p.h" |
43 | #include <QtCore/QFile> |
44 | |
45 | QT_BEGIN_NAMESPACE |
46 | |
47 | /*! |
48 | \class QSGMaterialRhiShader |
49 | \brief The QSGMaterialRhiShader class represents a graphics API independent shader program. |
50 | \inmodule QtQuick |
51 | \ingroup qtquick-scenegraph-materials |
52 | \since 5.14 |
53 | |
54 | QSGMaterialRhiShader is a modern, cross-platform alternative to |
55 | QSGMaterialShader. The latter is tied to OpenGL and GLSL by design, whereas |
56 | QSGMaterialRhiShader is based on QShader, a container for multiple |
57 | versions of a graphics shader together with reflection information. |
58 | |
59 | \note All classes with QSG prefix should be used solely on the scene graph's |
60 | rendering thread. See \l {Scene Graph and Rendering} for more information. |
61 | */ |
62 | |
63 | /*! |
64 | \enum QSGMaterialRhiShader::Flag |
65 | Flag values to indicate special material properties. |
66 | |
67 | \value UpdatesGraphicsPipelineState Setting this flag enables calling |
68 | updateGraphicsPipelineState(). |
69 | */ |
70 | |
71 | QShader QSGMaterialRhiShaderPrivate::loadShader(const QString &filename) |
72 | { |
73 | QFile f(filename); |
74 | if (!f.open(flags: QIODevice::ReadOnly)) { |
75 | qWarning() << "Failed to find shader" << filename; |
76 | return QShader(); |
77 | } |
78 | return QShader::fromSerialized(data: f.readAll()); |
79 | } |
80 | |
81 | void QSGMaterialRhiShaderPrivate::clearCachedRendererData() |
82 | { |
83 | for (int i = 0; i < MAX_SHADER_RESOURCE_BINDINGS; ++i) |
84 | textureBindingTable[i] = nullptr; |
85 | for (int i = 0; i < MAX_SHADER_RESOURCE_BINDINGS; ++i) |
86 | samplerBindingTable[i] = nullptr; |
87 | } |
88 | |
89 | static inline QRhiShaderResourceBinding::StageFlags toSrbStage(QShader::Stage stage) |
90 | { |
91 | switch (stage) { |
92 | case QShader::VertexStage: |
93 | return QRhiShaderResourceBinding::VertexStage; |
94 | case QShader::FragmentStage: |
95 | return QRhiShaderResourceBinding::FragmentStage; |
96 | default: |
97 | Q_UNREACHABLE(); |
98 | break; |
99 | } |
100 | return { }; |
101 | } |
102 | |
103 | void QSGMaterialRhiShaderPrivate::prepare(QShader::Variant vertexShaderVariant) |
104 | { |
105 | ubufBinding = -1; |
106 | ubufSize = 0; |
107 | ubufStages = { }; |
108 | memset(s: combinedImageSamplerBindings, c: 0, n: sizeof(combinedImageSamplerBindings)); |
109 | vertexShader = fragmentShader = nullptr; |
110 | masterUniformData.clear(); |
111 | |
112 | clearCachedRendererData(); |
113 | |
114 | for (QShader::Stage stage : { QShader::VertexStage, QShader::FragmentStage }) { |
115 | auto it = shaderFileNames.find(akey: stage); |
116 | if (it != shaderFileNames.end()) { |
117 | QString fn = *it; |
118 | const QShader s = loadShader(filename: *it); |
119 | if (!s.isValid()) |
120 | continue; |
121 | shaders[stage] = ShaderStageData(s); |
122 | // load only once, subsequent prepare() calls will have it all in shaders already |
123 | shaderFileNames.erase(it); |
124 | } |
125 | } |
126 | |
127 | auto vsIt = shaders.find(akey: QShader::VertexStage); |
128 | if (vsIt != shaders.end()) { |
129 | vsIt->shaderVariant = vertexShaderVariant; |
130 | vsIt->vertexInputLocations.clear(); |
131 | vsIt->qt_order_attrib_location = -1; |
132 | |
133 | const QShaderDescription desc = vsIt->shader.description(); |
134 | const QVector<QShaderDescription::InOutVariable> vertexInputs = desc.inputVariables(); |
135 | for (const QShaderDescription::InOutVariable &v : vertexInputs) { |
136 | const QByteArray name = v.name.toUtf8(); |
137 | if (vertexShaderVariant == QShader::BatchableVertexShader |
138 | && name == QByteArrayLiteral("_qt_order" )) |
139 | { |
140 | vsIt->qt_order_attrib_location = v.location; |
141 | } else { |
142 | vsIt->vertexInputLocations.append(t: v.location); |
143 | } |
144 | } |
145 | |
146 | if (vsIt->vertexInputLocations.contains(t: vsIt->qt_order_attrib_location)) { |
147 | qWarning(msg: "Vertex input clash in rewritten (batchable) vertex shader at input location %d. " |
148 | "Vertex shaders must avoid using this location." , vsIt->qt_order_attrib_location); |
149 | } |
150 | } |
151 | |
152 | for (auto it = shaders.begin(); it != shaders.end(); ++it) { |
153 | const QShaderDescription desc = it->shader.description(); |
154 | |
155 | const QVector<QShaderDescription::UniformBlock> ubufs = desc.uniformBlocks(); |
156 | const int ubufCount = ubufs.count(); |
157 | if (ubufCount > 1) { |
158 | qWarning(msg: "Multiple uniform blocks found in shader. " |
159 | "This should be avoided as Qt Quick supports only one." ); |
160 | } |
161 | for (int i = 0; i < ubufCount; ++i) { |
162 | const QShaderDescription::UniformBlock &ubuf(ubufs[i]); |
163 | if (ubufBinding == -1 && ubuf.binding >= 0) { |
164 | ubufBinding = ubuf.binding; |
165 | ubufSize = ubuf.size; |
166 | ubufStages |= toSrbStage(stage: it->shader.stage()); |
167 | masterUniformData.fill(c: '\0', size: ubufSize); |
168 | } else if (ubufBinding == ubuf.binding && ubuf.binding >= 0) { |
169 | if (ubuf.size > ubufSize) { |
170 | ubufSize = ubuf.size; |
171 | masterUniformData.fill(c: '\0', size: ubufSize); |
172 | } |
173 | ubufStages |= toSrbStage(stage: it->shader.stage()); |
174 | } else { |
175 | qWarning(msg: "Uniform block %s (binding %d) ignored" , qPrintable(ubuf.blockName), ubuf.binding); |
176 | } |
177 | } |
178 | |
179 | const QVector<QShaderDescription::InOutVariable> imageSamplers = desc.combinedImageSamplers(); |
180 | const int imageSamplersCount = imageSamplers.count(); |
181 | for (int i = 0; i < imageSamplersCount; ++i) { |
182 | const QShaderDescription::InOutVariable &var(imageSamplers[i]); |
183 | if (var.binding >= 0 && var.binding < MAX_SHADER_RESOURCE_BINDINGS) |
184 | combinedImageSamplerBindings[var.binding] |= toSrbStage(stage: it->shader.stage()); |
185 | else |
186 | qWarning(msg: "Encountered invalid combined image sampler (%s) binding %d" , |
187 | qPrintable(var.name), var.binding); |
188 | } |
189 | |
190 | if (it.key() == QShader::VertexStage) |
191 | vertexShader = &it.value(); |
192 | else if (it.key() == QShader::FragmentStage) |
193 | fragmentShader = &it.value(); |
194 | } |
195 | |
196 | if (vertexShader && vertexShaderVariant == QShader::BatchableVertexShader && vertexShader->qt_order_attrib_location == -1) |
197 | qWarning(msg: "No rewriter-inserted attribute found, this should not happen." ); |
198 | } |
199 | |
200 | /*! |
201 | Constructs a new QSGMaterialRhiShader. |
202 | */ |
203 | QSGMaterialRhiShader::QSGMaterialRhiShader() |
204 | : d_ptr(new QSGMaterialRhiShaderPrivate(this)) |
205 | { |
206 | } |
207 | |
208 | /*! |
209 | \internal |
210 | */ |
211 | QSGMaterialRhiShader::QSGMaterialRhiShader(QSGMaterialRhiShaderPrivate &dd) |
212 | : d_ptr(&dd) |
213 | { |
214 | } |
215 | |
216 | /*! |
217 | \internal |
218 | */ |
219 | QSGMaterialRhiShader::~QSGMaterialRhiShader() |
220 | { |
221 | } |
222 | |
223 | // We have our own enum as QShader is not initially public. Internally |
224 | // everything works with QShader::Stage however. So convert. |
225 | static inline QShader::Stage toShaderStage(QSGMaterialRhiShader::Stage stage) |
226 | { |
227 | switch (stage) { |
228 | case QSGMaterialRhiShader::VertexStage: |
229 | return QShader::VertexStage; |
230 | case QSGMaterialRhiShader::FragmentStage: |
231 | return QShader::FragmentStage; |
232 | default: |
233 | Q_UNREACHABLE(); |
234 | return QShader::VertexStage; |
235 | } |
236 | } |
237 | |
238 | /*! |
239 | Sets the \a shader for the specified \a stage. |
240 | */ |
241 | void QSGMaterialRhiShader::setShader(Stage stage, const QShader &shader) |
242 | { |
243 | Q_D(QSGMaterialRhiShader); |
244 | d->shaders[toShaderStage(stage)] = QSGMaterialRhiShaderPrivate::ShaderStageData(shader); |
245 | } |
246 | |
247 | /*! |
248 | Sets the \a filename for the shader for the specified \a stage. |
249 | |
250 | The file is expected to contain a serialized QRhiShader. |
251 | */ |
252 | void QSGMaterialRhiShader::setShaderFileName(Stage stage, const QString &filename) |
253 | { |
254 | Q_D(QSGMaterialRhiShader); |
255 | d->shaderFileNames[toShaderStage(stage)] = filename; |
256 | } |
257 | |
258 | /*! |
259 | \return the currently set flags for this material shader. |
260 | */ |
261 | QSGMaterialRhiShader::Flags QSGMaterialRhiShader::flags() const |
262 | { |
263 | Q_D(const QSGMaterialRhiShader); |
264 | return d->flags; |
265 | } |
266 | |
267 | /*! |
268 | Sets the \a flags on this material shader if \a on is true; |
269 | otherwise clears the specified flags. |
270 | */ |
271 | void QSGMaterialRhiShader::setFlag(Flags flags, bool on) |
272 | { |
273 | Q_D(QSGMaterialRhiShader); |
274 | if (on) |
275 | d->flags |= flags; |
276 | else |
277 | d->flags &= ~flags; |
278 | } |
279 | |
280 | /*! |
281 | This function is called by the scene graph to get the contents of the |
282 | shader program's uniform buffer updated. The implementation is not expected |
283 | to perform any real graphics operations, it is merely responsible for |
284 | copying data to the QByteArray returned from RenderState::uniformData(). |
285 | The scene graph takes care of making that buffer visible in the shaders. |
286 | |
287 | The current rendering \a state is passed from the scene graph. If the state |
288 | indicates that any relevant state is dirty, the implementation must update |
289 | the appropriate region in the buffer data that is accessible via |
290 | RenderState::uniformData(). When a state, such as, matrix or opacity, is |
291 | not dirty, there is no need to touch the corresponding region since the |
292 | data is persistent. |
293 | |
294 | The return value must be \c true whenever any change was made to the uniform data. |
295 | |
296 | The subclass specific state, such as the color of a flat color material, |
297 | should be extracted from \a newMaterial to update the relevant regions in |
298 | the buffer accordingly. |
299 | |
300 | \a oldMaterial can be used to minimize buffer changes (which are typically |
301 | memcpy calls) when updating material states. When \a oldMaterial is null, |
302 | this shader was just activated. |
303 | */ |
304 | bool QSGMaterialRhiShader::updateUniformData(RenderState &state, |
305 | QSGMaterial *newMaterial, |
306 | QSGMaterial *oldMaterial) |
307 | { |
308 | Q_UNUSED(state); |
309 | Q_UNUSED(newMaterial); |
310 | Q_UNUSED(oldMaterial); |
311 | return false; |
312 | } |
313 | |
314 | /*! |
315 | This function is called by the scene graph to prepare using a sampled image |
316 | in the shader, typically in form of a combined image sampler. |
317 | |
318 | \a binding is the binding number of the sampler. The function is called for |
319 | each variable in the material's shaders' |
320 | \l{QShaderDescription::combinedImageSamplers()}. |
321 | |
322 | When *\a{texture} is null, it must be set to a QSGTexture pointer before |
323 | returning. When non-null, it is up to the material to decide if a new |
324 | \c{QSGTexture *} is stored to it, or if it updates some parameters on the |
325 | already known QSGTexture. The ownership of the QSGTexture is not |
326 | transferred. |
327 | |
328 | The current rendering \a state is passed from the scene graph. It is up to |
329 | the material to enqueue the texture data uploads to the |
330 | QRhiResourceUpdateBatch retriveable via RenderState::resourceUpdateBatch(). |
331 | |
332 | The subclass specific state can be extracted from \a newMaterial. |
333 | |
334 | \a oldMaterial can be used to minimize changes. When \a oldMaterial is null, |
335 | this shader was just activated. |
336 | */ |
337 | void QSGMaterialRhiShader::updateSampledImage(RenderState &state, |
338 | int binding, |
339 | QSGTexture **texture, |
340 | QSGMaterial *newMaterial, |
341 | QSGMaterial *oldMaterial) |
342 | { |
343 | Q_UNUSED(state); |
344 | Q_UNUSED(binding); |
345 | Q_UNUSED(texture); |
346 | Q_UNUSED(newMaterial); |
347 | Q_UNUSED(oldMaterial); |
348 | } |
349 | |
350 | /*! |
351 | This function is called by the scene graph to enable the material to |
352 | provide a custom set of graphics state. The set of states that are |
353 | customizable by material is limited to blending and related settings. |
354 | |
355 | \note This function is only called when the UpdatesGraphicsPipelineState |
356 | flag was enabled via setFlags(). By default it is not set, and so this |
357 | function is never called. |
358 | |
359 | The return value must be \c true whenever a change was made to any of the |
360 | members in \a ps. |
361 | |
362 | \note The contents of \a ps is not persistent between invocations of this |
363 | function. |
364 | |
365 | The current rendering \a state is passed from the scene graph. |
366 | |
367 | The subclass specific state can be extracted from \a newMaterial. When \a |
368 | oldMaterial is null, this shader was just activated. |
369 | */ |
370 | bool QSGMaterialRhiShader::updateGraphicsPipelineState(RenderState &state, GraphicsPipelineState *ps, |
371 | QSGMaterial *newMaterial, QSGMaterial *oldMaterial) |
372 | { |
373 | Q_UNUSED(state); |
374 | Q_UNUSED(ps); |
375 | Q_UNUSED(newMaterial); |
376 | Q_UNUSED(oldMaterial); |
377 | return false; |
378 | } |
379 | |
380 | /*! |
381 | \class QSGMaterialRhiShader::RenderState |
382 | |
383 | \brief Encapsulates the current rendering state during a call to |
384 | QSGMaterialRhiShader::updateUniformData() and the other \c update type of |
385 | functions. |
386 | |
387 | \inmodule QtQuick |
388 | \since 5.14 |
389 | |
390 | The render state contains a number of accessors that the shader needs to |
391 | respect in order to conform to the current state of the scene graph. |
392 | */ |
393 | |
394 | /*! |
395 | \enum QSGMaterialRhiShader::RenderState::DirtyState |
396 | |
397 | \value DirtyMatrix Used to indicate that the matrix has changed and must be |
398 | updated. |
399 | |
400 | \value DirtyOpacity Used to indicate that the opacity has changed and must |
401 | be updated. |
402 | |
403 | \value DirtyAll Used to indicate that everything needs to be updated. |
404 | */ |
405 | |
406 | /*! |
407 | \fn bool QSGMaterialRhiShader::RenderState::isMatrixDirty() const |
408 | |
409 | Returns \c true if the dirtyStates() contain the dirty matrix state, |
410 | otherwise returns \c false. |
411 | */ |
412 | |
413 | /*! |
414 | \fn bool QSGMaterialRhiShader::RenderState::isOpacityDirty() const |
415 | |
416 | Returns \c true if the dirtyStates() contains the dirty opacity state, |
417 | otherwise returns \c false. |
418 | */ |
419 | |
420 | /*! |
421 | \fn QSGMaterialRhiShader::RenderState::DirtyStates QSGMaterialRhiShader::RenderState::dirtyStates() const |
422 | |
423 | Returns which rendering states that have changed and needs to be updated |
424 | for geometry rendered with this material to conform to the current |
425 | rendering state. |
426 | */ |
427 | |
428 | /*! |
429 | \class QSGMaterialRhiShader::GraphicsPipelineState |
430 | |
431 | \brief Describes state changes that the material wants to apply to the |
432 | currently active graphics pipeline state. |
433 | |
434 | \inmodule QtQuick |
435 | \since 5.14 |
436 | |
437 | Unlike QSGMaterialShader, directly issuing state change commands with the |
438 | underlying graphics API is not possible with QSGMaterialRhiShader. This is |
439 | mainly because the concept of individually changeable states is considered |
440 | deprecated and not supported with modern graphics APIs. |
441 | |
442 | Therefore, it is up to QSGMaterialRhiShader to expose a data structure with |
443 | the set of supported states, which the material can change in its |
444 | updatePipelineState() implementation, if there is one. The scenegraph will |
445 | then internally apply these changes to the active graphics pipeline state, |
446 | then rolling them back as appropriate. |
447 | */ |
448 | |
449 | /*! |
450 | \enum QSGMaterialRhiShader::GraphicsPipelineState::BlendFactor |
451 | \since 5.14 |
452 | |
453 | \value Zero |
454 | \value One |
455 | \value SrcColor |
456 | \value OneMinusSrcColor |
457 | \value DstColor |
458 | \value OneMinusDstColor |
459 | \value SrcAlpha |
460 | \value OneMinusSrcAlpha |
461 | \value DstAlpha |
462 | \value OneMinusDstAlpha |
463 | \value ConstantColor |
464 | \value OneMinusConstantColor |
465 | \value ConstantAlpha |
466 | \value OneMinusConstantAlpha |
467 | \value SrcAlphaSaturate |
468 | \value Src1Color |
469 | \value OneMinusSrc1Color |
470 | \value Src1Alpha |
471 | \value OneMinusSrc1Alpha |
472 | */ |
473 | |
474 | /*! |
475 | \enum QSGMaterialRhiShader::GraphicsPipelineState::ColorMaskComponent |
476 | \since 5.14 |
477 | |
478 | \value R |
479 | \value G |
480 | \value B |
481 | \value A |
482 | */ |
483 | |
484 | /*! |
485 | \enum QSGMaterialRhiShader::GraphicsPipelineState::CullMode |
486 | \since 5.14 |
487 | |
488 | \value CullNone |
489 | \value CullFront |
490 | \value CullBack |
491 | */ |
492 | |
493 | /*! |
494 | Returns the accumulated opacity to be used for rendering. |
495 | */ |
496 | float QSGMaterialRhiShader::RenderState::opacity() const |
497 | { |
498 | Q_ASSERT(m_data); |
499 | return float(static_cast<const QSGRenderer *>(m_data)->currentOpacity()); |
500 | } |
501 | |
502 | /*! |
503 | Returns the modelview determinant to be used for rendering. |
504 | */ |
505 | float QSGMaterialRhiShader::RenderState::determinant() const |
506 | { |
507 | Q_ASSERT(m_data); |
508 | return float(static_cast<const QSGRenderer *>(m_data)->determinant()); |
509 | } |
510 | |
511 | /*! |
512 | Returns the matrix combined of modelview matrix and project matrix. |
513 | */ |
514 | QMatrix4x4 QSGMaterialRhiShader::RenderState::combinedMatrix() const |
515 | { |
516 | Q_ASSERT(m_data); |
517 | return static_cast<const QSGRenderer *>(m_data)->currentCombinedMatrix(); |
518 | } |
519 | |
520 | /*! |
521 | Returns the ratio between physical pixels and device-independent pixels |
522 | to be used for rendering. |
523 | */ |
524 | float QSGMaterialRhiShader::RenderState::devicePixelRatio() const |
525 | { |
526 | Q_ASSERT(m_data); |
527 | return float(static_cast<const QSGRenderer *>(m_data)->devicePixelRatio()); |
528 | } |
529 | |
530 | /*! |
531 | Returns the model view matrix. |
532 | |
533 | If the material has the RequiresFullMatrix flag set, this is guaranteed to |
534 | be the complete transform matrix calculated from the scenegraph. |
535 | |
536 | However, if this flag is not set, the renderer may choose to alter this |
537 | matrix. For example, it may pre-transform vertices on the CPU and set this |
538 | matrix to identity. |
539 | |
540 | In a situation such as the above, it is still possible to retrieve the |
541 | actual matrix determinant by setting the RequiresDeterminant flag in the |
542 | material and calling the determinant() accessor. |
543 | */ |
544 | QMatrix4x4 QSGMaterialRhiShader::RenderState::modelViewMatrix() const |
545 | { |
546 | Q_ASSERT(m_data); |
547 | return static_cast<const QSGRenderer *>(m_data)->currentModelViewMatrix(); |
548 | } |
549 | |
550 | /*! |
551 | Returns the projection matrix. |
552 | */ |
553 | QMatrix4x4 QSGMaterialRhiShader::RenderState::projectionMatrix() const |
554 | { |
555 | Q_ASSERT(m_data); |
556 | return static_cast<const QSGRenderer *>(m_data)->currentProjectionMatrix(); |
557 | } |
558 | |
559 | /*! |
560 | Returns the viewport rect of the surface being rendered to. |
561 | */ |
562 | QRect QSGMaterialRhiShader::RenderState::viewportRect() const |
563 | { |
564 | Q_ASSERT(m_data); |
565 | return static_cast<const QSGRenderer *>(m_data)->viewportRect(); |
566 | } |
567 | |
568 | /*! |
569 | Returns the device rect of the surface being rendered to |
570 | */ |
571 | QRect QSGMaterialRhiShader::RenderState::deviceRect() const |
572 | { |
573 | Q_ASSERT(m_data); |
574 | return static_cast<const QSGRenderer *>(m_data)->deviceRect(); |
575 | } |
576 | |
577 | /*! |
578 | Returns a pointer to the data for the uniform (constant) buffer in the |
579 | shader. Uniform data must only be updated from |
580 | QSGMaterialRhiShader::updateUniformData(). The return value is null in the |
581 | other reimplementable functions, such as, |
582 | QSGMaterialRhiShader::updateSampledImage(). |
583 | |
584 | \note It is strongly recommended to declare the uniform block with \c |
585 | std140 in the shader, and to carefully study the standard uniform block |
586 | layout as described in section 7.6.2.2 of the OpenGL specification. It is |
587 | up to the QSGMaterialRhiShader implementation to ensure data gets placed |
588 | at the right location in this QByteArray, taking alignment requirements |
589 | into account. Shader code translated to other shading languages is expected |
590 | to use the same offsets for block members, even when the target language |
591 | uses different packing rules by default. |
592 | |
593 | \note Avoid copying from C++ POD types, such as, structs, in order to |
594 | update multiple members at once, unless it has been verified that the |
595 | layouts of the C++ struct and the GLSL uniform block match. |
596 | */ |
597 | QByteArray *QSGMaterialRhiShader::RenderState::uniformData() |
598 | { |
599 | Q_ASSERT(m_data); |
600 | return static_cast<const QSGRenderer *>(m_data)->currentUniformData(); |
601 | } |
602 | |
603 | /*! |
604 | Returns a resource update batch to which upload and copy operatoins can be |
605 | queued. This is typically used by |
606 | QSGMaterialRhiShader::updateSampledImage() to enqueue texture image |
607 | content updates. |
608 | */ |
609 | QRhiResourceUpdateBatch *QSGMaterialRhiShader::RenderState::resourceUpdateBatch() |
610 | { |
611 | Q_ASSERT(m_data); |
612 | return static_cast<const QSGRenderer *>(m_data)->currentResourceUpdateBatch(); |
613 | } |
614 | |
615 | /*! |
616 | Returns the current QRhi. |
617 | */ |
618 | QRhi *QSGMaterialRhiShader::RenderState::rhi() |
619 | { |
620 | Q_ASSERT(m_data); |
621 | return static_cast<const QSGRenderer *>(m_data)->currentRhi(); |
622 | } |
623 | |
624 | char const *const *QSGMaterialRhiShader::attributeNames() const |
625 | { |
626 | Q_ASSERT_X(false, "QSGMaterialRhiShader::attributeNames()" , "Not implemented for RHI" ); |
627 | return nullptr; |
628 | } |
629 | |
630 | QT_END_NAMESPACE |
631 | |