我们使用缓冲对象来减少CPU-GPU的复制操作,对于纹理缓冲对象,我们可以在缓冲对象中将目标从顶点更改为纹理。纹理缓冲区对象还有其他优点吗?另外,它不允许过滤,这有什么缺点吗?
uxh89sit1#
缓冲区纹理类似于1D纹理,但具有后备缓冲区存储,该缓冲区存储不是纹理对象的一部分(与任何其他纹理对象相反),而是通过绑定到TEXTURE_BUFFER的实际缓冲区对象实现的。使用缓冲区纹理有几个含义,AFAIK,一个用例不能Map到任何其他类型的纹理。请注意,缓冲区纹理 * 不是 * 缓冲区对象-缓冲区纹理只是使用glTexBuffer与缓冲区对象相关联。相比之下,缓冲区纹理可能很大。OpenGL 4.4核心规范的表23.53及以下定义了最小最大值(即实现必须提供的最小值)texelsMAX_TEXTURE_BUFFER_SIZE的数量。存储在缓冲区对象中的潜在纹素数量计算如下(如GL_ARB_texture_buffer_object中所示):floor(<buffer_size> / (<components> * sizeof(<base_type>))箝位到MAX_TEXTURE_BUFFER_SIZE的结果值是可寻址纹素的数量。
TEXTURE_BUFFER
MAX_TEXTURE_BUFFER_SIZE
floor(<buffer_size> / (<components> * sizeof(<base_type>))
示例:
你有一个缓冲区对象存储4 MiB的数据。您需要的是用于处理RGBA纹理的缓冲区纹理,因此选择内部格式RGBA8。纹理元素的可寻址数量为floor(4MiB / (4 * sizeof(UNSIGNED_BYTE)) == 1024^2 texels == 2^20 texels如果您的实现支持此数字,则可以处理缓冲区对象中的整个值范围。上面的效果并不令人印象深刻,可以简单地在当前实现中使用任何其他纹理来实现。然而,我写这个答案的机器支持2^28 == 268435456纹理。使用OpenGL 4.4(和4.3,可能还有更早的4.x版本),MAX_TEXTURE_SIZE是每个1D纹理2 ^ 16个纹理像素,因此缓冲区纹理仍然可以是4倍大。在我的本地机器上,我可以分配一个2GiB的缓冲区纹理(实际上甚至更大),但当使用RGBAF32纹理时,只能分配一个1GiB的1D纹理。缓冲区纹理的一个用例是对着色器内的大型数据存储的随机(和原子,如果需要的话)读/写访问(后者通过图像加载/存储)。是的,你可以对一个或多个块内的均匀数组进行随机 * 读 * 访问,但是如果你必须处理大量数据并且必须处理多个块,即使这样,查看单个阶段的所有均匀块中所有均匀组件的最大组合大小(其中单个浮点组件的大小为4字节),它也会变得非常乏味,MAX_(stage)_UNIFORM_BLOCKS * MAX_UNIFORM_BLOCK_SIZE + MAX_(stage)_UNIFORM_COMPONENTS * 4在着色器阶段中使用的空间并不是很大(取决于您的实现允许上述数字有多大)。纹理和缓冲区纹理之间的一个重要区别是,作为常规缓冲区对象的数据存储可用于纹理根本无法工作的操作。扩展中提到:使用buffer对象来提供存储允许以多种不同的方式指定纹理数据:通过缓冲区对象加载(BufferData)、直接CPU写入(MapBuffer)、帧缓冲区回读(EXT_pixel_buffer_object扩展)。缓冲区对象也可以通过变换反馈(NV_transform_feedback扩展)加载,该变换反馈捕获由GL处理的顶点的选定变换属性。这些机制中的一些不需要额外的数据副本,而使用传统的类TexImage入口点时需要额外的数据副本。使用缓冲区纹理的一个含义是,着色器内部的查找只能通过texelFetch完成。缓冲区纹理也不是mipMap的,正如你已经提到的,在提取过程中没有过滤。
RGBA8
floor(4MiB / (4 * sizeof(UNSIGNED_BYTE)) == 1024^2 texels == 2^20 texels
2^28 == 268435456
MAX_TEXTURE_SIZE
RGBAF32
MAX_(stage)_UNIFORM_BLOCKS * MAX_UNIFORM_BLOCK_SIZE + MAX_(stage)_UNIFORM_COMPONENTS * 4
texelFetch
附录:
从OpenGL 4.3开始,我们有了所谓的Shader Storage Buffer。这些也提供了对大型数据存储的随机(原子)读/写访问,但不需要像缓冲区纹理那样使用texelFetch()或图像加载/存储功能进行访问。使用缓冲区纹理还意味着必须处理gvec4返回值,包括texelFetch()和imageLoad()/imageStore()。一旦你想使用结构(或其数组),并且你不想考虑使用vec4的多个示例或使用多个缓冲区纹理来实现类似的东西的一些愚蠢的打包方案,这就变得非常乏味。使用作为着色器存储访问的缓冲区,您可以简单地索引到数据存储,并直接从缓冲区中提取一些struct {}的一个或多个示例。此外,由于它们与均匀块非常相似,因此使用它们应该相当简单-如果您知道如何使用均匀缓冲区,则无需花费很长时间来学习如何使用着色器存储缓冲区。同样值得浏览相应ARB extension的Issues部分。
texelFetch()
gvec4
imageLoad()
imageStore()
vec4
struct {}
性能影响
丹尼尔Rakos几年前做了一些性能分析,既作为comparison of uniform buffers and buffer textures,也基于AMD OpenCL编程指南中的信息进行了一点more general笔记。现在有一个非常新的版本,专门针对OpenCL optimization的AMD平台。影响性能的因素有很多:
访问模式和产生的缓存行为
高速缓存线大小和存储器布局
访问哪种存储器(寄存器、本地、全局、L1/L2等)及其各自的存储器带宽
同时执行其他操作隐藏内存获取延迟的程度
您使用的是哪种硬件,即。具有专用内存或某种统一内存架构的专用图形卡
等等等等
在担心性能时:实现一些有效东西,看看这些解决方案是否足够快,能够满足您的需要。否则,实施两种或更多种方法来解决问题,分析它们并进行比较。此外,供应商特定的指南可以提供大量的见解。上面提到的OpenCL用户和优化指南提供了一个高层次的架构视角和如何优化CL内核的具体提示-这些内容在开发着色器时也是相关的。
4ngedf3f2#
我发现的一个用例是存储每个图元的属性(在片段着色器中通过gl_PrimitiveID访问),同时仍然保持索引网格中的唯一顶点。
2条答案
按热度按时间uxh89sit1#
缓冲区纹理类似于1D纹理,但具有后备缓冲区存储,该缓冲区存储不是纹理对象的一部分(与任何其他纹理对象相反),而是通过绑定到
TEXTURE_BUFFER
的实际缓冲区对象实现的。使用缓冲区纹理有几个含义,AFAIK,一个用例不能Map到任何其他类型的纹理。请注意,缓冲区纹理 * 不是 * 缓冲区对象-缓冲区纹理只是使用glTexBuffer与缓冲区对象相关联。
相比之下,缓冲区纹理可能很大。OpenGL 4.4核心规范的表23.53及以下定义了最小最大值(即实现必须提供的最小值)texels
MAX_TEXTURE_BUFFER_SIZE
的数量。存储在缓冲区对象中的潜在纹素数量计算如下(如GL_ARB_texture_buffer_object中所示):floor(<buffer_size> / (<components> * sizeof(<base_type>))
箝位到
MAX_TEXTURE_BUFFER_SIZE
的结果值是可寻址纹素的数量。示例:
你有一个缓冲区对象存储4 MiB的数据。您需要的是用于处理RGBA纹理的缓冲区纹理,因此选择内部格式
RGBA8
。纹理元素的可寻址数量为floor(4MiB / (4 * sizeof(UNSIGNED_BYTE)) == 1024^2 texels == 2^20 texels
如果您的实现支持此数字,则可以处理缓冲区对象中的整个值范围。上面的效果并不令人印象深刻,可以简单地在当前实现中使用任何其他纹理来实现。然而,我写这个答案的机器支持
2^28 == 268435456
纹理。使用OpenGL 4.4(和4.3,可能还有更早的4.x版本),
MAX_TEXTURE_SIZE
是每个1D纹理2 ^ 16个纹理像素,因此缓冲区纹理仍然可以是4倍大。在我的本地机器上,我可以分配一个2GiB的缓冲区纹理(实际上甚至更大),但当使用RGBAF32
纹理时,只能分配一个1GiB的1D纹理。缓冲区纹理的一个用例是对着色器内的大型数据存储的随机(和原子,如果需要的话)读/写访问(后者通过图像加载/存储)。是的,你可以对一个或多个块内的均匀数组进行随机 * 读 * 访问,但是如果你必须处理大量数据并且必须处理多个块,即使这样,查看单个阶段的所有均匀块中所有均匀组件的最大组合大小(其中单个浮点组件的大小为4字节),它也会变得非常乏味,
MAX_(stage)_UNIFORM_BLOCKS * MAX_UNIFORM_BLOCK_SIZE + MAX_(stage)_UNIFORM_COMPONENTS * 4
在着色器阶段中使用的空间并不是很大(取决于您的实现允许上述数字有多大)。
纹理和缓冲区纹理之间的一个重要区别是,作为常规缓冲区对象的数据存储可用于纹理根本无法工作的操作。扩展中提到:
使用buffer对象来提供存储允许以多种不同的方式指定纹理数据:通过缓冲区对象加载(BufferData)、直接CPU写入(MapBuffer)、帧缓冲区回读(EXT_pixel_buffer_object扩展)。缓冲区对象也可以通过变换反馈(NV_transform_feedback扩展)加载,该变换反馈捕获由GL处理的顶点的选定变换属性。这些机制中的一些不需要额外的数据副本,而使用传统的类TexImage入口点时需要额外的数据副本。
使用缓冲区纹理的一个含义是,着色器内部的查找只能通过
texelFetch
完成。缓冲区纹理也不是mipMap的,正如你已经提到的,在提取过程中没有过滤。附录:
从OpenGL 4.3开始,我们有了所谓的Shader Storage Buffer。这些也提供了对大型数据存储的随机(原子)读/写访问,但不需要像缓冲区纹理那样使用
texelFetch()
或图像加载/存储功能进行访问。使用缓冲区纹理还意味着必须处理gvec4
返回值,包括texelFetch()
和imageLoad()
/imageStore()
。一旦你想使用结构(或其数组),并且你不想考虑使用vec4
的多个示例或使用多个缓冲区纹理来实现类似的东西的一些愚蠢的打包方案,这就变得非常乏味。使用作为着色器存储访问的缓冲区,您可以简单地索引到数据存储,并直接从缓冲区中提取一些struct {}
的一个或多个示例。此外,由于它们与均匀块非常相似,因此使用它们应该相当简单-如果您知道如何使用均匀缓冲区,则无需花费很长时间来学习如何使用着色器存储缓冲区。
同样值得浏览相应ARB extension的Issues部分。
性能影响
丹尼尔Rakos几年前做了一些性能分析,既作为comparison of uniform buffers and buffer textures,也基于AMD OpenCL编程指南中的信息进行了一点more general笔记。现在有一个非常新的版本,专门针对OpenCL optimization的AMD平台。
影响性能的因素有很多:
访问模式和产生的缓存行为
高速缓存线大小和存储器布局
访问哪种存储器(寄存器、本地、全局、L1/L2等)及其各自的存储器带宽
同时执行其他操作隐藏内存获取延迟的程度
您使用的是哪种硬件,即。具有专用内存或某种统一内存架构的专用图形卡
等等等等
在担心性能时:实现一些有效东西,看看这些解决方案是否足够快,能够满足您的需要。否则,实施两种或更多种方法来解决问题,分析它们并进行比较。
此外,供应商特定的指南可以提供大量的见解。上面提到的OpenCL用户和优化指南提供了一个高层次的架构视角和如何优化CL内核的具体提示-这些内容在开发着色器时也是相关的。
4ngedf3f2#
我发现的一个用例是存储每个图元的属性(在片段着色器中通过gl_PrimitiveID访问),同时仍然保持索引网格中的唯一顶点。