Search code examples
qtopengltextures

QOpenGLTexture::allocateStorage causes GL_INVALID_VALUE error


I've distilled this to trivial Qt code in which the only interesting thing is several lines in synchronize() handling a texture. I get a GL_INVALID_VALUE from the allocateStorage line. Anyone knows why? I suspect it's probably due to the parameters I pass to this function.

My code:

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickFramebufferObject>
#include <QOpenGLFramebufferObject>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>

class MyItem : public QQuickFramebufferObject {
    Q_OBJECT

public:
    Renderer* createRenderer() const;
};

class MyItemRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions {
public:
    MyItemRenderer() {
        initializeOpenGLFunctions();
    }

    void render() {
    }

    QOpenGLFramebufferObject* createFramebufferObject(const QSize &size) {
        QOpenGLFramebufferObjectFormat format;
        format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
        return new QOpenGLFramebufferObject(size, format);
    }

protected:
    void synchronize(QQuickFramebufferObject* qqfbo) {
        Q_UNUSED(qqfbo)

        QOpenGLTexture tex(QOpenGLTexture::Target2D);
        tex.setSize(100, 100);
        tex.allocateStorage(QOpenGLTexture::BGRA, QOpenGLTexture::Int8);

        qDebug() << "starting loop";
        GLenum err;
        while ((err = glGetError()) != GL_NO_ERROR) {
            qDebug("\tgl error: 0x%x", err, 0, 16);
        }
    }
};

QQuickFramebufferObject::Renderer* MyItem::createRenderer() const {
    return new MyItemRenderer();
}

int main(int argc, char **argv) {
    QGuiApplication app(argc, argv);

    qmlRegisterType<MyItem>("MyItem", 1, 0, "MyItem");

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    return app.exec();
}

#include "main.moc"

main.qml

import QtQuick 2.0
import MyItem 1.0
import QtQuick.Window 2.2

Window {
    visible: true
    width: 400
    height: 400

    MyItem {
        anchors.fill: parent
    }
}

Solution

  • After looking at the source of QOpenGLTexture::createMutableTexture and QOpenGLTexture::allocateStorage() (no-argument version) I saw that two-argument allocateStorage overload is really, really misleading. The docs make it seem like its 2 args will be used as the internal format of the texture (3rd arg of the glTexImage2D call in the implementation), when in fact they're used only as the "source-data-to-transfer-from-system-RAM" format/type (7th and 8th args of glTexImage2D), which, in the case of passing a null pointer to glTexImage2D, don't matter at all except in fringe OpenGL ES 2 cases.

    The way to actually request a certain internal format for the texture is to call tex.setFormat before calling tex.allocateStorage. So I replaced my allocateStorage line with this:

    tex.setFormat(QOpenGLTexture::RGBA8_UNorm);
    tex.allocateStorage();
    

    And that fixed the error.