| 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 | |