超过 128MB 的纹理时出现 OpenGL“内存不足”错误
Posted
技术标签:
【中文标题】超过 128MB 的纹理时出现 OpenGL“内存不足”错误【英文标题】:OpenGL "out of memory" error when exceeding 128MB of textures 【发布时间】:2011-01-12 21:26:12 【问题描述】:我正在使用 GMA500 图形硬件在 Intel Atom z530 上运行嵌入式 OpenGL 图形应用程序。 (据我了解,GMA500 是一个 PowerVR,但我不确定)。我在 Ubuntu 9.10 Karmic Koala 上使用 Tungsten Graphics “Gallium” 驱动程序运行。哦,你也应该知道我有 1 GB 的可用系统内存。
问题来了: 我有分配一堆 512x512x32 纹理的代码(每个大约 1MB)。当我达到其中的 118-120 个时,我从 OpenGL 收到“内存不足”错误,并且我还在控制台上收到以下消息:“错误:INTEL_ESCAPE_ALLOC_REGION failed”。
这与查看“顶部”时的简单测量一起向我表明,我正在达到约 128MB 的纹理限制。奇怪的是:这种架构没有专用的视频内存,它是共享的。而且我可以确定 OpenGL 正在使用系统内存来处理纹理,因为我可以看到“免费”内存在“顶部”中下降。那么为什么我会收到“内存不足”错误?我希望 opengl 能够简单地使用更多可用的系统内存。为什么会有这么硬的限制?有没有办法改变这个明显的“硬限制”设置?
谢谢! 克里斯
这是 glxinfo 的输出:
$ glxinfo
name of display: :0.0
display: :0 screen: 0
direct rendering: Yes
server glx vendor string: SGI
server glx version string: 1.2
server glx extensions:
GLX_ARB_multisample, GLX_EXT_visual_info, GLX_EXT_visual_rating,
GLX_EXT_import_context, GLX_EXT_texture_from_pixmap, GLX_OML_swap_method,
GLX_SGI_make_current_read, GLX_SGIS_multisample, GLX_SGIX_hyperpipe,
GLX_SGIX_swap_barrier, GLX_SGIX_fbconfig, GLX_MESA_copy_sub_buffer
client glx vendor string: SGI
client glx version string: 1.4
client glx extensions:
GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_allocate_memory,
GLX_MESA_copy_sub_buffer, GLX_MESA_swap_control,
GLX_MESA_swap_frame_usage, GLX_OML_swap_method, GLX_OML_sync_control,
GLX_SGI_make_current_read, GLX_SGI_swap_control, GLX_SGI_video_sync,
GLX_SGIS_multisample, GLX_SGIX_fbconfig, GLX_SGIX_pbuffer,
GLX_SGIX_visual_select_group, GLX_EXT_texture_from_pixmap
GLX version: 1.2
GLX extensions:
GLX_ARB_get_proc_address, GLX_ARB_multisample, GLX_EXT_import_context,
GLX_EXT_visual_info, GLX_EXT_visual_rating, GLX_MESA_swap_control,
GLX_OML_swap_method, GLX_SGI_make_current_read, GLX_SGIS_multisample,
GLX_SGIX_fbconfig, GLX_EXT_texture_from_pixmap
OpenGL vendor string: Tungsten Graphics, Inc.
OpenGL renderer string: Gallium 0.1, pipe/psb/Poulsbo on IEGD
OpenGL version string: 2.0 Mesa 7.1
OpenGL shading language version string: 1.10
OpenGL extensions:
GL_ARB_depth_texture, GL_ARB_draw_buffers, GL_ARB_fragment_program,
GL_ARB_fragment_shader, GL_ARB_multisample, GL_ARB_multitexture,
GL_ARB_occlusion_query, GL_ARB_pixel_buffer_object,
GL_ARB_point_parameters, GL_ARB_point_sprite, GL_ARB_shader_objects,
GL_ARB_shading_language_100, GL_ARB_shading_language_120, GL_ARB_shadow,
GL_ARB_texture_border_clamp, GL_ARB_texture_compression,
GL_ARB_texture_cube_map, GL_ARB_texture_env_add,
GL_ARB_texture_env_combine, GL_ARB_texture_env_crossbar,
GL_ARB_texture_env_dot3, GL_ARB_texture_mirrored_repeat,
GL_ARB_texture_non_power_of_two, GL_ARB_texture_rectangle,
GL_ARB_transpose_matrix, GL_ARB_vertex_buffer_object,
GL_ARB_vertex_program, GL_ARB_vertex_shader, GL_ARB_window_pos,
GL_EXT_abgr, GL_EXT_bgra, GL_EXT_blend_color,
GL_EXT_blend_equation_separate, GL_EXT_blend_func_separate,
GL_EXT_blend_logic_op, GL_EXT_blend_minmax, GL_EXT_blend_subtract,
GL_EXT_clip_volume_hint, GL_EXT_compiled_vertex_array,
GL_EXT_copy_texture, GL_EXT_draw_range_elements,
GL_EXT_framebuffer_object, GL_EXT_framebuffer_blit, GL_EXT_fog_coord,
GL_EXT_multi_draw_arrays, GL_EXT_packed_pixels,
GL_EXT_pixel_buffer_object, GL_EXT_point_parameters,
GL_EXT_polygon_offset, GL_EXT_rescale_normal, GL_EXT_secondary_color,
GL_EXT_separate_specular_color, GL_EXT_shadow_funcs,
GL_EXT_stencil_two_side, GL_EXT_stencil_wrap, GL_EXT_subtexture,
GL_EXT_texture, GL_EXT_texture3D, GL_EXT_texture_compression_s3tc,
GL_EXT_texture_edge_clamp, GL_EXT_texture_env_add,
GL_EXT_texture_env_combine, GL_EXT_texture_env_dot3,
GL_EXT_texture_filter_anisotropic, GL_EXT_texture_lod_bias,
GL_EXT_texture_mirror_clamp, GL_EXT_texture_object,
GL_EXT_texture_rectangle, GL_EXT_vertex_array, GL_APPLE_packed_pixels,
GL_ATI_blend_equation_separate, GL_ATI_separate_stencil,
GL_IBM_rasterpos_clip, GL_IBM_texture_mirrored_repeat,
GL_INGR_blend_func_separate, GL_MESA_ycbcr_texture, GL_MESA_window_pos,
GL_NV_blend_square, GL_NV_light_max_exponent, GL_NV_point_sprite,
GL_NV_texture_rectangle, GL_NV_texgen_reflection, GL_OES_read_format,
GL_SGI_color_matrix, GL_SGIS_generate_mipmap,
GL_SGIS_texture_border_clamp, GL_SGIS_texture_edge_clamp,
GL_SGIS_texture_lod, GL_SUN_multi_draw_arrays
...truncated visuals part...
【问题讨论】:
你能复制粘贴glxinfo
命令的结果吗? (视觉数组之前的行)
只是一个旁注:OpenGL 通常将纹理保留在 RAM 中,以便能够快速更改 GPU-RAM 中的纹理。因此,您不能使用增加的 RAM 使用率作为无专用纹理 RAM 的指标。 (我相信这可以使用缓冲区来解决。一直在谈论为仅 GPU 的纹理添加扩展)
MESA 不是纯软件渲染器吗? (我的 opengl-linux-fu 有点弱..)
我认为在这种情况下我可以。一方面,这个硬件没有 GPU-RAM,它是共享 RAM,所以 GPU 总是使用系统 RAM。此外,我仔细测量了系统 RAM 使用情况,它与这些纹理的理论大小非常匹配。
@Marcus:Mesa 有一个软件光栅化器,是的,但也有许多硬件驱动程序。
【参考方案1】:
共享视频内存并不意味着所有可用的 RAM 都可以用于纹理。通常图形单元只获得系统内存的一部分,系统的其余部分根本无法使用。在您的情况下,可能是 128MiB。类似于板载芯片组显卡使用的 AGP 孔径,或者英特尔酷睿集成显卡的帧缓冲区大小。
由于 OpenGL 声明了一个纯虚拟对象模型,它必须在“持久”内存中保留每个对象的副本(GPU 内存的内容可能随时失效,例如通过 VT 开关、GPU 重置等),这是从常规系统内存中消耗的内容。
【讨论】:
在我的例子中,GPU 肯定使用“常规”系统内存来存储纹理。当我创建纹理时,我可以看到可用的 ram 在“顶部”中下降。如果 GPU 使用的内存对系统的其余部分不可用,那么我不会看到“空闲”内存在“顶部”中下降。 (顺便说一句,它的下降量与我预期的完全一样,所以这不是由于我的应用程序中使用了其他内存)。 但是,我认为您对 GPU 获得系统内存的固定“切片”是正确的。我只是希望我能告诉司机以某种方式使用更多...... @sidewinderguy:您看到的 GPU 切片额外消耗的内存是 OpenGL 驱动程序的后备存储。 GPU 内存的内容(纹理、顶点缓冲区对象、FBO 等)可能会被丢弃,例如,如果系统切换到另一个 X11 会话。或者,如果您将系统置于休眠状态 – 唤醒时 GPU 会重置并且 GPU 内存片的内容会损坏。然而 OpenGL 必须保证,应用程序可以随时使用它们的对象。所以每个对象都有一个副本保存在系统内存中。【参考方案2】:使用较小或压缩的纹理,或托盘化的纹理。还要警惕同样消耗 GPU 资源的几何/显示列表。
(如果您的 GL 实现不支持此类纹理,您可以自己在着色器中查找调色板。)
【讨论】:
小一点会很好,但是我必须保持一定程度的细节。我考虑过压缩纹理,它们听起来不错,但它们绘制和/或渲染的速度是否较慢?我的 CPU/GPU 性能非常有限。关于显示列表的好点...我将不得不尝试在没有这些的情况下运行,看看我是否能得到一些好处。 这让我想到一个问题:你怎么能拥有 120 个 512x512 的纹理并以全分辨率显示它们? @tibur:这些纹理都是包含一些“图像”的“图块”,这些“图像”将作为 3D 地图的一部分显示。因此它们不会同时显示,这取决于您的平移/缩放您看到的图块以及分辨率。 @sidewinderguy:实际上不可能低于 8 位纹理(好吧,通过大量数学运算,您可以将两个 4 位纹理打包成一个并使用着色器选择每个纹理......但仅此而已只是愚蠢)。但是如果 8 位不能让你到达那里,也许你可以考虑动态管理你的 mipmap(因为你不会一直使用所有的纹理)。想想谷歌地球。这更复杂,但可以更好地扩展,并且不会过多地干扰您的应用程序的其余部分。 @sidewinderguy 压缩 DXT 纹理的绘制速度更快,因为缓存使用更好。解码完全在 TMU 中完成。现代芯片不再支持托盘化纹理 - 驱动程序将在加载它们之前解压缩到 32 位。【参考方案3】:您是否考虑过为执行mipmapping 而创建的低分辨率纹理副本?
预计算的、优化的图像集合,伴随主要纹理,旨在提高渲染速度并减少锯齿伪影。
这些以 2 的幂为单位递减,因此您将拥有 256x256、128x128、64x64 ......伴随主纹理的图像。这将比您仅拥有单个图像更快地消耗您的纹理记忆。
在他们在 Wikipedia 上使用的示例中,原始纹理是 256x256,他们将 mip-map 纹理一直降低到 1x1。根据他们的计算
所有这些 mipmap 所需的存储空间增加是原始纹理的三分之一
这假设您当然没有将其关闭。
关于如何增加可以访问的内存量 - 抱歉不知道。
【讨论】:
但这只会导致 1/4 + 1/16 + 1/64 + ... @brian_d - 我做这些东西已经有一段时间了,所以我的数学有点生疏了。 关于 mipmapping 的要点。如果它还没有,我绝对应该关闭它(知道如何在 opengl 中做到这一点?;-) - 问题是,即使有这些可能的节省,我也需要更多的内存(我希望512MB)。 @sidewiderguy - 很抱歉我不记得了(已经有一段时间了),我认为这可能是问题所在。您的每个纹理实际上占用大约 1.36MB。将 128 除以 1.36 得到大约 94,但低于您的 118。 @ChrisF:我真正的问题不是要弄清楚为什么我只能分配 118 个纹理。真正的问题是,我如何为我提供更多可用的 RAM。无论如何,感谢您对这个 mipmapping 的意见,我会记住这一点,我相信它会有所帮助。以上是关于超过 128MB 的纹理时出现 OpenGL“内存不足”错误的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL - 在 NVIDIA 卡上渲染到纹理时出现 FBO 黑屏