【问题标题】:How to efficiently initialize texture with zeroes?如何有效地用零初始化纹理?
【发布时间】:2011-08-25 18:07:47
【问题描述】:

我需要用零初始化一个 OpenGL 2D 纹理。

为什么?我用 OpenCL 渲染到这个纹理。大致来说,渲染阶段是:

  1. 创建 RGBA 纹理,用零初始化(因此它包含透明的黑色像素)
  2. OpenCL:计算某些对象可见的像素颜色并将它们写入此纹理
  3. OpenGL:将环境映射添加到透明像素并显示最终图像

因此我不需要将任何实际纹理数据传递给glTexImage2d。但是根据规范,当我传递data=NULL时,纹理内存被分配但没有被初始化。

分配一个用零填充的客户端内存并传递给glTexImage2D 不是一个很好的选择,尽管我只能想到一个。

编辑:我实际上只想初始化 alpha 分量(RGB 无论如何都会被覆盖),但我怀疑这会使情况变得更容易。

【问题讨论】:

    标签: opengl


    【解决方案1】:

    有几种方法可以做到这一点:

    1:给定纹理的宽度和高度:

    std::vector<GLubyte> emptyData(width * height * 4, 0);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_BYTE, &emptyData[0]);
    

    为了最大限度地提高效率,您应该在调用它和 OpenCL 开始工作之间留出一些时间。

    2:将其附加到 FBO 并使用 glClearBuffer

    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
    glFramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0); //Only need to do this once.
    glDrawBuffer(GL_COLOR_ATTACHMENT0); //Only need to do this once.
    GLuint clearColor[4] = {0, 0, 0, 0};
    glClearBufferuiv(GL_COLOR, 0, clearColor);
    

    这似乎应该更快,因为没有 CPU-GPU DMA 正在进行。但是 FBO 的绑定和解除绑定可能会导致效率低下。再说一次,它可能不会。对其进行分析以确保。

    请注意,这只适用于可用作渲染目标的图像格式。所以不是压缩纹理。

    3:如果有足够的驱动程序,您可以使用新的ARB_clear_texture 扩展:

    glClearTexImage(texture, 0, GL_BGRA, GL_UNSIGNED_BYTE, &clearColor);
    

    请注意,这仅适用于数据可由standard pixel transfers 提供的图像格式。所以不是压缩格式。

    【讨论】:

    • 从未听说过glClearBuffer。这是来自一个非常新的版本吗?它比glClear 有什么优势(或者后者甚至被弃用了)?。
    • @Christian:ClearBuffer 的主要优点是可以清除特定的缓冲区。如果帧缓冲区中有多个缓冲区、多个渲染目标,那么您可能希望将不同的缓冲区清除为不同的颜色。或者根本不清楚一些。 glClear 不能做到这一点;它将所有缓冲区清除为相同的清除颜色。 glClear 未被弃用,glClearBuffer 来自 GL 3.0(没有扩展名)。
    • 请注意,glClearTexImage 仅在先前已分配纹理存储时才有效,使用调用 glTexImage* 或 glTexStorage*。简单地使用 glBindTexture 创建纹理是不够的。但这当然也适用于 glTexSubImage2D。
    • 另外,glClearTexImage 仅适用于非压缩格式。但我有一个问题。我可以看到 ARB 函数已映射(非零)并且定义为 1。但是,即使应该使用 glTexImage/glTexStorage/glTexCopy 函数创建纹理存储(句柄非零),我仍然得到GL 错误说纹理不存在。有什么想法吗?
    • @StarShine:感谢关于压缩纹理清除的提醒。至于你的问题,这就是“提问”按钮的作用。
    【解决方案2】:

    请注意:新的GL_ARB_clear_texture(4.4 中的核心)扩展专门解决了这个问题。

    【讨论】:

    • 这是真的,但要警告一句:您肯定想对此进行分析。在我的系统上,glClearTexture 比使用帧缓冲区和 glClear / glClearBuffer 慢得多。
    • @Jagoly 您是否使用 GPU 计时器查询正确配置文件?
    • 不,只是使用帧时间。不过,它不仅慢了一点。 clearTexture(两次调用,rgb8 + 24 位深度)花费的时间是 clear 的三倍多。我已经设置了帧缓冲区。仅深度(5x)的差异甚至更大。
    【解决方案3】:
    1. glTexSubImage 填满了整张图片:
            GLfloat* pData = new GLfloat[1024*768*4];
            memset(pData, 0x00, 1024*768*4*sizeof(GLfloat));
            glBindTexture(GL_TEXTURE_2D, m_ImageTex);
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1024, 768, GL_RGBA, GL_FLOAT, pData);
            glBindTexture(GL_TEXTURE_2D, 0);
            delete pData;
    
    1. 使用Pixel Buffer从gpu复制数据,这种方法更快更好

      我。初始化PBO

            glGenBuffers(1, &m_PixelBuffer);
            glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_PixelBuffer);
            glBufferData(GL_PIXEL_UNPACK_BUFFER, SCREEN_WIDTH*SCREEN_HEIGHT*4*sizeof(GLfloat), NULL, GL_STATIC_DRAW);
            GLfloat* pData = nullptr;
            pData = (GLfloat*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
            memset(pData, 0x00, 1024*768*4*sizeof(GLfloat));
            glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
    
    ii.     
    
            glBindBuffer(GL_PIXEL_UNPACK_BUFFER, m_PixelBuffer);
            glBindTexture(GL_TEXTURE_2D, m_ImageTex);
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGBA, GL_FLOAT, NULL);
            glBindTexture(GL_TEXTURE_2D, 0);
            glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
    

    【讨论】:

      【解决方案4】:

      也许您可以将纹理设置为第一遍的渲染目标并绘制黑色图元。它可能会更快,因为内存和显卡之间没有内存传输。

      【讨论】:

      • 好点。但是我可以设法用这种方法设置 alpha=0 吗?我实际上只想初始化 alpha,我不关心 RGB 组件。
      • 使用 glClearColor 和 glClear 可能会更好。 glClearColor 接受 alpha。
      猜你喜欢
      • 2018-04-08
      • 2015-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-29
      相关资源
      最近更新 更多