-
Bug
-
Resolution: Done
-
P1: Critical
-
5.15, 6.2.2
-
None
-
-
81bbd0b45a (qt/qtdeclarative/dev) 81bbd0b45a (qt/tqtc-qtdeclarative/dev) 5561df5ac4 (qt/qtdeclarative/6.2) 5561df5ac4 (qt/tqtc-qtdeclarative/6.2) 27daadc214 (qt/qtdeclarative/6.3) 684ed0323c (qt/tqtc-qtquickcontrols2/5.15)
Using QQuickNinePatch Image as a provider, an crash occurs on QQuickOpenGLShaderEffectMaterial::updateTextures() in qt5.15 and QSGRhiShaderEffectNode::preprocess() in Qt6.2.
The brief reason of this crash is that ShaderEffect is trying to use wrong texture invalidated already by wrong image source.
The major factors of this crash are
- use QQuickNinePatchImage.
- QQuickNinePatchImage's cache: false.
- use the QQuickNinePatchImage as a source of other Shader related object like ShaderEffect or OpacityMask or something.
- change the QQuickNinePatchImage's source to invalid image after running with valid image.
- after above, update them.
Test codes are below.
Window { id: root width: 640 height: 480 visible: true title: qsTr("Hello World") NinePatchImage { id: np source : "qrc://aaa.png" // any valid image. cache: false visible: false } /* * this is for Qt6 ShaderEffect { width: 300 height: 300 property variant source: np property real amplitude: 0.04 property real frequency: 20 property real time: 0 fragmentShader: "content/shaders/wobble.frag.qsb" // any shader codes. this fragment shader code was from QtQuick ShaderEffect example } */ // this is for Qt5 ShaderEffect { width: 300 height: 300 property variant src: np // any vertex shader vertexShader: " uniform highp mat4 qt_Matrix; attribute highp vec4 qt_Vertex; attribute highp vec2 qt_MultiTexCoord0; varying highp vec2 coord; void main() { coord = qt_MultiTexCoord0; gl_Position = qt_Matrix * qt_Vertex; }" // any fragment shader fragmentShader: " varying highp vec2 coord; uniform sampler2D src; uniform lowp float qt_Opacity; void main() { lowp vec4 tex = texture2D(src, coord); gl_FragColor = vec4(vec3(dot(tex.rgb, vec3(0.344, 0.5, 0.156))), tex.a) * qt_Opacity; }" } Timer{ running: true interval: 2000 onTriggered: { np.source ="" } } MouseArea { anchors.fill: parent onClicked: { root.update(); } } }
If QQuickImage is used instead, these is no problem because QQuickImage updates provider's texture before checking invalidation of current texture while updating like this.
// qtdeclarative/src/quick/items/qquickimage.cpp QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) { Q_D(QQuickImage); QSGTexture *texture = d->sceneGraphRenderContext()->textureForFactory(d->pix.textureFactory(), window()); // Copy over the current texture state into the texture provider... if (d->provider) { d->provider->m_smooth = d->smooth; d->provider->m_mipmap = d->mipmap; d->provider->updateTexture(texture); } if (!texture || width() <= 0 || height() <= 0) { delete oldNode; return nullptr; } // ... }
in QQuickNinePatchImage, however, provider's texture remains regardless whether current image is valid or not. it seems to cause dangling problem.