Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-62611

Combination QQuickFramebufferObject+texturing+GridView doesn't show items when you scroll to them

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Incomplete
    • Icon: P2: Important P2: Important
    • None
    • 5.9.1
    • Quick: SceneGraph
    • 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.

        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            sletta Gunnar Sletta
            stefan_monov Stefan Monov
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved:

                There are no open Gerrit changes