glDeleteTextures似乎没有释放Windows上的纹理内存,没有解决方法吗?

glDeleteTextures似乎没有释放Windows上的纹理内存,没有解决方法吗?

问题描述:

我的openGL应用程序内存不足时遇到了一些问题,我试图找出问题所在.为此,我创建了一个小型测试程序,该程序基本上只从名为glDeleteTextures的文件中加载一个巨大的纹理,然后再次加载它,如果我在OSX上运行此测试程序,则该过程可以运行数百次迭代而不会出现问题(大多数情况下,我将其运行为1024,这没有问题),但是在Windows上进行约14次迭代后,我收到了GLU_OUT_OF_MEMORY错误.我一遍又一遍地加载的纹理是一个巨大的圆顶(4096 x 1024和4.9MB).

I have been having some problems with my openGL application running out of memory and I am trying to track down my problem. To this end, I created a small test program that basically just loads a giant texture from a file calls glDeleteTextures and then loads it again, if I run this test program on OSX this process can run for hundreds of iterations with no problems (the most I ran it for was 1024 and this had no problems) but after about 14 iterations on windows I get a GLU_OUT_OF_MEMORY error. The texture I am loading over and over is a huge sky dome (4096 x 1024 and 4.9MB).

这是我正在运行的代码,其中包含针对非轻度倾斜的注释:

Here is the code I am running with comments for the non lisp inclined:

测试程序:

 (with-glcontext (shared-opengl-view)
   ;;loop 1024 times
   (dotimes (i 1024)
    ;; create a texture and return its texture name
    (let ((texture (create-texture-from-file (truename "lui:resources;sky domes;DarkClouds.png"))))
      ;;Allocate two bytes to pass to glDeleteTextures
      (ccl::rlet ((&texName :long))
        ;; put the texture string into our allocated bytes
        (setf (ccl::%get-long &texName) texture)
          ;; Delete the textures?
          (glDeleteTextures 1 &texName)))))

从文件创建纹理(此方法大部分由openGL调用组成,因此我认为大多数openGL人员应该对这里发生的事情有一个合理的了解,但我可以弄清任何令人困惑的地方):

