# 渲染整体架构

DX11一共有6种Shader：vs、ps、cs、hs、ds、gs

我们通过尾缀来标识是哪种shader，hlsl文件中通过 pragma 来标识shader入口。

一个pass需要写在一个shader中并标识。

1. Pipeline State\
   包含blend state、Rasterizer State、Depth Stencil State
2. Render Pass\
   包含一趟pass所需的shader（vs、ps、cs、hs、ds、gs，定义可见[Shader规范](https://app.gitbook.com/o/HuKCCM4VNURIcT0xlszs/s/GUKK6YnYBR07zaFrfU1O/~/changes/139/shi-yong-wen-dang/shader-gui-fan) 一节）。这里面村的是 IShader，里头会有这个shader对应的constant buffer以及其他，通过着色器反射来获取到。
3. Material：\
   包含 Pipeline State 与 Render Pass，并且可以选择 Type（Default即默认的PBR、BaseLit或者是后处理），同时可以对 Pipeline State 进行设置。\
   选择BaseLit或者后处理的时候则可以 add shader，例如 mat.AddShader("BasePBR")，此时会在CACHE中寻找所有BasePBR.xx，这里XX可以是上面六种尾缀的一种，此时即会去重新构造 Render Pass。\
   添加进来后会通过着色器反射，把所有信息存在mat中（实际上在 Render Pass 的每个 IShader 里），对应建立常量缓冲区。mat可以set一个变量的值。例如 mat`.SetUniform("xx", value)`\
   material有点类似一个subpass
4. Render Tech\
   包含 Material、index buffer、vertex buffer、topology、vertex layout，相当于一次渲染
5. Render Pipeline\
   包含 Render Tech, Frame Buffer

一次渲染应该是以 Render Pipeline 为单位，先绑定 Frame Buffer，再去遍历 Render Tech，每个 Render Tech 的渲染绑定 Material（绑定里面的 State 与 Shader），再去绑定 index buffer、vertex buffer、topology、vertex layout 等。

后续应该接着考虑 Forward、Defferred 等管线的设置。

## 渲染流程

我们希望逐 pipeline 来进行，而不是遍历mesh每遇到一种材质再绑定一个pipeline。逐pipeline来进行就避免了冗余的绑定，提升了效率。

为此我们需要在反序列化场景的时候（以及更改mesh的材质的时候）去把mesh提交到render queue里面，render queue里面是一个pass到submesh的一个对应。而每个pass目前就对应一条pipeline。

这样子我们渲染的步骤就变成：

1. 遍历render queue的每一个pass
2. 对每个pass而言，获取对应的pipeline，并bind
3. 遍历这个pass对应的所有submesh，渲染submesh

并且我们日后做剔除以及半透明渲染的时候，也可以在对应render queue做submesh的增删与新建render queue。

## deferred context 与 immediate context

现代图形api无疑是deferred context的，而在 d3d11 中，也有deferred context的模式，他最终其实还是要提交到immediate context去执行。但是，deferred context往往是线程安全的，我们一般会提交命令到commandlist上，这只是记录下来你的命令，等到真正execute的时候才会真正提交到gpu去执行。因此我们可以多线程地去记录（encode）我们的命令，例如每个线程一个commandlist，最终执行的时候再一并提交。

但是immediate context也有好处：无脑，方便，debug简单，兼容只有immediate context的OpenGL。我们目前要快速堆效果达到一个成熟的可以做游戏的引擎，因此我们直接使用immediate context去封装dx11和OpenGL。

这种模式下我们可以灵活地封装成一个bind函数，用来绑定所需的各种东西，主要是：shader、常量缓冲区、顶点layout（仅dx11，ogl是要先绑定到vertex array里头再去指定）、PrimitiveTopology、vertex buffer与index buffer。全部绑定好后再直接用 Draw 或 DrawIndexed 方法渲染即可。

因此对于各种方法我们可以统一地封装到 RenderCommand 类中。这里我们希望这个类的方法全部都是静态方法，这样调用方便，因此我们需要额外弄个类 RendererAPI 类，相同的方法在 RendererAPI 类中再写一次做对应。\\

\\
