opengl es,glActiveTexture 时出错

Posted

技术标签:

【中文标题】opengl es,glActiveTexture 时出错【英文标题】:opengl es, error when glActiveTexture 【发布时间】:2016-01-14 19:42:20 【问题描述】:

我正在 android 系统中开发一个基于 Qt 5.4 的应用程序。 我正在生成几个 OES 纹理并通过着色器在 Qt FBO TEXTURE_2D 中渲染。每个 OES 纹理都有自己的 eglcontext,每个人都有相同的 sharedContext。 OES 纹理是一一使用的,我的意思是,我不想同时渲染多个,但我需要创建多个,因为我必须能够在同一时间渲染多个未来。

这是我必须更新时使用的代码:

m_program->bind();
glActiveTexture(GL_TEXTURE0 + textureId);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
/* my code to fill shader attr and glDraw*() */
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
m_program->release();

问题是,由于某种原因,我只能渲染创建的第一个 OES 纹理,因为在尝试 glActiveTexture 第二个时我得到了W/Adreno-ES20(28468): <core_glActiveTexture:348>: GL_INVALID_ENUM。因此,目标纹理被填充为黑色。

我已经检查了所有这些并且是正确的:

textureId 调用 eglCreateContext 时的 sharedContext。 渲染时的当前 eglContext,我的意思是,当调用到上面时 代码。 已填充第二个 OES 纹理 GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 16 GL_MAX_TEXTURE_IMAGE_UNITS 16 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 32

我有点迷茫,我不确定这是我的代码中的限制还是错误。

有什么想法吗?

编辑:在其他设备上尝试,应用程序正常工作,所以我认为问题与设备限制有关..

【问题讨论】:

既然您说第二个调用已经报告错误,您是否可以尝试为第二个调用硬编码 GL_TEXTURE1。如果这可行,那么您的 textureId 有一个奇怪的值或 GL_TEXTURE1 在您的情况下不等于 GL_TEXTURE0+1 。如果这些工作有效,您可以通过包装纹理 ID 创建一个解决方法,创建另一个自定义自动增量 ID,然后将其用于包含 GL_TEXTUREX 枚举的访问表。 @MaticOblak 由于某种原因,生成的textureIds不是一个一个,我正在检查它是否有3个要渲染的纹理,数字是:(oesTextureId 23)(oesTextureId 45)(oesTextureId 61)跨度> 所以这似乎是问题所在。您可能永远不会假设 id 将是连续的,甚至以 0 或任何其他低值开头。您是否还在纠结该怎么做,或者您是否了解生成自己的自动增量活动纹理 ID 的概念? @MaticOblak,是的,我仍然坚持要做什么,我正在阅读有关生成我自己的自动增量纹理 ID 的信息,因为我从未使用过,欢迎提供任何帮助。 【参考方案1】:

生成纹理时,您无法保证 id 将从零开始或递增 1。因此您可能不会期望值会是 [0, 1, 2,...] 并且不能将活动纹理用作 @ 987654321@。您将需要创建自己的自动增量系统,最好通过创建某种能够生成纹理、分配两个 ID 等的纹理对象来实现。

要增加内部 ID,您需要做的就是使用一个静态整数值,该值会随着您生成的每个纹理而增加。这是最基本的系统,您将在某个时间只加载一些纹理,然后重用它们,假设它们都不应该被释放和重用。其他系统需要对已发布的纹理进行某种跟踪,并能够重用空槽。

因此,对于基础知识,您将拥有一个对象/类,例如:

static GLint currentActiveTextureID = GL_TEXTURE0;

class ActiveTextureObject 
    GLuint textureID;
    GLenum activeTextureID;

    void generateNew() 
        activeTextureID = currentActiveTextureID++;
        useActive();
        glGenTextures(1, &activeTextureID);
    

    void useActive() 
        glActiveTexture(activeTextureID);
    
    void bind() 
        glBindTexture(GL_TEXTURE_2D, textureID);
    
    void bindAndUseActive() 
        useActive();
        bind();
    
;

这现在包含您在 sn-p 中发布的所有功能。如果您愿意,也可以在构造函数中调用方法generateNew。如您所见,该对象将纹理和活动纹理绑定在一起,因此您只需调用bindAndUseActive 即可完成两者。

对于更复杂的系统,您可以使用一组元素来表示活动纹理的插槽。然后,您可以循环遍历数组以找到一个空槽。

class ActiveTexturePool 

    static const GLint maximumActiveTextures = 16; // number of maximum units
    GLint currentActiveTextureID[maximumActiveTextures]; // have the container

    ActiveTexturePool()  // a constructor is needed to reset the data
        memset(currentActiveTextureID, 0, sizeof(currentActiveTextureID)); // sets all to zero
    

    class ActiveTextureObject 
    public:
        GLuint textureID;
        GLenum activeTextureID;

        void generateNew() 
            useActive();
            glGenTextures(1, &activeTextureID);
        

        void useActive() 
            glActiveTexture(activeTextureID);
        
        void bind() 
            glBindTexture(GL_TEXTURE_2D, textureID);
        
        void bindAndUseActive() 
            useActive();
            bind();
        
    ;

    ActiveTextureObject getNewTextureObject() 
        ActiveTextureObject toReturn;

        for(GLint i=0; i<maximumActiveTextures; i++) 
            if(currentActiveTextureID[i] == 0) 
                GLenum activeTexture = GL_TEXTURE0 + i;

                currentActiveTextureID[i] = activeTexture;
                toReturn.activeTextureID = activeTexture;

                return toReturn;;
            
        
        return NULL; // the pool is full, you may not create another active texture!
    

    void recycleTexture(ActiveTextureObject texture)  // remove from the pool
        for(GLint i=0; i<maximumActiveTextures; i++) 
            if(currentActiveTextureID[i] == texture.activeTextureID) 
                currentActiveTextureID[i] = 0;
                texture.activeTextureID = 0;
                // you may also delete the data here but that should most likely be handled by the ActiveTextureObject
                break;
            
        
    
;

现在在这种情况下,您宁愿在某处创建一个池来处理纹理。您可能很容易拥有一个或多个可用于多种上下文的池。最后,最好创建一个包含主要上下文并具有纹理池的类。然后,上下文对象还可以为您正在生成的每个纹理创建共享上下文,并且还负责删除、回收纹理和上下文。

【讨论】:

非常感谢您的帮助,如果我告诉我我在目标设备上尝试过并且一切正常,并且我的应用程序能够显示至少 4 个(我没有检查更多),我不是在开玩笑同时。我认为这是我的开发设备中可用的相关 GPU 内存

以上是关于opengl es,glActiveTexture 时出错的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL,禁用纹理单元、glActiveTexture 和 glBindTexture

openGL之API学习(一九四)glGenTextures glActiveTexture

Qt 和 QGLWidget 中的 glActiveTexture?

glActiveTexture 默认行为与预期不符

opengl - 只显示一个纹理

OpenGLES渲染颜色问题