Create-texture-from-file (most of this method is made up of openGL calls so I think most openGL people should have a reasonable understanding of what's happening here but I can clarify anything thats confusing):

(defun CREATE-TEXTURE-FROM-FILE (Filename &key Verbose (Build-Mipmaps t) Repeat (Mag-Filter *Default-OpenGL-Texture-Magnification-Filter*) Forced-Depth) "
in:  Filename {string}, 
&key Verbose {boolean}, Repeat
out: OpenGL-Texture-Name {int}, width, height, depth
Load the <Filename> texture inside the texture directory.
- Ideal file should be 32 bit ARGB compatible, e.g., .png with mask or 24 bit RGB
- 8 bit and 16 bit image will work too 
- Image size must be 2^n x 2^m, at least 64 x 64
- This function must be called with active AGL context, e.g., inside OpenGL-Window INIT     method."
 (declare (ftype function create-image-from-file))
 (rlet ((&texName :long))
   (multiple-value-bind (&Image Width Height Depth) (create-image-from-file Filename :verbose Verbose :flip-vertical t :forced-depth Forced-Depth)
     (unless &Image (return-from create-texture-from-file nil))
     (glPixelStorei GL_UNPACK_ROW_LENGTH Width)  ; Set proper unpacking row length for image
     (glPixelStorei GL_UNPACK_ALIGNMENT 1)       ; Set byte aligned unpacking (needed for 3-byte-per-pixel image)
     (glGenTextures 1 &texName)
     ; Specify the texture's properties.
     (glBindTexture GL_TEXTURE_2D (%get-long &texName))
     (glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_S (if Repeat GL_REPEAT GL_CLAMP_TO_EDGE))
     (glTexParameteri GL_TEXTURE_2D GL_TEXTURE_WRAP_T (if Repeat GL_REPEAT GL_CLAMP_TO_EDGE))
     (glTexParameteri gl_texture_2d gl_texture_mag_filter Mag-Filter)   ;; make textures look smooth (can be costly)
     ;; Mipmaps: make texture look good at different sizes
     (if Build-Mipmaps
      (glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR_MIPMAP_NEAREST)
      (glTexParameteri GL_TEXTURE_2D GL_TEXTURE_MIN_FILTER GL_LINEAR))
    ;; Experimental: anisotropic filtering to make textures less blurry at angle
    #-:cocotron  (glTexParameterf GL_TEXTURE_2D GL_TEXTURE_MAX_ANISOTROPY_EXT 16.0)
     (let ((PixelFormat (ecase Depth (32 GL_RGBA) (24 GL_RGB)))
         (InternalFormat (ecase Depth (32 GL_RGBA8) (24 GL_RGB8))))
      (glTexImage2D GL_TEXTURE_2D 0 InternalFormat width height 0 PixelFormat GL_UNSIGNED_BYTE &Image)
      (when Build-Mipmaps
        (when Verbose (format t "~%Building Mipmaps~%"))
      (unless 
          ;; The calls to gluBuild2DMipmaps will return GLU_OUT_OF_MEMORY when we run out.
          (zerop (print (gluBuild2DMipmaps GL_TEXTURE_2D InternalFormat width height PixelFormat GL_UNSIGNED_BYTE &Image)))
        (print (get-opengl-error))
        (error "could not create mipmaps"))
      (when Verbose (format t "Completed Mipmaps~%"))))
  ;; OpenGL should have copied now the image data into texture memory: release
  (dispose-vector &Image)
  ;; return the texture handle and image dimensions
  (values
   (%get-long &texName)
   Width 
   Height
   Depth))))

我在其他地方读过glDeleteTextures并没有完全取消所有资源,但是这些帖子都没有提供任何替代方案或解决方案.有没有这样的解决方案?

I have read elsewhere the glDeleteTextures does not completely dealocate all resources but none of these posts offered any alternative or solutions. Is there no such solution?

Windows OpenGL驱动程序的设计假设您的代码实际上会在某些时候 draw 东西.因此,当您要求完成任务时,他们倾向于避免准确地做事,从而将他们推迟到更方便的时间.这就是您在这里遇到的问题.

Windows OpenGL drivers are designed on the assumption that your code will actually draw stuff at some point. Because of that, they tend to avoid doing things exactly when you ask them to be done, deferring them to a more convenient time. And that's what you're running into here.

仅仅因为您告诉OpenGL您已经完成了纹理对象的操作,并不意味着OpenGL必须立即放弃该内存.这样做通常需要进行一些非常繁重的操作.因此,驱动程序会将其推迟到以后.

Just because you tell OpenGL that you're done with a texture object doesn't mean that OpenGL must immediately relinquish that memory. Doing that generally requires some pretty heavy-weight operations. So instead, drivers will defer this until later.

问题在于后期"通常被定义为glDraw*命令,glEndglFlush/Finish或交换缓冲区命令的某种形式.或那种性质的东西.如果您要做的只是坐在一个循环中并创建/删除纹理,则驱动程序可能没有机会实际删除任何内容.

The problem is that "later" is usually defined as some form of glDraw* command, glEnd, glFlush/Finish, or a swap buffer command. Or something of that nature. If all you do is sit in a loop and create/delete textures, the driver may not get the chance to actually delete anything.

尝试减少测试的人工性.在每个glDeleteTextures之后添加一个glFinish.如果那不起作用,请在删除之间绘制内容.

Try making your test less artificial. Add a glFinish after each glDeleteTextures. If that doesn't work, draw stuff between deletions.

最终,您不能强制驱动程序执行所需的操作.您所能做的就是使您的测试应用程序的行为更像普通应用程序.

Ultimately, you cannot force drivers to do what you want. All you can do is make your test application behave more like a normal application.