Drawing in QQuickFramebufferObject via texture taken from an Item. It fails unless I repaint/update constantly
Unsolved
QML and Qt Quick
-
What my code does, in short:
- Create a simple
Rectangle
namedrect
, withlayer.enabled: true
. - Pass
rect
to an instance of myQQuickFramebufferObject
subclass calleditemSnapshotter
- In
synchronize
, take a copy of the texture provided byrect
- In
render
, draw a rectangle textured with the texture I took - When
main.qml
finishes loading, callitemSnapshotter.update();
for the first and only time.
The problem is that the QQFBO draws nothing, unless I uncomment the
update
call at the end ofrender()
. Any idea why?My code:
main.cpp:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QQuickFramebufferObject> #include <QOpenGLFramebufferObject> #include <QSGTextureProvider> #include <QObject> #include <QOpenGLFunctions> #include <QOpenGLShaderProgram> #include <QOpenGLBuffer> #include <QQuickWindow> #include <QOpenGLFunctions> // propertyhelper.h is from http://syncor.blogspot.bg/2014/11/qt-auto-property.html #include "propertyhelper.h" class ItemSnapshotter : public QQuickFramebufferObject { Q_OBJECT AUTO_PROPERTY(QQuickItem*, sourceItem) public: Renderer *createRenderer() const; }; class ItemSnapshotterRenderer : public QObject , public QQuickFramebufferObject::Renderer , protected QOpenGLFunctions { Q_OBJECT public: ItemSnapshotterRenderer() { initializeOpenGLFunctions(); initShader(); createGeometry(); } void createGeometry() { m_vertices << QVector2D(0, 0) << QVector2D(0, 1) << QVector2D(1, 1); m_vertices << QVector2D(0, 0) << QVector2D(1, 0) << QVector2D(1, 1); } void initShader() { m_shaderProgram.addShaderFromSourceFile( QOpenGLShader::Vertex, ":/PassThrough.vert.glsl"); m_shaderProgram.addShaderFromSourceFile( QOpenGLShader::Fragment, ":/PassThrough.frag.glsl"); m_shaderProgram.link(); m_shaderProgram.bind(); glActiveTexture(GL_TEXTURE0); m_shaderProgram.setUniformValue("uTex", 0); } void prepareShader() { m_shaderProgram.enableAttributeArray("aPos"); m_shaderProgram.setAttributeArray("aPos", m_vertices.constData()); m_shaderProgram.bind(); } void render() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); prepareShader(); m_tex->bind(); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glDrawArrays(GL_TRIANGLES, 0, m_vertices.size()); m_window->resetOpenGLState(); //update(); } void synchronize(QQuickFramebufferObject* qqfbo){ auto parentItem = (ItemSnapshotter*)qqfbo; m_window = parentItem->window(); copyTexture(*parentItem); } void copyTexture(const ItemSnapshotter &srcItem) { QQuickItem* sourceItem = srcItem.sourceItem(); QSGTextureProvider* sourceTexProvider = sourceItem->textureProvider(); m_tex = sourceTexProvider->texture(); GLenum err; while ((err = glGetError()) != GL_NO_ERROR) { qDebug("\tgl error: 0x%x", err, 0, 16); } } QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) { QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); // TODO simpler format return new QOpenGLFramebufferObject(size, format); } private: QOpenGLShaderProgram m_shaderProgram; QQuickWindow* m_window; QSGTexture* m_tex; QVector<QVector2D> m_vertices; }; QQuickFramebufferObject::Renderer *ItemSnapshotter::createRenderer() const { return new ItemSnapshotterRenderer(); } int main(int argc, char *argv[]) { qmlRegisterType<ItemSnapshotter>("ItemSnapshotter", 1, 0, "ItemSnapshotter"); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); } #include "main.moc"
main.qml:
import QtQuick 2.6 import QtQuick.Window 2.2 import ItemSnapshotter 1.0 Window { visible: true width: 640 height: 480 Row { Rectangle { layer.enabled: true id: rect width: 100 height: 100 color: "red" border.color: "black" } ItemSnapshotter { id: itemSnapshotter sourceItem: rect width: sourceItem.width height: sourceItem.height } } Component.onCompleted: { itemSnapshotter.update(); } }
PassThrough.frag.glsl:
varying highp vec2 vTexCoord; uniform sampler2D uTex; void main() { gl_FragColor = texture2D(uTex, vTexCoord); }
PassThrough.vert.glsl:
attribute highp vec2 aPos; varying highp vec2 vTexCoord; void main() { gl_Position = vec4(aPos, 0.0, 1.0); vTexCoord = aPos; }
- Create a simple