c++ - OpenGL 新纹理在删除后替换旧纹理

标签 c++ winapi opengl textures

我在使用 OpenGL 时遇到了一些令人困惑的问题,它很简单,但我没有找到任何直接相关的信息。

我想做什么

我每帧创建几个新纹理,创建后我立即绑定(bind)它们,使用它们进行绘图,然后立即删除它们。

问题

如果我在使用每个纹理后立即将其删除,则最后绘制的纹理会替换之前的纹理(但它们不同的几何形状会正常工作)。如果我在完成所有绘图后批量删除,它会按预期工作,但如果我在删除纹理后执行任何绘图调用,则最后一次绘图调用中使用的纹理会替换旧的(可能是一些常见的永久 Sprite )纹理)。

调试结果

我试过使用 glFlush(),它似乎根本没有做任何事情,根本不删除纹理给出了正确的行为,而且在删除纹理和调用 SwapBuffers() 之间根本不绘制任何东西有效。

代码

这不是我的代码的样子,但相关部分归结为:

int Tex1, Tex2, Tex3;
glGenTextures(1, &Tex1);
glBindTexture(GL_TEXTURE_2D, Tex1);
// ... Fill Texture with data, set correct filtering etc.
glDrawElements(GL_TRIANGLES, ...); // Using Tex1


glGenTextures(1, &Tex2);
glBindTexture(GL_TEXTURE_2D, Tex2);
// ... Fill Texture with data, set correct filtering etc.
glDrawElements(GL_TRIANGLES, ...); // Using Tex2

// I delete some textures here.
glDeleteTextures(1, &Tex1);
glDeleteTextures(1, &Tex2);

// If I comment out this section, everything works correctly
// If I leave it in, this texture replaces Tex1 and Tex2, but
// the geometry is correct for each geometry batch.
glGenTextures(1, &Tex3);
glBindTexture(GL_TEXTURE_2D, Tex3);
// ... Fill Texture with data, set correct filtering etc.
glDrawElements(GL_TRIANGLES, ...); // Using Tex3 
glDeleteTextures(1, &Tex3);

// ...
SwapBuffers();

我怀疑这可能与 OpenGL 缓冲我的绘制调用有关, 并且在实际处理它们时纹理已被删除?虽然这对我来说真的没有意义,为什么在删除以前的纹理之后绘制其他东西会导致这种行为?

更多上下文

生成的纹理是文本字符串,可能会或可能不会改变每一帧,现在我为每一帧的每个字符串创建新纹理,然后渲染纹理并在之后立即丢弃它。位图数据是用 Windows GDI 生成的。

我并不是真的在寻找有关效率的建议,理想情况下,我想要一个答案,该答案可以引用有关使用此类临时纹理进行渲染的预期/正确行为的文档,以及这种方法可能存在的常见问题。

最佳答案

预期的行为很明确。您可以在使用完对象后立即将其删除。在您的情况下,在使用纹理进行绘制调用后,您可以在这些纹理上调用 glDeleteTextures()。您不需要采取额外的预防措施。

在幕后,OpenGL 通常会异步执行绘制调用。因此在绘制调用返回后纹理仍将被使用。但这不是你的问题。驱动程序负责跟踪和管理对象的生命周期,使它们一直存在,直到它们不再被使用。

我在规范中找到的最清晰的表达是在 OpenGL 4.5 规范的第 28 页:

If an object is deleted while it is currently in use by a GL context, its name is immediately marked as unused, and some types of objects are automatically unbound from binding points in the current context, as described in section 5.1.2. However, the actual underlying object is not deleted until it is no longer in use.

在您的代码中,这意味着在 GPU 使用纹理完成绘制调用之前,驱动程序无法删除纹理。

为什么这对你的情况不起作用很难说。一种可能性始终是您的代码中的某些内容无意中比应有的时间更早地删除了纹理。对于复杂的软件架构,这比您想象的要容易得多。例如,一个非常普遍的原因是人们将 OpenGL 对象包装在 C++ 类中,并让这些 C++ 对象超出范围,而底层 OpenGL 对象仍在使用中。

因此您绝对应该仔细检查(例如通过使用调试断点或日志记录)没有在意外时间调用删除纹理的代码。

另一个选项是驱动程序错误。虽然对象生命周期管理并非完全微不足道,但它是如此关键以至于很难想象它会在一个非常基本的情况下被破坏。但这当然是可能的,而且可能性或多或少取决于供应商和平台。

作为变通方法,您可以尝试不删除纹理对象,而只为相同的对象指定新数据(使用 glTexImage2D())。如果纹理大小不变,则只用 glTexSubImage2D() 替换数据可能会更有效。

关于c++ - OpenGL 新纹理在删除后替换旧纹理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32313749/

相关文章:

qt - 在没有 openGL 的情况下使用 Qt

c++ - 如何在 OpenGL 中将像素绘制为多边形的纹理?

c++ - 提取opencv中特定颜色的形状

c++ - 用 x 的 c++ 替换字符串的一部分

c++ - 嵌套结构化绑定(bind)可能吗?

c++ - char 类型的参数与参数类型 LPWSTR 不兼容

c++ - CreateThread 会干扰 VirtualAlloc 的使用吗?

c - 函数中返回文件/文件夹结构的指针

c++ - 我们可以使用 Qt(64) 生成一个可以在 32 位窗口和 64 位窗口上运行的应用程序吗?

opengl - 光线转换体渲染中的不透明度校正