| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 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 "qsgtexturematerial_p.h" | 
| 41 | #include <private/qsgtexture_p.h> | 
| 42 | #if QT_CONFIG(opengl) | 
| 43 | # include <QtGui/qopenglshaderprogram.h> | 
| 44 | # include <QtGui/qopenglfunctions.h> | 
| 45 | #endif | 
| 46 | #include <QtGui/private/qrhi_p.h> | 
| 47 |  | 
| 48 | QT_BEGIN_NAMESPACE | 
| 49 |  | 
| 50 | inline static bool isPowerOfTwo(int x) | 
| 51 | { | 
| 52 |     // Assumption: x >= 1 | 
| 53 |     return x == (x & -x); | 
| 54 | } | 
| 55 |  | 
| 56 | QSGOpaqueTextureMaterialShader::QSGOpaqueTextureMaterialShader() | 
| 57 | { | 
| 58 | #if QT_CONFIG(opengl) | 
| 59 |     setShaderSourceFile(type: QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/scenegraph/shaders/opaquetexture.vert" )); | 
| 60 |     setShaderSourceFile(type: QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/opaquetexture.frag" )); | 
| 61 | #endif | 
| 62 | } | 
| 63 |  | 
| 64 | char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const | 
| 65 | { | 
| 66 |     static char const *const attr[] = { "qt_VertexPosition" , "qt_VertexTexCoord" , nullptr }; | 
| 67 |     return attr; | 
| 68 | } | 
| 69 |  | 
| 70 | void QSGOpaqueTextureMaterialShader::initialize() | 
| 71 | { | 
| 72 | #if QT_CONFIG(opengl) | 
| 73 |     m_matrix_id = program()->uniformLocation(name: "qt_Matrix" ); | 
| 74 | #endif | 
| 75 | } | 
| 76 |  | 
| 77 | void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) | 
| 78 | { | 
| 79 |     Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); | 
| 80 |     QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newEffect); | 
| 81 |     QSGOpaqueTextureMaterial *oldTx = static_cast<QSGOpaqueTextureMaterial *>(oldEffect); | 
| 82 |  | 
| 83 |     QSGTexture *t = tx->texture(); | 
| 84 |  | 
| 85 | #ifndef QT_NO_DEBUG | 
| 86 |     if (!qsg_safeguard_texture(t)) | 
| 87 |         return; | 
| 88 | #endif | 
| 89 |  | 
| 90 |     t->setFiltering(tx->filtering()); | 
| 91 |  | 
| 92 |     t->setHorizontalWrapMode(tx->horizontalWrapMode()); | 
| 93 |     t->setVerticalWrapMode(tx->verticalWrapMode()); | 
| 94 | #if QT_CONFIG(opengl) | 
| 95 |     bool npotSupported = const_cast<QOpenGLContext *>(state.context()) | 
| 96 |         ->functions()->hasOpenGLFeature(feature: QOpenGLFunctions::NPOTTextureRepeat); | 
| 97 |     if (!npotSupported) { | 
| 98 |         QSize size = t->textureSize(); | 
| 99 |         const bool isNpot = !isPowerOfTwo(x: size.width()) || !isPowerOfTwo(x: size.height()); | 
| 100 |         if (isNpot) { | 
| 101 |             t->setHorizontalWrapMode(QSGTexture::ClampToEdge); | 
| 102 |             t->setVerticalWrapMode(QSGTexture::ClampToEdge); | 
| 103 |         } | 
| 104 |     } | 
| 105 | #else | 
| 106 |     Q_UNUSED(state) | 
| 107 | #endif | 
| 108 |     t->setMipmapFiltering(tx->mipmapFiltering()); | 
| 109 |     t->setAnisotropyLevel(tx->anisotropyLevel()); | 
| 110 |  | 
| 111 |     if (oldTx == nullptr || oldTx->texture()->textureId() != t->textureId()) | 
| 112 |         t->bind(); | 
| 113 |     else | 
| 114 |         t->updateBindOptions(); | 
| 115 | #if QT_CONFIG(opengl) | 
| 116 |     if (state.isMatrixDirty()) | 
| 117 |         program()->setUniformValue(location: m_matrix_id, value: state.combinedMatrix()); | 
| 118 | #endif | 
| 119 | } | 
| 120 |  | 
| 121 |  | 
| 122 | QSGOpaqueTextureMaterialRhiShader::QSGOpaqueTextureMaterialRhiShader() | 
| 123 | { | 
| 124 |     setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.vert.qsb" )); | 
| 125 |     setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/opaquetexture.frag.qsb" )); | 
| 126 | } | 
| 127 |  | 
| 128 | bool QSGOpaqueTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *, QSGMaterial *) | 
| 129 | { | 
| 130 |     bool changed = false; | 
| 131 |     QByteArray *buf = state.uniformData(); | 
| 132 |  | 
| 133 |     if (state.isMatrixDirty()) { | 
| 134 |         const QMatrix4x4 m = state.combinedMatrix(); | 
| 135 |         memcpy(dest: buf->data(), src: m.constData(), n: 64); | 
| 136 |         changed = true; | 
| 137 |     } | 
| 138 |  | 
| 139 |     return changed; | 
| 140 | } | 
| 141 |  | 
| 142 | void QSGOpaqueTextureMaterialRhiShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture, | 
| 143 |                                                            QSGMaterial *newMaterial, QSGMaterial *oldMaterial) | 
| 144 | { | 
| 145 |     if (binding != 1) | 
| 146 |         return; | 
| 147 |  | 
| 148 | #ifdef QT_NO_DEBUG | 
| 149 |     Q_UNUSED(oldMaterial); | 
| 150 | #endif | 
| 151 |     Q_ASSERT(oldMaterial == nullptr || newMaterial->type() == oldMaterial->type()); | 
| 152 |     QSGOpaqueTextureMaterial *tx = static_cast<QSGOpaqueTextureMaterial *>(newMaterial); | 
| 153 |     QSGTexture *t = tx->texture(); | 
| 154 |  | 
| 155 |     t->setFiltering(tx->filtering()); | 
| 156 |     t->setMipmapFiltering(tx->mipmapFiltering()); | 
| 157 |     t->setAnisotropyLevel(tx->anisotropyLevel()); | 
| 158 |  | 
| 159 |     t->setHorizontalWrapMode(tx->horizontalWrapMode()); | 
| 160 |     t->setVerticalWrapMode(tx->verticalWrapMode()); | 
| 161 |     if (!state.rhi()->isFeatureSupported(feature: QRhi::NPOTTextureRepeat)) { | 
| 162 |         QSize size = t->textureSize(); | 
| 163 |         const bool isNpot = !isPowerOfTwo(x: size.width()) || !isPowerOfTwo(x: size.height()); | 
| 164 |         if (isNpot) { | 
| 165 |             t->setHorizontalWrapMode(QSGTexture::ClampToEdge); | 
| 166 |             t->setVerticalWrapMode(QSGTexture::ClampToEdge); | 
| 167 |             t->setMipmapFiltering(QSGTexture::None); | 
| 168 |         } | 
| 169 |     } | 
| 170 |  | 
| 171 |     t->updateRhiTexture(rhi: state.rhi(), resourceUpdates: state.resourceUpdateBatch()); | 
| 172 |     *texture = t; | 
| 173 | } | 
| 174 |  | 
| 175 |  | 
| 176 | /*! | 
| 177 |     \class QSGOpaqueTextureMaterial | 
| 178 |     \brief The QSGOpaqueTextureMaterial class provides a convenient way of | 
| 179 |     rendering textured geometry in the scene graph. | 
| 180 |     \inmodule QtQuick | 
| 181 |     \ingroup qtquick-scenegraph-materials | 
| 182 |  | 
| 183 |     \warning This utility class is only functional when running with the | 
| 184 |     default backend of the Qt Quick scenegraph. | 
| 185 |  | 
| 186 |     The opaque textured material will fill every pixel in a geometry with | 
| 187 |     the supplied texture. The material does not respect the opacity of the | 
| 188 |     QSGMaterialShader::RenderState, so opacity nodes in the parent chain | 
| 189 |     of nodes using this material, have no effect. | 
| 190 |  | 
| 191 |     The geometry to be rendered with an opaque texture material requires | 
| 192 |     vertices in attribute location 0 and texture coordinates in attribute | 
| 193 |     location 1. The texture coordinate is a 2-dimensional floating-point | 
| 194 |     tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an | 
| 195 |     attribute set compatible with this material. | 
| 196 |  | 
| 197 |     The texture to be rendered can be set using setTexture(). How the | 
| 198 |     texture should be rendered can be specified using setMipmapFiltering(), | 
| 199 |     setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode(). | 
| 200 |     The rendering state is set on the texture instance just before it | 
| 201 |     is bound. | 
| 202 |  | 
| 203 |     The opaque textured material respects the current matrix and the alpha | 
| 204 |     channel of the texture. It will disregard the accumulated opacity in | 
| 205 |     the scenegraph. | 
| 206 |  | 
| 207 |     A texture material must have a texture set before it is used as | 
| 208 |     a material in the scene graph. | 
| 209 |  */ | 
| 210 |  | 
| 211 |  | 
| 212 |  | 
| 213 | /*! | 
| 214 |     Creates a new QSGOpaqueTextureMaterial. | 
| 215 |  | 
| 216 |     The default mipmap filtering and filtering mode is set to | 
| 217 |     QSGTexture::Nearest. The default wrap modes is set to | 
| 218 |     \c QSGTexture::ClampToEdge. | 
| 219 |  | 
| 220 |  */ | 
| 221 | QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial() | 
| 222 |     : m_texture(nullptr) | 
| 223 |     , m_filtering(QSGTexture::Nearest) | 
| 224 |     , m_mipmap_filtering(QSGTexture::None) | 
| 225 |     , m_horizontal_wrap(QSGTexture::ClampToEdge) | 
| 226 |     , m_vertical_wrap(QSGTexture::ClampToEdge) | 
| 227 |     , m_anisotropy_level(QSGTexture::AnisotropyNone) | 
| 228 | { | 
| 229 |     setFlag(flags: SupportsRhiShader, on: true); | 
| 230 | } | 
| 231 |  | 
| 232 |  | 
| 233 | /*! | 
| 234 |     \internal | 
| 235 |  */ | 
| 236 | QSGMaterialType *QSGOpaqueTextureMaterial::type() const | 
| 237 | { | 
| 238 |     static QSGMaterialType type; | 
| 239 |     return &type; | 
| 240 | } | 
| 241 |  | 
| 242 | /*! | 
| 243 |     \internal | 
| 244 |  */ | 
| 245 | QSGMaterialShader *QSGOpaqueTextureMaterial::createShader() const | 
| 246 | { | 
| 247 |     if (flags().testFlag(flag: RhiShaderWanted)) | 
| 248 |         return new QSGOpaqueTextureMaterialRhiShader; | 
| 249 |     else | 
| 250 |         return new QSGOpaqueTextureMaterialShader; | 
| 251 | } | 
| 252 |  | 
| 253 |  | 
| 254 | /*! | 
| 255 |     \fn QSGTexture *QSGOpaqueTextureMaterial::texture() const | 
| 256 |  | 
| 257 |     Returns this texture material's texture. | 
| 258 |  */ | 
| 259 |  | 
| 260 |  | 
| 261 |  | 
| 262 | /*! | 
| 263 |     Sets the texture of this material to \a texture. | 
| 264 |  | 
| 265 |     The material does not take ownership of the texture. | 
| 266 |  */ | 
| 267 |  | 
| 268 | void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) | 
| 269 | { | 
| 270 |     m_texture = texture; | 
| 271 |     setFlag(flags: Blending, on: m_texture ? m_texture->hasAlphaChannel() : false); | 
| 272 | } | 
| 273 |  | 
| 274 |  | 
| 275 |  | 
| 276 | /*! | 
| 277 |     \fn void QSGOpaqueTextureMaterial::setMipmapFiltering(QSGTexture::Filtering filtering) | 
| 278 |  | 
| 279 |     Sets the mipmap mode to \a filtering. | 
| 280 |  | 
| 281 |     The mipmap filtering mode is set on the texture instance just before the | 
| 282 |     texture is bound for rendering. | 
| 283 |  | 
| 284 |     If the texture does not have mipmapping support, enabling mipmapping has no | 
| 285 |     effect. | 
| 286 |  */ | 
| 287 |  | 
| 288 |  | 
| 289 |  | 
| 290 | /*! | 
| 291 |     \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::mipmapFiltering() const | 
| 292 |  | 
| 293 |     Returns this material's mipmap filtering mode. | 
| 294 |  | 
| 295 |     The default mipmap mode is \c QSGTexture::Nearest. | 
| 296 |  */ | 
| 297 |  | 
| 298 |  | 
| 299 |  | 
| 300 | /*! | 
| 301 |     \fn void QSGOpaqueTextureMaterial::setFiltering(QSGTexture::Filtering filtering) | 
| 302 |  | 
| 303 |     Sets the filtering to \a filtering. | 
| 304 |  | 
| 305 |     The filtering mode is set on the texture instance just before the texture | 
| 306 |     is bound for rendering. | 
| 307 |  */ | 
| 308 |  | 
| 309 |  | 
| 310 |  | 
| 311 | /*! | 
| 312 |     \fn QSGTexture::Filtering QSGOpaqueTextureMaterial::filtering() const | 
| 313 |  | 
| 314 |     Returns this material's filtering mode. | 
| 315 |  | 
| 316 |     The default filtering is \c QSGTexture::Nearest. | 
| 317 |  */ | 
| 318 |  | 
| 319 |  | 
| 320 |  | 
| 321 | /*! | 
| 322 |     \fn void QSGOpaqueTextureMaterial::setHorizontalWrapMode(QSGTexture::WrapMode mode) | 
| 323 |  | 
| 324 |     Sets the horizontal wrap mode to \a mode. | 
| 325 |  | 
| 326 |     The horizontal wrap mode is set on the texture instance just before the texture | 
| 327 |     is bound for rendering. | 
| 328 |  */ | 
| 329 |  | 
| 330 |  | 
| 331 |  | 
| 332 |  /*! | 
| 333 |      \fn QSGTexture::WrapMode QSGOpaqueTextureMaterial::horizontalWrapMode() const | 
| 334 |  | 
| 335 |      Returns this material's horizontal wrap mode. | 
| 336 |  | 
| 337 |      The default horizontal wrap mode is \c QSGTexture::ClampToEdge. | 
| 338 |   */ | 
| 339 |  | 
| 340 |  | 
| 341 |  | 
| 342 | /*! | 
| 343 |     \fn void QSGOpaqueTextureMaterial::setVerticalWrapMode(QSGTexture::WrapMode mode) | 
| 344 |  | 
| 345 |     Sets the vertical wrap mode to \a mode. | 
| 346 |  | 
| 347 |     The vertical wrap mode is set on the texture instance just before the texture | 
| 348 |     is bound for rendering. | 
| 349 |  */ | 
| 350 |  | 
| 351 |  | 
| 352 |  | 
| 353 |  /*! | 
| 354 |      \fn QSGTexture::WrapMode QSGOpaqueTextureMaterial::verticalWrapMode() const | 
| 355 |  | 
| 356 |      Returns this material's vertical wrap mode. | 
| 357 |  | 
| 358 |      The default vertical wrap mode is \c QSGTexture::ClampToEdge. | 
| 359 |   */ | 
| 360 |  | 
| 361 | /*! | 
| 362 |   \fn void QSGOpaqueTextureMaterial::setAnisotropyLevel(QSGTexture::AnisotropyLevel level) | 
| 363 |  | 
| 364 |   Sets this material's anistropy level to \a level. | 
| 365 | */ | 
| 366 |  | 
| 367 | /*! | 
| 368 |   \fn QSGTexture::AnisotropyLevel QSGOpaqueTextureMaterial::anisotropyLevel() const | 
| 369 |  | 
| 370 |   Returns this material's anistropy level. | 
| 371 | */ | 
| 372 |  | 
| 373 | /*! | 
| 374 |     \internal | 
| 375 |  */ | 
| 376 |  | 
| 377 | int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const | 
| 378 | { | 
| 379 |     Q_ASSERT(o && type() == o->type()); | 
| 380 |     const QSGOpaqueTextureMaterial *other = static_cast<const QSGOpaqueTextureMaterial *>(o); | 
| 381 |     if (int diff = m_texture->comparisonKey() - other->texture()->comparisonKey()) | 
| 382 |         return diff; | 
| 383 |     return int(m_filtering) - int(other->m_filtering); | 
| 384 | } | 
| 385 |  | 
| 386 |  | 
| 387 |  | 
| 388 | /*! | 
| 389 |     \class QSGTextureMaterial | 
| 390 |     \brief The QSGTextureMaterial class provides a convenient way of | 
| 391 |     rendering textured geometry in the scene graph. | 
| 392 |     \inmodule QtQuick | 
| 393 |     \ingroup qtquick-scenegraph-materials | 
| 394 |  | 
| 395 |     \warning This utility class is only functional when running with the | 
| 396 |     default backend of the Qt Quick scenegraph. | 
| 397 |  | 
| 398 |     The textured material will fill every pixel in a geometry with | 
| 399 |     the supplied texture. | 
| 400 |  | 
| 401 |     The geometry to be rendered with a texture material requires | 
| 402 |     vertices in attribute location 0 and texture coordinates in attribute | 
| 403 |     location 1. The texture coordinate is a 2-dimensional floating-point | 
| 404 |     tuple. The QSGGeometry::defaultAttributes_TexturedPoint2D returns an | 
| 405 |     attribute set compatible with this material. | 
| 406 |  | 
| 407 |     The texture to be rendered can be set using setTexture(). How the | 
| 408 |     texture should be rendered can be specified using setMipmapFiltering(), | 
| 409 |     setFiltering(), setHorizontalWrapMode() and setVerticalWrapMode(). | 
| 410 |     The rendering state is set on the texture instance just before it | 
| 411 |     is bound. | 
| 412 |  | 
| 413 |     The textured material respects the current matrix and the alpha | 
| 414 |     channel of the texture. It will also respect the accumulated opacity | 
| 415 |     in the scenegraph. | 
| 416 |  | 
| 417 |     A texture material must have a texture set before it is used as | 
| 418 |     a material in the scene graph. | 
| 419 |  */ | 
| 420 |  | 
| 421 | /*! | 
| 422 |     \internal | 
| 423 |  */ | 
| 424 |  | 
| 425 | QSGMaterialType *QSGTextureMaterial::type() const | 
| 426 | { | 
| 427 |     static QSGMaterialType type; | 
| 428 |     return &type; | 
| 429 | } | 
| 430 |  | 
| 431 | /*! | 
| 432 |     \internal | 
| 433 |  */ | 
| 434 |  | 
| 435 | QSGMaterialShader *QSGTextureMaterial::createShader() const | 
| 436 | { | 
| 437 |     if (flags().testFlag(flag: RhiShaderWanted)) | 
| 438 |         return new QSGTextureMaterialRhiShader; | 
| 439 |     else | 
| 440 |         return new QSGTextureMaterialShader; | 
| 441 | } | 
| 442 |  | 
| 443 |  | 
| 444 | QSGTextureMaterialShader::QSGTextureMaterialShader() | 
| 445 | { | 
| 446 | #if QT_CONFIG(opengl) | 
| 447 |     setShaderSourceFile(type: QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/scenegraph/shaders/texture.frag" )); | 
| 448 | #endif | 
| 449 | } | 
| 450 |  | 
| 451 | void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) | 
| 452 | { | 
| 453 |     Q_ASSERT(oldEffect == nullptr || newEffect->type() == oldEffect->type()); | 
| 454 | #if QT_CONFIG(opengl) | 
| 455 |     if (state.isOpacityDirty()) | 
| 456 |         program()->setUniformValue(location: m_opacity_id, value: state.opacity()); | 
| 457 | #endif | 
| 458 |     QSGOpaqueTextureMaterialShader::updateState(state, newEffect, oldEffect); | 
| 459 | } | 
| 460 |  | 
| 461 | void QSGTextureMaterialShader::initialize() | 
| 462 | { | 
| 463 |     QSGOpaqueTextureMaterialShader::initialize(); | 
| 464 | #if QT_CONFIG(opengl) | 
| 465 |     m_opacity_id = program()->uniformLocation(name: "opacity" ); | 
| 466 | #endif | 
| 467 | } | 
| 468 |  | 
| 469 |  | 
| 470 | QSGTextureMaterialRhiShader::QSGTextureMaterialRhiShader() | 
| 471 | { | 
| 472 |     setShaderFileName(stage: VertexStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.vert.qsb" )); | 
| 473 |     setShaderFileName(stage: FragmentStage, QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/texture.frag.qsb" )); | 
| 474 | } | 
| 475 |  | 
| 476 | bool QSGTextureMaterialRhiShader::updateUniformData(RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) | 
| 477 | { | 
| 478 |     bool changed = false; | 
| 479 |     QByteArray *buf = state.uniformData(); | 
| 480 |  | 
| 481 |     if (state.isOpacityDirty()) { | 
| 482 |         const float opacity = state.opacity(); | 
| 483 |         memcpy(dest: buf->data() + 64, src: &opacity, n: 4); | 
| 484 |         changed = true; | 
| 485 |     } | 
| 486 |  | 
| 487 |     changed |= QSGOpaqueTextureMaterialRhiShader::updateUniformData(state, newMaterial, oldMaterial); | 
| 488 |  | 
| 489 |     return changed; | 
| 490 | } | 
| 491 |  | 
| 492 | QT_END_NAMESPACE | 
| 493 |  |