首先分享一个我做的图,没有严格按照UML规范,主要是要表达这样的一个意思而已。
[原图:http://ishare.iask.sina.com.cn/f/7863351.html ]
首先需要明确一些这样的信息:
1.每个高级Shader语言都可以编译成汇编代码的形式。在cg中我们使用cgGetProgramString,DX有API可以用:D3DXAssembleShader。
2. 每个Shader的参数(这里指需要由应用程序输入的元素)都存在于GPU的寄存器中。我们可以得到它们的索引,但是这个索引并非寄存器的编号。cg中有方法cgGetParameterResourceIndex,DX中可以通过LPD3DXCONSTANTTABLE来获取这些信息。这个索引很重要,因为在DX的API SetVertexShaderConstantF[及其族类]的第一个参数就是这个索引。
如上面的图所示,有不少的类和结构体来实现这一系列的功能,但是我认为最重要的就三个部分:
1.GpuConstantDefinition 这是最基本的结构体,因为它存储了最基本的信息。
2.GpuNamedConstants 这个是参数名称和其Definition之间的映射。
3.GpuProgramParameters 这个是给外部使用的接口。
现在我们可以简单的说一下流程:
在编译Shader的时候,GPUProgram及其派生类会创建自己对应的GpuProgramParameters,然后会独立的创建GpuNamedConstants,最后会添加到GpuProgramParameters对象中。
在渲染的时候,会取出这些值,通过SetVertexShaderConstantF[及其族类]进行绑定(for DX, only)。
下面一段话是GpuProgramParameters在图中的注解,我就直接Copy过来用了:
对于GPU程序的参数的封装类。对于高级Shader语言来说,使用命名常量。
对于低级Shader语言来说,使用逻辑索引和物理索引。
这其中的相关的Buffer和Constant的分析都不是由它完成的,而是由对应的GPUProgram的类完成的。
对于高级语言来说,位于函数:
virtual void buildConstantDefinitions() const = 0;
中。这里会遍历编译完成的Shader,然后提取所有的Constant相关信息GpuConstantDefinition。
(cg中在recurseParams中完成,HLSL中使用LPD3DXCONSTANTTABLE来完成)
D3D9GpuProgram是为低级Shader语言准备的类。
在系统运行的时候,SceneManager会通过updateGpuProgramParameters更新GPU程序的参数,然后获取Pass的对应的顶点、片段的参数GpuProgramParameters,
然后调用RenderSystem的bindGpuProgramParameters执行更新过程,这时候会根据GpuConstantDefinition中定义的类型去取对应的逻辑索引,缓冲区起始地
址,以及个数,以DX为例,这调用IDirect3DDevice9::SetVertexShaderConstantF等函数进行绑定。
另外Ogre调用设置参数的值的方法,如下面这个及其重载:
void GpuProgramParameters::setConstant(size_t index, const int *val, size_t count)
他们并非直接调用API去设定值,而只是将其Copy到了对应的浮点或者整形缓冲区中,之后才由RenderSystem统一设置,如果说逻辑索引标志着GPU参数在GPU寄存器中的顺序的话,那么物理索引就指示了GPU参数在缓冲区中的位置。把它们结合起来,就可以让RenderSystem去正确的缓冲区中获取正确的值去调用底层的API。
void GpuProgramParameters::_writeRawConstants(size_t physicalIndex, const float* val, size_t count)
{
assert(physicalIndex + count <= mFloatConstants.size());
memcpy(&mFloatConstants[physicalIndex], val, sizeof(float) * count);
}
Ok,就这么多了。