【问题标题】:glDeleteTextures does not seem to free up texture memory on Windows, is there no solution?glDeleteTextures 似乎没有在 Windows 上释放纹理内存,有没有解决方案?
【发布时间】:2012-01-10 05:26:18
【问题描述】:

我的 openGL 应用程序内存不足时遇到了一些问题,我正在尝试找出我的问题。为此,我创建了一个小测试程序,它基本上只是从调用 glDeleteTextures 的文件中加载一个巨大的纹理,然后再次加载它,如果我在 OSX 上运行这个测试程序,这个过程可以运行数百次迭代而没有问题(最我运行它是 1024 并且这没有问题)但是在 windows 上大约 14 次迭代后我得到一个 GLU_OUT_OF_MEMORY 错误。我一遍又一遍地加载的纹理是一个巨大的天空穹顶(4096 x 1024 和 4.9MB)。

这是我使用 cmets 为非 lisp 倾向运行的代码:

测试程序:

 (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)))))

Create-texture-from-file(这个方法的大部分是由 openGL 调用组成的,所以我认为大多数 openGL 人应该对这里发生的事情有一个合理的理解,但我可以澄清任何令人困惑的事情):

(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 并没有完全释放所有资源,但这些帖子都没有提供任何替代方案或解决方案。有没有这样的解决方案?

【问题讨论】:

  • 不创建 mipmap 会发生什么?
  • @genpfault:当我不创建 mipmap 时,它会在 17 次迭代(而不是 14 次)后耗尽内存。
  • 但是如果不生成mipmap,是不是生成的是GL_OUT_OF_MEMORY而不是GLU_OUT_OF_MEMORY?
  • 在删除纹理后尝试调用 glIsTexture 和 glAreTexturesResident。使用与删除纹理时相同的 texID(在两种情况下都应该返回 false,但如果不是我们知道问题出在哪里)

标签: opengl textures


【解决方案1】:

Windows OpenGL 驱动程序的设计假设您的代码在某些时候实际上会绘制 东西。正因为如此,当你要求他们完成时,他们往往会避免做某事,将他们推迟到更方便的时间。这就是你在这里遇到的问题。

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

问题是“稍后”通常被定义为某种形式的glDraw* 命令、glEndglFlush/Finish 或交换缓冲区命令。或者类似的东西。如果您所做的只是循环创建/删除纹理,驱动程序可能没有机会实际删除任何内容。

尽量减少测试的人为因素。在每个glDeleteTextures 之后添加glFinish。如果这不起作用,请在删除之间画一些东西。

最终,您不能强制司机做您想做的事。您所能做的就是让您的测试应用程序的行为更像一个普通的应用程序。

【讨论】:

  • 非常感谢 Nicol 的回答,但我认为这不是问题所在(至少不是唯一的问题)。我添加了 glFinish ,但我仍然遇到同样的崩溃。我最初受到启发来创建这个测试程序,因为我在实际应用程序中遇到了同样的麻烦行为。在我的应用程序中,我有一个世界(一个大的 openGLView)和一个重新加载按钮,它将重新加载 openGL(根据 XML 文件中描述的规范),当按下这个重新加载按钮大约 14 次时,我首先遇到了这个问题。每次都会显示openGLView。
  • 在我上一条评论中描述的世界中,我拥有同样大的天空穹顶。
  • 你用的是什么显卡?
  • 我有一个 ATI Radeon HD 4670,我的同事在 NVidia GeForce 8600M GT 上遇到了同样的行为。
  • 这也发生在配备 Intel 高清显卡的低端 HP 测试机和运行 bootcamp/Windows 7 且配备 GeForce GT 130 的 IMac 上。
【解决方案2】:

另外,由于您的错误带有 GLU 前缀,您可以尝试在不构建 mipmap 的情况下运行相同的程序吗?[已经完成] 我不认为 GLU_OUT_OF_MEMORY 一定意味着您已经退出GPU 内存(实际上 mipmap 可能是在 CPU 上构建的),所以您可能正在遭受Heap fragmentation 的困扰。您在具有不同 GPU 的不同 Windows 机器上遇到错误这一事实似乎表明这不是特定的 OpenGL 驱动程序问题;它们因供应商而异。

由于您使用的是大纹理,并且如果不使用 gluBuild2DMipmaps 并不能解决问题,您可以在应用启动时为大纹理预先分配 GPU 内存并重用纹理对象使用 glTexSubImage 而不是在重新加载时创建新的。

编辑:以下不提供解决方案(请参阅问题 cmets),但在我看来仍然有用

由于您得到的是GLU_OUT_OF_MEMORY 而不是GL_OUT_OF_MEMORY,我假设问题发生在使用gluBuild2DMipmaps 创建mipmap 期间。由于 glu 函数可能有问题,也许您可​​以尝试在离线过程中构建您的 mipmap,然后简单地将它们加载到 Create-texture-from-file 中。除了可能解决您的内存不足错误之外,这还可以让您更好地控制实际的 mipmap 生成。例如,您可以使用高斯滤波器而不是箱形滤波器。它还将确保跨平台的相同 mipmap 内容。我的理解是这就是通常处理 mipmap 的方式。

【讨论】:

    【解决方案3】:

    我认为您可以尝试使用 glTexImage2d/3d 将空图像推送到要删除的纹理。它适用于 VBO - 我通过使用 glBufferData 删除缓冲区数据并传递一个空数组句柄来删除图形卡中的数据,因为 glDeleteBuffers 本身并没有删除数据。

    【讨论】:

    • 我试过这个但没有运气:( 绘制一个简单的三角形、glFlush()、glFinish() 或交换缓冲区似乎都没有使驱动程序释放内存。AMD Omega 14.12 驱动程序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多