Opengl glDelete上的访问冲突*
我在这里遇到了一个奇怪的问题:我有一个潜在的大(高达500mb)3d纹理,每秒创建几次。纹理的大小可能会改变,因此每次都不能重复使用旧纹理。避免内存消耗的逻辑步骤是每次不再使用纹理时删除它(使用glDeleteTexture),但程序很快就会因读或写访问冲突而崩溃。在我用来更新纹理的缓冲区上调用glDeleteBuffer时,同样的情况也会发生在glDeleteBuffer上Opengl glDelete上的访问冲突*,opengl,opengl-3,Opengl,Opengl 3,我在这里遇到了一个奇怪的问题:我有一个潜在的大(高达500mb)3d纹理,每秒创建几次。纹理的大小可能会改变,因此每次都不能重复使用旧纹理。避免内存消耗的逻辑步骤是每次不再使用纹理时删除它(使用glDeleteTexture),但程序很快就会因读或写访问冲突而崩溃。在我用来更新纹理的缓冲区上调用glDeleteBuffer时,同样的情况也会发生在glDeleteBuffer上 import pyglet from pyglet.gl import * import random def toG
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()
在我看来,这不可能发生,因为glDelete*函数是非常安全的。如果你给他们一个gl句柄,它不是一个对应的对象,他们什么也不做
有趣的是,如果我不删除纹理和缓冲区,程序就会正常运行,直到图形卡上的内存用完为止
这是在WindowsXP 32位,Nvidia GeFiel9500 GT上运行的262.58ER驱动程序,Visual Studio 2005中的编程语言是C++。
更新
显然,glDelete不是唯一受影响的函数。我只是在其他几种方法中发现了违规行为(昨天的情况并非如此)。。。这里好像有什么东西坏了
更新2
这不应该失败,是吗
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
}
最佳猜测:有什么东西把程序内存弄乱了?我不知道为什么glDelete会崩溃,但我相当确定您无论如何都不需要它,并且正在将其过度复杂化 glGenTextures为纹理创建一个“名称”。glTexImage3D为OpenGL提供了一些附加到该名称的数据。如果我的理解是正确的,当您不再需要数据时,没有理由删除该名称 相反,您只需在相同的纹理名称上再次调用glTexImage3D,并相信驱动程序会知道不再需要您的旧数据。这允许您每次重新指定一个新大小,而不是先指定最大大小,然后调用glTexSubImage3D,这将使实际使用数据变得困难,因为纹理仍将保持其最大大小 下面是python中的一个愚蠢的测试(需要pyglet),它分配了一大堆纹理(只是为了检查GPU-Z中的GPU内存使用度量是否有效),然后在每一帧向同一纹理重新分配新数据,使用一个随机的新大小和一些随机数据只是为了在数据保持不变的情况下解决可能存在的任何优化问题 它(显然)非常慢,但至少在我的系统(Windows server 2003 x64、NVidia Quadro FX1800、drivers 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()
在你的代码中撒上一点。我敢打赌,glDelete并没有真正销毁该对象,这一事实让你大吃一惊。该对象的使用时间可能更长一些。因此,我怀疑您的内存不足(即glGetError返回的GL_内存不足)。不重新创建纹理对象(非常昂贵),只需使用替换旧内容即可glTexSubImage3D@datenwolf:就像我说的,纹理的大小是changing@Floarian:要初始化纹理内容,只需传递一个空指针作为glTexImage数据参数。不需要助手数组。OpenGL规范准确定义了这种行为:“在GL版本1.1或更高版本中,数据可能是空指针。在这种情况下,纹理内存被分配来容纳宽度和高度的纹理。然后可以下载子文本来初始化该纹理内存。如果用户试图将纹理图像的未初始化部分应用于原语,则图像是未定义的。“另外,请向我们展示您对glDeleteTextures的调用。我起初没有注意到这一点,但为什么您要使用glTextureImage3DEXT?为什么不使用ARB扩展或OpenGL-1.3向上核心函数?还有第一个参数“object”是什么“你在那儿干什么?glTexImage3D的签名看起来不同。实际上。。。我没有考虑过这个。。。C++包装器是用“一个C++对象,一个OpenGL对象”的概念构建的。因此,每当创建一个新的C++对象时,就会生成一个新的OpenGL对象。我想这应该改变。。。但我不确定这是否有助于解决这个问题。但是,谢谢:“弗洛里安:是的,OpenGL周围的大多数C++包装都是愚蠢的。对于纹理,它们通常遵循“纹理是图像”模式,而不是更合理的“纹理摄取图像”模式。