mercredi 28 avril 2021

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.

Aucun commentaire:

Enregistrer un commentaire