# Qt 6.6.1 WebAssembly Error. WebGL: INVALID\_ENUM: bindFramebuffer: invalid target

**URL:** <https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398>\
**Category:** WebGL\
**Created:** [December 30, 2023, 12:07am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398 "2023-12-30T00:07:28Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![8Observer8](https://community.khronos.org/letter_avatar_proxy/v4/letter/8/bbe5ce/32.png) [@8Observer8](https://community.khronos.org/u/8Observer8)\
**Post date:** [December 30, 2023, 12:07am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/1 "2023-12-30T00:07:28Z")

</div>

Hi,

My example works on Desktop. It prints a color of a pixel with (0, 0) coordinates and OpenGL version:

![image](https://community.khronos.org/uploads/default/original/2X/2/2ff88207035f6aa19365b4c8f5500c96af277e42.png)

But when I try to build it for WebAssembly the browser prints this message: `WebGL: INVALID_ENUM: bindFramebuffer: invalid target`

main.cpp

```auto
#include <QtGui/QOpenGLExtraFunctions>
#include <QtGui/QSurfaceFormat>
#include <QtGui/QVector3D>
#include <QtOpenGL/QOpenGLFramebufferObject>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QWidget>
#include <QtWidgets/QVBoxLayout>
#include <QtOpenGLWidgets/QOpenGLWidget>

class OpenGLWidget : public QOpenGLWidget, private QOpenGLExtraFunctions
{
    Q_OBJECT

public:
    OpenGLWidget()
    {
        QSurfaceFormat surfaceFormat;
        surfaceFormat.setSamples(4);
        setFormat(surfaceFormat);
    }

signals:
    void showInfoSignal(const QString &openGLVersion, const QString &shadingVersion,
                        const QString &vendor);
    void showPixelColorSignal(const QVector3D &color);

private:
    void initializeGL() override
    {
        initializeOpenGLFunctions();
        glClearColor(0.f, 1.f, 0.f, 1.f);
        m_fbo.reset(new QOpenGLFramebufferObject(1, 1));
        QString version(QString("OpenGL version: %1").arg((const char*) glGetString(GL_VERSION)));
        QString shadingLanguageVersion(QString("GLSL version: %1")
                                           .arg((const char*) glGetString(GL_SHADING_LANGUAGE_VERSION)));
        QString vendor(QString("Vendor: %1").arg((const char*) glGetString(GL_VENDOR)));
        emit showInfoSignal(version, shadingLanguageVersion, vendor);
    }

    void paintGL() override
    {
        glClear(GL_COLOR_BUFFER_BIT);
        // Set draw buffer to be fbo. Read buffer is already the default one
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo->handle());
        // Blit from the default MSAA buffer to non-MSAA fbo
        glBlitFramebuffer(0, 0, m_fbo->width(), m_fbo->height(),
                          0, 0, m_fbo->width(), m_fbo->height(),
                          GL_COLOR_BUFFER_BIT, GL_NEAREST);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context()->defaultFramebufferObject());
        // Set read buffer
        glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo->handle());
        // Read the pixel
        GLubyte pixel[4];
        glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
        // Set read buffer back to default
        glBindBuffer(GL_READ_FRAMEBUFFER, context()->defaultFramebufferObject());
        emit showPixelColorSignal(QVector3D(pixel[0] / 255.f, pixel[1] / 255.f, pixel[2] / 255.f));
    }

private:
    std::unique_ptr<QOpenGLFramebufferObject> m_fbo;
};

class MainWindow : public QWidget
{
    Q_OBJECT

public:
    MainWindow()
    {
        resize(300, 300);
        setWindowTitle("Read Pixel Color");

        m_openGLVersionLabel = new QLabel();
        m_shadingLanguageVersionLabel = new QLabel();
        m_vendorLabel = new QLabel();
        m_pixelColorLabel = new QLabel();
        OpenGLWidget *openGLWidget = new OpenGLWidget();

        m_openGLVersionLabel->setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed);
        m_shadingLanguageVersionLabel->setSizePolicy(QSizePolicy::Policy::Fixed,
                                                     QSizePolicy::Policy::Fixed);
        m_vendorLabel->setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed);
        m_pixelColorLabel->setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed);

        QVBoxLayout *layout = new QVBoxLayout();
        layout->addWidget(m_openGLVersionLabel);
        layout->addWidget(m_shadingLanguageVersionLabel);
        layout->addWidget(m_vendorLabel);
        layout->addWidget(m_pixelColorLabel);
        layout->addWidget(openGLWidget);
        setLayout(layout);

        connect(openGLWidget, &OpenGLWidget::showPixelColorSignal,
                this, &MainWindow::showPixelColorSlot);
        connect(openGLWidget, &OpenGLWidget::showInfoSignal, this, &MainWindow::showInfoSlot);
    }

private slots:
    void showInfoSlot(const QString &openGLVersion, const QString &shadingVersion,
                      const QString &vendor)
    {
        m_openGLVersionLabel->setText(openGLVersion);
        m_shadingLanguageVersionLabel->setText(shadingVersion);
        m_vendorLabel->setText(vendor);
    }

    void showPixelColorSlot(const QVector3D &color)
    {
        m_pixelColorLabel->setText(QString("Pixel Color: (r: %1, g: %2, b: %3)")
                                       .arg(color.x()).arg(color.y()).arg(color.x()));
    }

private:
    QLabel *m_openGLVersionLabel;
    QLabel *m_shadingLanguageVersionLabel;
    QLabel *m_vendorLabel;
    QLabel *m_pixelColorLabel;
};

#include "main.moc"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow w;
    w.show();
    return app.exec();
}

```

pro

```auto
QT += core gui openglwidgets widgets

win32: LIBS += -lopengl32

CONFIG += c++17

SOURCES += \
    main.cpp

TARGET = app

```

---

<div class="post-metadata">

**Author:** ![Dark\_Photon](https://community.khronos.org/user_avatar/community.khronos.org/dark_photon/32/4349_2.png) [@Dark\_Photon](https://community.khronos.org/u/Dark_Photon)\
**Post date:** [December 30, 2023, 1:27am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/2 "2023-12-30T01:27:39Z")

</div>

Cross-ref:

> <https://stackoverflow.com/questions/77733503/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target>

---

<div class="post-metadata">

**Author:** ![Dark\_Photon](https://community.khronos.org/user_avatar/community.khronos.org/dark_photon/32/4349_2.png) [@Dark\_Photon](https://community.khronos.org/u/Dark_Photon)\
**Post date:** [December 30, 2023, 1:28am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/3 "2023-12-30T01:28:21Z")

</div>

Docs show that `glBindFramebuffer()` only takes `GL_FRAMEBUFFER` in WebAssembly…

> **[WebGLRenderingContext: bindFramebuffer() method - Web APIs | MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/bindFramebuffer)**
>
> The WebGLRenderingContext.bindFramebuffer() method of the
> WebGL API binds to the specified target the provided WebGLFramebuffer, or, if the framebuffer argument is null, the default WebGLFramebuffer, which is associated with the canvas rendering...

in WebGL 1 ([WebGLRenderingContext](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext), which provides OpenGL ES 2.0).

WebGL 2 ([WebGL2RenderingContext](https://developer.mozilla.org/en-US/docs/Web/API/WebGL2RenderingContext)) provides OpenGL ES 3.0 rendering context, which supports `GL_DRAW_FRAMEBUFFER` and `GL_READ_FRAMEBUFFER` as well.

UPDATE: I guess that’s WebGL, not WebAssembly. But I suspect there may be something similar going on (OpenGL ES 2.0 vs. 3.0).

---

<div class="post-metadata">

**Author:** ![8Observer8](https://community.khronos.org/letter_avatar_proxy/v4/letter/8/bbe5ce/32.png) [@8Observer8](https://community.khronos.org/u/8Observer8)\
**Post date:** [December 30, 2023, 2:24am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/4 "2023-12-30T02:24:09Z")

</div>

This means that WebAssembly uses WebGL 1.0. To solve the problem, I need WebAssembly to use WebGL 2.0. But how to do that?

---

<div class="post-metadata">

**Author:** ![8Observer8](https://community.khronos.org/letter_avatar_proxy/v4/letter/8/bbe5ce/32.png) [@8Observer8](https://community.khronos.org/u/8Observer8)\
**Post date:** [December 30, 2023, 2:52am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/5 "2023-12-30T02:52:17Z")

</div>

Cross-ref:

> **[Qt 6.6.1 WebAssembly Error. WebGL: INVALID\_ENUM: bindFramebuffer: invalid target](https://forum.qt.io/topic/153358/qt-6-6-1-webassembly-error-webgl-invalid_enum-bindframebuffer-invalid-target)**
>
> Hi, My example works on Desktop. It prints a color of a pixel with (0, 0) coordinates and OpenGL version: But when I try to build it for WebAssembly the browser prints this message: WebGL: INVALID\_ENUM: bindFramebuffer: invalid target main.cpp...

---

<div class="post-metadata">

**Author:** ![8Observer8](https://community.khronos.org/letter_avatar_proxy/v4/letter/8/bbe5ce/32.png) [@8Observer8](https://community.khronos.org/u/8Observer8)\
**Post date:** [December 30, 2023, 3:06am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/6 "2023-12-30T03:06:57Z")

</div>

I commented all lines of code except `glClear()` in the `paintGL()` method to show OpenGL version, GLSL version, and vendor:

- OpenGL version: `OpenGL version: OpenGL ES 2.0 (WebGL 1.0 (OpenGL ES 2.0 Chromium))`
- GLSL version: `GLSL version: OpenGL ES GLSL ES 1.00 (WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium))`
- Vendor version: `Vendor: WebKit`

How to activate WebGL 2.0 from WebAssembly?

---

<div class="post-metadata">

**Author:** ![8Observer8](https://community.khronos.org/letter_avatar_proxy/v4/letter/8/bbe5ce/32.png) [@8Observer8](https://community.khronos.org/u/8Observer8)\
**Post date:** [December 30, 2023, 11:05am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/7 "2023-12-30T11:05:03Z")

</div>

**lorn.potter** advised to set a version of OpenGL to 3.0 [in this topic](https://forum.qt.io/post/784652):

```cpp
    OpenGLWidget()
    {
        QSurfaceFormat surfaceFormat;
        surfaceFormat.setMajorVersion(3);
        surfaceFormat.setMinorVersion(0);
        surfaceFormat.setSamples(4);
        setFormat(surfaceFormat);
    }

```

But it didn’t help:

![image](https://community.khronos.org/uploads/default/original/2X/c/c1e4adcc2287b71f5be2af964a24c794e2296e72.png)

---

<div class="post-metadata">

**Author:** ![8Observer8](https://community.khronos.org/letter_avatar_proxy/v4/letter/8/bbe5ce/32.png) [@8Observer8](https://community.khronos.org/u/8Observer8)\
**Post date:** [December 30, 2023, 11:59am UTC](https://community.khronos.org/t/qt-6-6-1-webassembly-error-webgl-invalid-enum-bindframebuffer-invalid-target/110398/8 "2023-12-30T11:59:03Z")

</div>

I found a temporary solution that is good for me for now. I just deleted the sampling!

```cpp
    OpenGLWidget()
    {
        // QSurfaceFormat surfaceFormat;
        // surfaceFormat.setMajorVersion(3);
        // surfaceFormat.setMinorVersion(0);
        // surfaceFormat.setSamples(4);
        // setFormat(surfaceFormat);
    }

```

In this case I don’t need to use `GL_DRAW_FRAMEBUFFER` and `GL_READ_FRAMEBUFFER` to read a pixel color using `glReadPixels()`:

```cpp
    void paintGL() override
    {
        glClear(GL_COLOR_BUFFER_BIT);
        // // Set draw buffer to be fbo. Read buffer is already the default one
        // glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo->handle());
        // // Blit from the default MSAA buffer to non-MSAA fbo
        // glBlitFramebuffer(0, 0, m_fbo->width(), m_fbo->height(),
        // 0, 0, m_fbo->width(), m_fbo->height(),
        // GL_COLOR_BUFFER_BIT, GL_NEAREST);
        // glBindFramebuffer(GL_DRAW_FRAMEBUFFER, context()->defaultFramebufferObject());
        // // Set read buffer
        // glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo->handle());

        // Read the pixel
        GLubyte pixel[4];
        glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
        // Set read buffer back to default
        // glBindBuffer(GL_READ_FRAMEBUFFER, context()->defaultFramebufferObject());
        qDebug() << pixel[0] / 255.f << pixel[1] / 255.f << pixel[2] / 255.f;
        emit showPixelColorSignal(QVector3D(pixel[0] / 255.f, pixel[1] / 255.f, pixel[2] / 255.f));
    }

```

My applications works correctly on Android and WebAssembly. It read a pixel with green color (0, 1, 0):

Android:

![image](https://community.khronos.org/uploads/default/original/2X/f/facb208c2c300ac70a19e2ff2413f0b70f4405d9.png)

WebAssembly:

![image](https://community.khronos.org/uploads/default/original/2X/a/acdda8479ac175188d0b0e8a6c5bcfef26a980f4.png)
