QOpenGLTexture::allocateStorage 导致 GL_INVALID_VALUE 错误

Posted

技术标签:

【中文标题】QOpenGLTexture::allocateStorage 导致 GL_INVALID_VALUE 错误【英文标题】:QOpenGLTexture::allocateStorage causes GL_INVALID_VALUE error 【发布时间】:2017-03-20 16:38:30 【问题描述】:

我已将其提炼为琐碎的 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
    

【问题讨论】:

【参考方案1】:

查看QOpenGLTexture::createMutableTextureQOpenGLTexture::allocateStorage()(无参数版本)的来源后,我发现allocateStorage 的两个参数重载真的,真的 误导。文档使它看起来像它的 2 个 args 将用作纹理的 internal format(实现中 glTexImage2D 调用的第 3 个 arg),而实际上它们仅用作"source-data-to-transfer-from-system-RAM" 格式/类型(glTexImage2D 的第 7 和第 8 个参数),在将空指针传递给 glTexImage2D 的情况下,根本不重要除了边缘 OpenGL ES 2 情况。

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

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

这样就修复了错误。

【讨论】:

好吧,也听到另一个铃声,allocateStorage 的参数的两种枚举类型清楚地表明它们是关于外部格式,而不是内部格式...... Qt 的 GL 包装器是灾难。+1 为答案,否则我可能会花费数小时来弄清楚。设计此 API 的人并不真正了解 OpenGL:/【参考方案2】:

你有...

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 之后打印了tex.isCreated(),我得到了true【参考方案3】:

在“分配存储”期间,您正在向 opeGL 驱动程序传达有关纹理存储格式的信息。

对于“GL_BGRA 或 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::allocateStorage 导致 GL_INVALID_VALUE 错误的主要内容,如果未能解决你的问题,请参考以下文章