QOpenGLTexture::allocateStorage 导致 GL_INVALID_VALUE 错误

QOpenGLTexture::allocateStorage causes GL_INVALID_VALUE error

我已将其提炼为简单的 Qt 代码,其中唯一有趣的是 synchronize() 中处理纹理的几行代码。我从 allocateStorage 行得到一个 GL_INVALID_VALUE。任何人都知道为什么?我怀疑这可能是因为我传递给这个函数的参数。

我的代码:

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
    }
}

你有...

QOpenGLTexture tex(QOpenGLTexture::Target2D);

根据 docs 实际上并没有创建底层纹理对象。我想你需要...

tex.create();

在设置大小和分配存储之前。所以...

QOpenGLTexture tex(QOpenGLTexture::Target2D);
if (!tex.create()) {

  /*
   * Take appropriate action.
   */
}
tex.setSize(100, 100);
tex.allocateStorage(QOpenGLTexture::BGRA, QOpenGLTexture::Int8);

编辑 1:

实际上,查看代码似乎 tex.allocateStorage 应该在必要时分配一个纹理 ID。但是,如果由于某种原因(例如没有当前上下文)而失败,那么这可能会导致您看到的问题。

在"allocatestorage"期间,您正在传送有关纹理存储格式的opeGL驱动程序。

对于格式 "GL_BGRA or GL_RGBA",OpenGL 建议 "GL_UNSIGNED_BYTE"、

在 Qt 中 ----- “QOpenGLTexture::BGRA”(对于 GL_BGRA)和“QOpenGLTexture::UInt8”(对于 GL_UNSIGNED_BYTE)。

https://www.khronos.org/opengl/wiki/Textures_-_more

所以你的基于(openGL推荐)的分配存储函数应该是

tex.allocateStorage(QOpenGLTexture::BGRA, QOpenGLTexture::UInt8);

在查看 QOpenGLTexture::createMutableTextureQOpenGLTexture::allocateStorage() 的源代码(无参数版本)后,我发现双参数 allocateStorage 重载确实如此,确实如此误导。文档让它看起来像它的 2 args 将被用作纹理的 内部格式 (实现中 glTexImage2D 调用的第三个 arg),而实际上它们' re 仅用作 "source-data-to-transfer-from-system-RAM" format/type(glTexImage2D 的第 7 个和第 8 个参数),在将空指针传递给 glTexImage2D 的情况下,这无关紧要除了附带的 OpenGL ES 2 案例之外的所有案例。

实际上为纹理请求某种内部格式的方法是在调用[=18之前调用tex.setFormat =].所以我用这个替换了我的 allocateStorage 行:

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

然后修复了错误。