我在这里遇到一个奇怪的问题:我有一个潜在的大(最多500mb)3d纹理,每秒创建几次。纹理的大小可能会改变,因此重复使用旧纹理不是每次都可以选择。避免内存消耗的逻辑步骤是每次不使用时删除纹理(使用glDeleteTexture),但程序很快就会发生读取或写入访问冲突。在用于更新纹理的缓冲区上调用glDeleteBuffer时会发生同样的事情。
在我看来,这不可能发生,因为glDelete *函数非常安全。如果你给他们一个不是相应对象的gl句柄,他们就什么都不做。
有趣的是,如果我不删除纹理和缓冲区,程序运行正常,直到它最终耗尽显卡内存。
这是在Windows XP 32bit,NVIDIA Geforce 9500GT和266.58er驱动程序上运行,编程语言是visual studio 2005中的c ++。
显然glDelete并不是唯一受影响的功能。我刚刚违反了其他几种方法(昨天情况并非如此)......看起来这里的东西真是太糟糕了。
这不应该失败吗?
template <> inline
Texture<GL_TEXTURE_3D>::Texture(
GLint internalFormat,
glm::ivec3 size,
GLint border ) : Wrapper<detail::gl_texture>()
{
glGenTextures(1,&object.t);
std::vector<GLbyte> tmp(glm::compMul(size)*4);
glTextureImage3DEXT(
object, // texture
GL_TEXTURE_3D, // target
0, // level
internalFormat, // internal format
size.x, size.y, size.z, // size
border, // border
GL_RGBA, // format
GL_BYTE, // type
&tmp[0]); // don't load anything
}
失败了:
Exception (first chance) at 0x072c35c0: 0xC0000005: Access violoation while writing to position 0x00000004.
Unhandled exception at 0x072c35c0 in Project.exe: 0xC0000005: Access violatione while writing to position 0x00000004.
最好的猜测:弄乱程序内存的东西?
答案 0 :(得分:4)
我不知道为什么glDelete会崩溃,但我相当肯定你不需要它而且过于复杂。
glGenTextures为纹理创建一个“名称”。 glTexImage3D为OpenGL提供了一些附加到该名称的数据。如果我的理解是正确的,没有理由在您不再需要数据时删除该名称。
相反,您应该在相同的纹理名称上再次调用glTexImage3D并相信驱动程序将知道不再需要您的旧数据。这允许您每次重新指定一个新的大小,而不是先指定一个最大大小,然后调用glTexSubImage3D,这将使实际使用数据变得困难,因为纹理仍将保持其最大大小。
下面是python中的一个愚蠢的测试(pyglet需要),它分配了一大堆纹理(只是为了检查GPU-Z中的GPU内存使用量测量是否真的有效)然后每帧重新分配新数据到相同的纹理,随机新大小和一些随机数据只是为了解决数据保持不变时可能存在的任何优化。
它(显然)很慢,但它绝对显示,至少在我的系统(Windows服务器2003 x64,NVidia Quadro FX1800,驱动程序259.81)上,GPU内存使用量不会上升而循环重新分配纹理。
import pyglet
from pyglet.gl import *
import random
def toGLArray(input):
return (GLfloat*len(input))(*input)
w, h = 800, 600
AR = float(h)/float(w)
window = pyglet.window.Window(width=w, height=h, vsync=False, fullscreen=False)
def init():
glActiveTexture(GL_TEXTURE1)
tst_tex = GLuint()
some_data = [11.0, 6.0, 3.2, 2.8, 2.2, 1.90, 1.80, 1.80, 1.70, 1.70, 1.60, 1.60, 1.50, 1.50, 1.40, 1.40, 1.30, 1.20, 1.10, 1.00]
some_data = some_data * 1000*500
# allocate a few useless textures just to see GPU memory load go up in GPU-Z
for i in range(10):
dummy_tex = GLuint()
glGenTextures(1, dummy_tex)
glBindTexture(GL_TEXTURE_2D, dummy_tex)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1000, 1000, 0, GL_RGBA, GL_FLOAT, toGLArray(some_data))
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
# our real test texture
glGenTextures(1, tst_tex)
glBindTexture(GL_TEXTURE_2D, tst_tex)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1000, 1000, 0, GL_RGBA, GL_FLOAT, toGLArray(some_data))
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
def world_update(dt):
pass
pyglet.clock.schedule_interval(world_update, 0.015)
@window.event
def on_draw():
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
# randomize texture size and data
size = random.randint(1, 1000)
data = [random.randint(0, 100) for i in xrange(size)]
data = data*1000*4
# just to see our draw calls 'tick'
print pyglet.clock.get_fps()
# reallocate texture every frame
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, 1000, size, 0, GL_RGBA, GL_FLOAT, toGLArray(data))
def main():
init()
pyglet.app.run()
if __name__ == '__main__':
main()
答案 1 :(得分:0)
在整个代码中加注glGetError()。我敢打赌你被glDelete实际上没有破坏对象的事实所困扰。该对象可以在更长的时间内使用几帧。因此我怀疑你的内存不足(即glGetError返回GL_OUT_OF_MEMORY)。