Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QT6 Render QML to images using QQuickRenderControl
Forum Updated to NodeBB v4.3 + New Features

QT6 Render QML to images using QQuickRenderControl

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
3 Posts 2 Posters 929 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Aujo
    wrote on 3 Mar 2024, 17:18 last edited by
    #1

    I am looking for some sample code snnipets to render a qml (animated) to set of png images offscreen using framebuffer as similar to the implementation mentioned in the below forum

    https://www.qt.io/blog/2017/02/21/making-movies-qml

    I have tried using the QQuickWindow and QquickRenderControl libraries of QT6 but its not working.

    Not sure how to initialise the QquickRenderControl with the framebuffer object as the initialize object wont take OpenGLContext in QT6 . Any help is much appreciated . Thanks

    Z 1 Reply Last reply 5 Mar 2024, 06:57
    0
    • A Aujo
      3 Mar 2024, 17:18

      I am looking for some sample code snnipets to render a qml (animated) to set of png images offscreen using framebuffer as similar to the implementation mentioned in the below forum

      https://www.qt.io/blog/2017/02/21/making-movies-qml

      I have tried using the QQuickWindow and QquickRenderControl libraries of QT6 but its not working.

      Not sure how to initialise the QquickRenderControl with the framebuffer object as the initialize object wont take OpenGLContext in QT6 . Any help is much appreciated . Thanks

      Z Offline
      Z Offline
      ZeroZero
      wrote on 5 Mar 2024, 06:57 last edited by
      #2

      @Aujo In Qt 6, you need to set QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); before QGuiApplication app(argc, argv); to use the old way of rendering.

      A 1 Reply Last reply 16 Mar 2024, 10:57
      0
      • Z ZeroZero
        5 Mar 2024, 06:57

        @Aujo In Qt 6, you need to set QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); before QGuiApplication app(argc, argv); to use the old way of rendering.

        A Offline
        A Offline
        Aujo
        wrote on 16 Mar 2024, 10:57 last edited by
        #3

        @ZeroZero Thanks for your response below is my code refactored for QT6 . I have set q->setGraphicsApi(QSGRendererInterface::OpenGL); here previously .

        Was getting the below error.

        error:
        QQuickWindow: No render target (neither swapchain nor custom target was provided)

        Moving that to main as you mentioned still get the same error with some additional .

        int main(int argc, char *argv[])
        {
        {
        QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
        QCoreApplication app(argc, argv);
        ....
        ........................................................................................
        Error:
        Framebuffer incomplete: 0x8cd6
        Failed to build texture render target for QQuickRenderTarget
        QQuickWindow: No render target (neither swapchain nor custom target was provided)

        Refactored Code for QT6 that I am struggling to make it work

        #include "fboquickwindow.h"
        #include <QOffscreenSurface>
        #include <QOpenGLContext>
        #include <QOpenGLFramebufferObject>
        #include <QOpenGLFunctions>
        #include <QQuickRenderControl>
        #include <QTimer>
        #include <QQuickRenderTarget>
        class FboQuickWindowPrivate : public QObject
        {
            Q_OBJECT
            Q_DECLARE_PUBLIC(FboQuickWindow)
            Q_DISABLE_COPY(FboQuickWindowPrivate)
        
        public:
            FboQuickWindowPrivate(FboQuickWindow *q_ptr);
            ~FboQuickWindowPrivate();
        
            static FboQuickWindowPrivate *create(FboQuickWindowPrivate *&d_ptr, FboQuickWindow *q_ptr);
        
        public slots:
            void sceneGraphInitialized();
            void sceneGraphInvalidated();
            void renderRequested();
            void sceneChanged();
        
        public:
            void render();
        
        public:
            QOpenGLContext *context;
            QOffscreenSurface *offscreenSurface;
            QQuickRenderControl *renderControl;
            QOpenGLFramebufferObject *fbo;
            bool needsPolishAndSync;
            QTimer updateTimer;
        
            FboQuickWindow * const q_ptr;
        };
        
        FboQuickWindowPrivate::FboQuickWindowPrivate(FboQuickWindow *q_ptr) :
            fbo(0),
            needsPolishAndSync(false),
            q_ptr(q_ptr)
        {
            updateTimer.setSingleShot(true);
            updateTimer.setInterval(5);
        
            connect(&updateTimer, &QTimer::timeout, this, &FboQuickWindowPrivate::render);
        
            renderControl = new QQuickRenderControl;
        
            connect(renderControl, &QQuickRenderControl::renderRequested, this, &FboQuickWindowPrivate::renderRequested);
            connect(renderControl, &QQuickRenderControl::sceneChanged, this, &FboQuickWindowPrivate::sceneChanged);
        
            QSurfaceFormat format;
            format.setDepthBufferSize(16);
            format.setStencilBufferSize(8);
        
            context = new QOpenGLContext;
            context->setFormat(format);
            context->create();
        
            offscreenSurface = new QOffscreenSurface;
            offscreenSurface->setFormat(context->format());
            offscreenSurface->create();
        }
        
        FboQuickWindowPrivate::~FboQuickWindowPrivate()
        {
            context->makeCurrent(offscreenSurface);
            delete renderControl;
            context->doneCurrent();
            delete offscreenSurface;
            delete context;
        }
        
        FboQuickWindowPrivate *FboQuickWindowPrivate::create(FboQuickWindowPrivate *&d_ptr,
                                                             FboQuickWindow *q_ptr)
        {
            return (d_ptr = new FboQuickWindowPrivate(q_ptr));
        }
        
        void FboQuickWindowPrivate::sceneGraphInitialized()
        {
            Q_Q(FboQuickWindow);
        
            Q_ASSERT(context);
            Q_ASSERT(!fbo);
        
            fbo = new QOpenGLFramebufferObject(QSize(1, 1).expandedTo(q->size()),
                                               QOpenGLFramebufferObject::CombinedDepthStencil);
            QQuickRenderTarget rt = QQuickRenderTarget::fromOpenGLRenderBuffer(fbo->handle(), fbo->size() ,1);
            q->setGraphicsApi(QSGRendererInterface::OpenGL);
            q->setRenderTarget(rt);
        }
        
        void FboQuickWindowPrivate::sceneGraphInvalidated()
        {
            delete fbo;
            fbo = 0;
        }
        
        void FboQuickWindowPrivate::renderRequested()
        {
            if (!updateTimer.isActive())
                updateTimer.start();
        }
        
        void FboQuickWindowPrivate::sceneChanged()
        {
            needsPolishAndSync = true;
        
            if (!updateTimer.isActive())
                updateTimer.start();
        }
        
        void FboQuickWindowPrivate::render()
        {
            Q_Q(FboQuickWindow);
        
            if (!context->makeCurrent(offscreenSurface))
                return;
        
            // if (needsPolishAndSync) {
            //     renderControl->polishItems();
            //     renderControl->beginFrame();
            //     renderControl->sync();
            //     renderControl->endFrame();
            //     needsPolishAndSync = false;
            // }
            q->beginExternalCommands(); // Begin external OpenGL commands
            renderControl->beginFrame();
            renderControl->sync();
            renderControl->render();
            renderControl->endFrame();
            q->endExternalCommands(); // End external OpenGL commands
        
            // q->resetOpenGLState();
            //QOpenGLFramebufferObject::bindDefault();
            //context->functions()->glFlush();
        
            emit q->sceneRendered();
        }
        
        FboQuickWindow::FboQuickWindow() :
            QQuickWindow(FboQuickWindowPrivate::create(d_ptr, this)->renderControl)
        {
            Q_D(FboQuickWindow);
        
            connect(this, &QQuickWindow::sceneGraphInitialized, d, &FboQuickWindowPrivate::sceneGraphInitialized);
            connect(this, &QQuickWindow::sceneGraphInvalidated, d, &FboQuickWindowPrivate::sceneGraphInvalidated);
            d->context->makeCurrent(d->offscreenSurface);
        
            d->renderControl->initialize();
            // if (!d->renderControl->initialize())
            //     qWarning("Failed to initialize redirected Qt Quick rendering");
        
            d->context->doneCurrent();
        }
        
        FboQuickWindow::~FboQuickWindow()
        {
            delete d_ptr;
        }
        
        QImage FboQuickWindow::grab() const
        {
            Q_D(const FboQuickWindow);
        
            return d->renderControl->window()->grabWindow();
        }
        
        void FboQuickWindow::resize(const QSize &newSize)
        {
            QResizeEvent event(size(), newSize);
        
            setGeometry(0, 0, newSize.width(), newSize.height());
            resizeEvent(&event);
        }
        
        void FboQuickWindow::resize(int w, int h)
        {
            resize(QSize(w, h));
        }
        
        void FboQuickWindow::resizeEvent(QResizeEvent *event)
        {
            Q_D(FboQuickWindow);
        
            QQuickWindow::resizeEvent(event);
        
            Q_ASSERT(d->context);
        
            if (d->context->makeCurrent(d->offscreenSurface)) {
                d->sceneGraphInvalidated();
                d->sceneGraphInitialized();
                d->context->doneCurrent();
            }
        }
        
        #include "fboquickwindow.moc"
        
        

        And here is the original code that works with QT5

        #include "fboquickwindow.h"
        #include <QOffscreenSurface>
        #include <QOpenGLContext>
        #include <QOpenGLFramebufferObject>
        #include <QOpenGLFunctions>
        #include <QQuickRenderControl>
        #include <QTimer>
        
        class FboQuickWindowPrivate : public QObject
        {
            Q_OBJECT
            Q_DECLARE_PUBLIC(FboQuickWindow)
            Q_DISABLE_COPY(FboQuickWindowPrivate)
        
        public:
            FboQuickWindowPrivate(FboQuickWindow *q_ptr);
            ~FboQuickWindowPrivate();
        
            static FboQuickWindowPrivate *create(FboQuickWindowPrivate *&d_ptr, FboQuickWindow *q_ptr);
        
        public slots:
            void sceneGraphInitialized();
            void sceneGraphInvalidated();
            void renderRequested();
            void sceneChanged();
        
        public:
            void render();
        
        public:
            QOpenGLContext *context;
            QOffscreenSurface *offscreenSurface;
            QQuickRenderControl *renderControl;
            QOpenGLFramebufferObject *fbo;
            bool needsPolishAndSync;
            QTimer updateTimer;
        
            FboQuickWindow * const q_ptr;
        };
        
        FboQuickWindowPrivate::FboQuickWindowPrivate(FboQuickWindow *q_ptr) :
            fbo(0),
            needsPolishAndSync(false),
            q_ptr(q_ptr)
        {
            updateTimer.setSingleShot(true);
            updateTimer.setInterval(5);
        
            connect(&updateTimer, &QTimer::timeout, this, &FboQuickWindowPrivate::render);
        
            renderControl = new QQuickRenderControl;
        
            connect(renderControl, &QQuickRenderControl::renderRequested, this, &FboQuickWindowPrivate::renderRequested);
            connect(renderControl, &QQuickRenderControl::sceneChanged, this, &FboQuickWindowPrivate::sceneChanged);
        
            QSurfaceFormat format;
            format.setDepthBufferSize(16);
            format.setStencilBufferSize(8);
        
            context = new QOpenGLContext;
            context->setFormat(format);
            context->create();
        
            offscreenSurface = new QOffscreenSurface;
            offscreenSurface->setFormat(context->format());
            offscreenSurface->create();
        }
        
        FboQuickWindowPrivate::~FboQuickWindowPrivate()
        {
            context->makeCurrent(offscreenSurface);
            delete renderControl;
            context->doneCurrent();
            delete offscreenSurface;
            delete context;
        }
        
        FboQuickWindowPrivate *FboQuickWindowPrivate::create(FboQuickWindowPrivate *&d_ptr,
                                                             FboQuickWindow *q_ptr)
        {
            return (d_ptr = new FboQuickWindowPrivate(q_ptr));
        }
        
        void FboQuickWindowPrivate::sceneGraphInitialized()
        {
            Q_Q(FboQuickWindow);
        
            Q_ASSERT(context);
            Q_ASSERT(!fbo);
        
            fbo = new QOpenGLFramebufferObject(QSize(1, 1).expandedTo(q->size()),
                                               QOpenGLFramebufferObject::CombinedDepthStencil);
            q->setRenderTarget(fbo);
        }
        
        void FboQuickWindowPrivate::sceneGraphInvalidated()
        {
            delete fbo;
            fbo = 0;
        }
        
        void FboQuickWindowPrivate::renderRequested()
        {
            if (!updateTimer.isActive())
                updateTimer.start();
        }
        
        void FboQuickWindowPrivate::sceneChanged()
        {
            needsPolishAndSync = true;
        
            if (!updateTimer.isActive())
                updateTimer.start();
        }
        
        void FboQuickWindowPrivate::render()
        {
            Q_Q(FboQuickWindow);
        
            if (!context->makeCurrent(offscreenSurface))
                return;
        
            if (needsPolishAndSync) {
                renderControl->polishItems();
                renderControl->sync();
                needsPolishAndSync = false;
            }
        
            renderControl->render();
        
            q->resetOpenGLState();
            QOpenGLFramebufferObject::bindDefault();
            context->functions()->glFlush();
        
            emit q->sceneRendered();
        }
        
        FboQuickWindow::FboQuickWindow() :
            QQuickWindow(FboQuickWindowPrivate::create(d_ptr, this)->renderControl)
        {
            Q_D(FboQuickWindow);
        
            connect(this, &QQuickWindow::sceneGraphInitialized, d, &FboQuickWindowPrivate::sceneGraphInitialized);
            connect(this, &QQuickWindow::sceneGraphInvalidated, d, &FboQuickWindowPrivate::sceneGraphInvalidated);
            d->context->makeCurrent(d->offscreenSurface);
            d->renderControl->initialize(d->context);
            d->context->doneCurrent();
        }
        
        FboQuickWindow::~FboQuickWindow()
        {
            delete d_ptr;
        }
        
        QImage FboQuickWindow::grab() const
        {
            Q_D(const FboQuickWindow);
        
            return d->renderControl->grab();
        }
        
        void FboQuickWindow::resize(const QSize &newSize)
        {
            QResizeEvent event(size(), newSize);
        
            setGeometry(0, 0, newSize.width(), newSize.height());
            resizeEvent(&event);
        }
        
        void FboQuickWindow::resize(int w, int h)
        {
            resize(QSize(w, h));
        }
        
        void FboQuickWindow::resizeEvent(QResizeEvent *event)
        {
            Q_D(FboQuickWindow);
        
            QQuickWindow::resizeEvent(event);
        
            Q_ASSERT(d->context);
        
            if (d->context->makeCurrent(d->offscreenSurface)) {
                d->sceneGraphInvalidated();
                d->sceneGraphInitialized();
                d->context->doneCurrent();
            }
        }
        
        #include "fboquickwindow.moc"
        
        

        Any thoughts or inputs is very helpful, many thanks.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved