-
Bug
-
Resolution: Incomplete
-
P2: Important
-
None
-
5.9.1
-
None
Please seeĀ my StackOverflow question.
What I'm doing, in short:
Deriving class MyItem from QQuickFramebufferObject. Drawing a simple textured triangle MyItem. The texture is taken from a QML item.
Wrapping MyItem in a MyItemWrapper.qml component. On Component.onCompleted:, I make a delay and then call myItem.update()
I have a scrollable (with the mouse wheel) GridView of MyItemWrapper items
The items that are initially in the viewport show fine. But when I scroll down, the items that come into the viewport don't show at all. They only show when I hover them, since I've added a test MouseArea.onEntered that calls myItem.update(). I've observed this with 2 different systems with different GPUs.
I've tried enabling OpenGL debug logging for this testcase, but it prints no errors.
I've tried setting cacheBuffer: Number.MAX_SAFE_INTEGER on the GridView, to no avail.
Any ideas?
My code:
main.cpp:
#include <QQmlApplicationEngine> #include <QGuiApplication> #include "myitem.h" int main(int argc, char** argv) { qmlRegisterType<MyItem>("MyItem", 1, 0, "MyItem"); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
myitem.cpp:
#include "myitem.h" #include <QOpenGLFramebufferObject> #include <QSGTextureProvider> #include <QSGTexture> #include <QQuickWindow> #include <QOpenGLBuffer> #include <QOpenGLShaderProgram> #include "mesh.h" class MyItemRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions { public: MyItemRenderer() { initializeOpenGLFunctions(); m_program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/flat.vert.glsl"); m_program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/flat.frag.glsl"); m_program.bind(); m_program.bindAttributeLocation("aPos", Mesh::posAttribLocation); m_program.link(); m_program.setUniformValue("uTex", 0); } void synchronize(QQuickFramebufferObject* qqfbo){ auto item = (MyItem*)qqfbo; m_window = item->window(); m_tex = item->sourceItem()->textureProvider()->texture(); } QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) { QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); return new QOpenGLFramebufferObject(size, format); } void render() { glDisable(GL_DEPTH_TEST); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); m_program.bind(); m_mesh.vao.bind(); glActiveTexture(GL_TEXTURE0); m_tex->bind(); glDrawArrays(GL_TRIANGLES, 0, 3); m_window->resetOpenGLState(); } private: QQuickWindow* m_window; Mesh m_mesh; QSGTexture* m_tex; QOpenGLShaderProgram m_program; }; QQuickFramebufferObject::Renderer *MyItem::createRenderer() const { return new MyItemRenderer(); }
myitem.h:
#ifndef MYITEM_H #define MYITEM_H #include <QQuickFramebufferObject> #include "propertyhelper.h" // this file is from http://syncor.blogspot.bg/2014/11/qt-auto-property.html class MyItem : public QQuickFramebufferObject { Q_OBJECT AUTO_PROPERTY(QQuickItem*, sourceItem) public: Renderer *createRenderer() const; }; #endif
mesh.h
#ifndef MESH_H #define MESH_H #include <QOpenGLFunctions> #include <QOpenGLVertexArrayObject> #include <QOpenGLBuffer> class Mesh : protected QOpenGLFunctions { template<class T> int getNumBytes(std::vector<T> vec) { return vec.size() * sizeof(T); } public: Mesh() : vertexPosBuffer(QOpenGLBuffer::VertexBuffer) { initializeOpenGLFunctions(); std::vector<float> vertexPosData { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0 }; vao.create(); QOpenGLVertexArrayObject::Binder binder(&vao); vertexPosBuffer.create(); vertexPosBuffer.bind(); vertexPosBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw); vertexPosBuffer.allocate(vertexPosData.data(), getNumBytes(vertexPosData)); glEnableVertexAttribArray(posAttribLocation); vertexPosBuffer.bind(); glVertexAttribPointer(posAttribLocation, 2, GL_FLOAT, false, 0, 0); } QOpenGLBuffer vertexPosBuffer; QOpenGLVertexArrayObject vao; static const int posAttribLocation = 1; }; #endif // MESH_H
main.qml:
import QtQuick 2.5 import QtQuick.Window 2.2 Window { visible: true id: window width: 700 height: 700 GridView { id: grid anchors.fill: parent cellWidth: 350 cellHeight: 350 model: 20 delegate: MyItemWrapper { } } }
MyItemWrapper.qml:
import QtQuick 2.5 import MyItem 1.0 Item { width: grid.cellWidth height: grid.cellHeight Rectangle { id: texSource x: -10000 layer.enabled: true color: "red" width: 100 height: 100 } MyItem { anchors.fill: parent id: myItem sourceItem: texSource } MouseArea { id: mouseArea hoverEnabled: true anchors.fill: parent onEntered: { myItem.update(); } } function connectSingleShot(sig, slot) { var f = function() { slot.apply(this, arguments) sig.disconnect(f) } sig.connect(f) } Component.onCompleted: { connectSingleShot(window.afterRendering, function() { myItem.update(); }); } }
flat.frag.glsl:
#version 150
in highp vec2 vTexCoord;
out vec4 outputColor;
uniform sampler2D uTex;
void main() {
outputColor = texture(uTex, vTexCoord);
}
flat.vert.glsl:
#version 150
in highp vec2 aPos;
out highp vec2 vTexCoord;
void main() {
gl_Position = vec4(aPos, 0.0, 1.0);
vTexCoord = aPos * .5 + .5;
}
I think the problem is very likely related to this older problem of mine. With this in mind, I tried two things:
reparent the relevant items to have parent null during the myItem.update() line, then reparent them back. This was intended to avoid the GL rendering being affected by some middleman component of the GridView. But the result was that no items were ever displayed, for some reason.
use a Connections to connect to the onVisibleChanged signal of the MyItemWrapper, and of its parent, and of it's parent's parents. In the signal handler I had a console.log. It never got executed.
I've traced the Qt code down to this point:
http://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/quick/items/qquickwindow.cpp?h=v5.9.1#n3148
Here it sets opacity=0 for culled items. I don't know how to continue from here though.