Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

About QSGGeometryNode and WebAssembly in QT



  • I'm trying to deploy my project on the Web with WebAssembly and encountered some problems.

    The project made a custom rendering with QSGRenderNode and ran on the web.

    And I'm getting error "INVALID OPERATION insufficient buffer size".

    Here's my code bellow.

    openglerenderer.h

    #ifndef OPENGLRENDERER_H
    #define OPENGLRENDERER_H
    
    #include <qsgrendernode.h>
    #include <QQuickItem>
    #include "webaccess/render/baserender.h"
    
    #if QT_CONFIG(opengl)
    
    
    class OpenGLRenderNode : public QSGRenderNode
    {
    public:
        ~OpenGLRenderNode();
    
        void render(const RenderState *state) override;
        void releaseResources() override;
        StateFlags changedStates() const override;
        RenderingFlags flags() const override;
        QRectF rect() const override;
    
        void sync(QQuickItem *item);
    
    private:
        void init();
        int m_width = 0;
        int m_height = 0;
        bool beInit = false;
        BaseRender* m_render = nullptr;
    };
    
    #endif
    
    #endif // OPENGLRENDERER_H
    

    openglerenderer.cpp

    #include "openglrenderer.h"
    #include <QQuickItem>
    
    #if QT_CONFIG(opengl)
    
    #include <QOpenGLFunctions>
    #include <QOpenGLExtraFunctions>
    #include <QQuickWindow>
    
    #include "webaccess/render/tutorial/les1.h"
    #include "webaccess/render/tutorial/les2.h"
    #include "webaccess/render/tutorial/les3.h"
    #include "webaccess/render/tutorial/les4.h"
    
    OpenGLRenderNode::~OpenGLRenderNode()
    {
        releaseResources();
    }
    
    void OpenGLRenderNode::releaseResources()
    {
        if (m_render) {
            m_render->releaseResources();
        }
    }
    
    void OpenGLRenderNode::init()
    {
        if (m_render) {
            m_render->init();
            beInit = true;
        }
    }
    
    void OpenGLRenderNode::render(const RenderState *state)
    {
        if (!beInit)
            init();
        if (m_render) {
            m_render->render(state);
        }
    }
    
    QSGRenderNode::StateFlags OpenGLRenderNode::changedStates() const
    {
        return BlendState | ScissorState | StencilState;
    }
    
    QSGRenderNode::RenderingFlags OpenGLRenderNode::flags() const
    {
        return BoundedRectRendering | DepthAwareRendering;
    }
    
    QRectF OpenGLRenderNode::rect() const
    {
        return QRect(0, 0, m_width, m_height);
    }
    
    void OpenGLRenderNode::sync(QQuickItem *item)
    {
        m_width = static_cast<int>(item->width());
        m_height = static_cast<int>(item->height());
        if (!m_render) {
            m_render = static_cast<BaseRender*>(new les4{});
            if (m_render) {
                QObject::connect(item->window(), &QQuickWindow::beforeRendering, m_render, [&]() { m_render->beforeRender(); }, Qt::DirectConnection);
            }
        }
        if (m_render) {
            m_render->sync(item);
            m_render->setViewportSize(item->size().toSize() * item->window()->devicePixelRatio());
            m_render->setPosition(item->position().toPoint());
            m_render->setWindow(item->window());
        }
    }
    
    #endif
    

    les4.h

    #ifndef LES4_H
    #define LES4_H
    
    #include "../baserender.h"
    
    class QOpenGLTexture;
    class QOpenGLShaderProgram;
    class QOpenGLBuffer;
    class QOpenGLVertexArrayObject;
    
    class les4 : public BaseRender
    {
    public:
        les4();
    
        ~les4() override;
        virtual void init() override;
        virtual void render(const QSGRenderNode::RenderState *state) override;
        virtual void sync(QQuickItem *item) override;
        virtual void releaseResources() override;
    
        virtual void setViewportSize(QSize size) override { m_viewportSize = size; }
        virtual void setPosition(QPoint point) override { m_position = point; }
        virtual void setWindow(QQuickWindow* window) override { m_window = window; }
        virtual void beforeRender() override;
    
    private:
        QSize m_viewportSize{};
        QPoint m_position{};
        QQuickWindow* m_window{};
    
        QOpenGLShaderProgram *m_program = nullptr;
        QOpenGLVertexArrayObject *m_vao = nullptr;
        QOpenGLBuffer *m_vbo = nullptr;
        QOpenGLBuffer *m_ibo = nullptr;
    
        int m_width = 0;
        int m_height = 0;
    };
    
    #endif // LES4_H
    

    les4.cpp

    #include "les4.h"
    #include <QQuickWindow>
    #include <QOpenGLContext>
    #include <QOpenGLTexture>
    #include <QOpenGLShaderProgram>
    #include <QOpenGLBuffer>
    #include <QOpenGLVertexArrayObject>
    #include <QOpenGLFunctions>
    #include <QGuiApplication>
    
    static const char *vertexShaderSource =
            "#version 100\n"
            "attribute vec3 aPos;\n"
            "attribute vec3 aColor;\n"
            "varying vec3 ourColor;\n"
            "void main() {\n"
            "   gl_Position = vec4(aPos.xyz, 1.0);\n"
            "   ourColor = aColor;\n"
            "}";
    
    static const char *fragmentShaderSource =
            "#version 100\n"
    #if defined(Q_OS_HTML5) or defined(Q_OS_WASM) or defined(__EMSCRIPTEN__)
            "precision mediump float;\n"
    #endif
            "varying vec3 ourColor;\n"
            "void main() {\n"
            "   gl_FragColor = vec4(ourColor, 1.0);\n"
            "}";
    
    static float vertices[] {
        // 位置              // 顏色
         0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // 右下
        -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // 左下
         0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // 頂部
    };
    
    static unsigned int indices[] {
        0, 1, 2
    };
    
    les4::les4()
    {
    
    }
    
    les4::~les4()
    {
    
    }
    
    void les4::init() {
        QSurfaceFormat fmt;
        fmt.setVersion(2, 0);
        fmt.setRenderableType(QSurfaceFormat::OpenGLES);
        fmt.setMajorVersion(2);
        fmt.setMinorVersion(0);
        fmt.setRedBufferSize(5);
        fmt.setGreenBufferSize(6);
        fmt.setBlueBufferSize(5);
        fmt.setAlphaBufferSize(0);
        fmt.setDepthBufferSize(0);
    
        QSurfaceFormat::setDefaultFormat(fmt);
    
        QOpenGLContext *ctx = QOpenGLContext::currentContext();
        ctx->setFormat(fmt);
    }
    
    void les4::releaseResources() {
        delete m_program;
        m_program = nullptr;
    
        delete m_vbo;
        m_vbo = nullptr;
    
        delete m_ibo;
        m_ibo = nullptr;
    
        delete m_vao;
        m_vao = nullptr;
    }
    
    void les4::beforeRender() {
    
    }
    
    void les4::render(const QSGRenderNode::RenderState*) {
    
        QOpenGLContext *ctx = QOpenGLContext::currentContext();
    
    #if defined(Q_OS_HTML5) or defined(Q_OS_WASM) or defined(__EMSCRIPTEN__)
    const bool isCoreProfile  = false;
    #else
    const bool isCoreProfile  = ctx->format().profile() == QSurfaceFormat::CoreProfile;
    #endif
    
        QOpenGLFunctions *f = ctx->functions();
    
        int y = (m_window->size()* m_window->devicePixelRatio()).height() - m_viewportSize.height() - m_position.y();
        f->glViewport(m_position.x(), y, m_viewportSize.width(), m_viewportSize.height());
        f->glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        f->glClear(GL_COLOR_BUFFER_BIT);
    
        auto setupVertAttrs = [this, f] {
            m_vbo->bind();
            f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)0);
            f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
            f->glEnableVertexAttribArray(0);
            f->glEnableVertexAttribArray(1);
        };
    
        if (!m_program) {
            m_program = new QOpenGLShaderProgram;
            m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
            m_program->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
            m_program->bindAttributeLocation("aPos", 0);
            m_program->bindAttributeLocation("aColor", 1);
            m_program->link();
    
            m_vao = new QOpenGLVertexArrayObject;
            m_vao->create();
    
            m_vbo = new QOpenGLBuffer;
            m_vbo->create();
    
            m_ibo = new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer);
            m_ibo->create();
        }
    
        // non-premultiplied alpha
        f->glEnable(GL_BLEND);
        f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        // no backface culling
        f->glDisable(GL_CULL_FACE);
        // still need depth test to test against the items rendered in the opaque pass
        f->glEnable(GL_DEPTH_TEST);
        // but no need to write out anything to the depth buffer
        f->glDepthMask(GL_FALSE);
        // do not write out alpha
        f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE);
        // will always scissor
        f->glEnable(GL_SCISSOR_TEST);
    
        if (m_vao->isCreated())
            m_vao->bind();
    
        m_program->bind();
    
        m_vbo->bind();
        m_vbo->allocate(vertices, sizeof(vertices));
        m_ibo->bind();
        m_ibo->allocate(indices, sizeof(indices));
    
        setupVertAttrs();
    
        //scissor...
        //texture...
        f->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
        f->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    }
    
    void les4::sync(QQuickItem *item) {
      //  qDebug() << "w:" << item->width() << " h:" << item->height();
        m_width = static_cast<int>(item->width());
        m_height = static_cast<int>(item->height());
    }
    

    Please help me. I'm stuck here for a long time.



  • I figure out the solution.
    First there is supposed to be three indices in my elements. The second argument of the function glDrawElements should be 3.
    Second there's a limitation in webgl that the type of element supposed to be GL_UNSIGNED_SHORT.


Log in to reply