buffer资源
下面来谈谈buffer的管理。buffer资源从广义上就是C语言的数组。如下图所示。
图 buffer的广义模型
在渲染管线中,无论是opengl还是dx或者其他的渲染api,都会提供下列的buffer类型。vertex buffer,index buffer,constant buffer,structured buffer,raw buffer与indirect arguments buffer. 这些buffer的不同就在于两个方面。
首先就是内存结构。有流式的buffer,如vertex buffer和index buffer,它们的行为更像是数据流,数据的读取时顺序的,因此内存的分布式紧密和连续的。而structured buffer,constatn buffer等是结构式的buffer,为了满足GPU中高效的随机访问buffer数据的需求,这些buffer通常会按照一定的规则进行内存对齐。
其次,在上面已经提到,就是访问方式的不同。正式因为访问方式的不同,才有了内存结构的不同。流式数据往往数据量很大(数万个定点,数十万个索引的高模),只提供顺序访问,并且访问的工作已经由shader中不同的stage辅助处理了。而结构式的buffer往往shader程序中的数据量没有流式数据那么绝大,但更多的是高效与方便的随机访问buffer数据,他们在shader程序中都有类似operator[](constant buffer),还有类似栈的行为(append & consume buffer).
对buffer资源的管理基本遵循两个关键点。1. 一个元素的大小与元素的个数 2. 如何方便应用程序在cpu端初始化和访问buffer的数据。第一决定整个buffer的大小,第二个是buffer在应用程序段操作数据的接口。
后面的篇幅会依次对这些buffer资源进行详细讨论,buffer的管理较texture而言较为复杂,我们先从vertex buffer和index buffer开始。前面说过,vertex buffer和index buffer是流式数据。一般情况下,它们的数据保存在模型文件中,程序载入这些数据,创建vb和ib作为应用程序的输入。vertex buffer除了作为输入之外,还可以作为geometry shader的输出。
vertex buffer
图 vertex buffer
我们借用d3d api中input layout的概念来管理vb中单位元素的大小。vb的一个单位元素,都是由若干个基本的一维向量类型的属性(attribute)依次排开,而组成。
Input layout由
1. 描述每个属性的类型;
enum class data_format { float_, float2, // ........... float4x4, int_, // ....... uint4, structured, };
2. 描述每个属性相对于元素内存起始位置的偏移量
3. 描述每个属性的语义(在d3d中有用)
enum class data_semantic { position, normal, binormal, tangent, texcoord0, texcoord1, // ....... texcoord7, color0, color1, };
这样,input layout就能够完整的计算出vb单位元素的大小,并辅助在应用程序段对vb初始化和访问数据的工作。
在leaves::pipeline::buffer的实现宏, 除了buffer<vertex_buffer>基类提供的ptr_as<T>()模板成员函数方便直接的内存拷贝之外,我们管理的vb还提供类似stl访问容器的迭代器,分语义来访问vb中的元素。
index buffer
图 index buffer
index buffer的管理较vb稍简单一些。单位元素就是一个整形。因此它的迭代器也轻量一些,直接使用指针。但是index buffer还需要管理一个primitive type。它描述的是定点索引之间的拓扑关系。如图。
图 基本的拓扑结构
图 line_list_adj 和 line_strip_adj
图 triangle_list_adj
图 triangle_strip_adj
不同拓扑关系会影响index buffer元素个数,可以根据上面几张图的关系来实现一个由primitive数量计算indices数量的函数。
下一篇将详细介绍constant buffer及剩下buffer的管理。
详细的实现代码托管在 https://github.com/IndignantAngel/modern-graphics-framework 中,欢迎大神前来指教。