D3D11渲染流程笔记
2024-07-29
25
0
顶点
ID3D11DeviceContext::VSSetShader - 设置顶点着色器
ID3D11DeviceContext::IASetInputLayout - 设置顶点着色器的参数布局
ID3D11DeviceContext::VSSetConstantBuffers - 设置顶点着色器常量空间
device->context->VSSetShader(shader, NULL, 0);
device->context->IASetInputLayout(layout);
device->context->VSSetConstantBuffers(0, 1, &constants);//slot,NumBuffers,ID3D11Buffer**
像素
ID3D11DeviceContext::PSSetShader 设置像素着色器
ID3D11DeviceContext::PSSetConstantBuffers 设置像素着器常量空间
ID3D11DeviceContext::PSSetSamplers 设置采样状态
device->context->PSSetShader(shader, NULL, 0);
device->context->PSSetConstantBuffers(0, 1, &constants);
device->context->PSSetSamplers(0, GS_MAX_TEXTURES, states);//slot,数组中的采样器数,采样器
常量空间
常量空间是一片内存,包括所有参数的空间。故常量空间一般只创建一个。而在常量空间内部,各个参数根据其偏移位置对号入座。
void gs_shader::BuildConstantBuffer()
{
//计数常量空间的总大小
for (size_t i = 0; i < params.size(); i++) {
gs_shader_param ¶m = params[i];
size_t size = 0;
switch (param.type) {
case GS_SHADER_PARAM_BOOL:
case GS_SHADER_PARAM_INT:
case GS_SHADER_PARAM_FLOAT:
size = sizeof(float);
break;
case GS_SHADER_PARAM_INT2:
case GS_SHADER_PARAM_VEC2:
size = sizeof(vec2);
break;
case GS_SHADER_PARAM_INT3:
case GS_SHADER_PARAM_VEC3:
size = sizeof(float) * 3;
break;
case GS_SHADER_PARAM_INT4:
case GS_SHADER_PARAM_VEC4:
size = sizeof(vec4);
break;
case GS_SHADER_PARAM_MATRIX4X4:
size = sizeof(float) * 4 * 4;
break;
case GS_SHADER_PARAM_TEXTURE:
case GS_SHADER_PARAM_STRING:
case GS_SHADER_PARAM_UNKNOWN:
continue;
}
//数组个数
if (param.arrayCount)
size *= param.arrayCount;
/* checks to see if this constant needs to start at a new register
//常量总大小没有16字节对齐时
if (size && (constantSize & 15) != 0)
{
size_t alignMax = (constantSize + 15) & ~15; //常量总大小16字节对齐后
//如果超过了,最最大值
if ((size + constantSize) > alignMax)
constantSize = alignMax;
}
param.pos = constantSize;//参数在常量空间的位置,都是16字节对齐的
constantSize += size; //总的常量空间大小
}
memset(&bd, 0, sizeof(bd));
if (constantSize)
{
HRESULT hr;
bd.ByteWidth = (constantSize + 15) & 0xFFFFFFF0; /* align */
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
//创建常量空间
hr = device->device->CreateBuffer(&bd, NULL, constants.Assign());
if (FAILED(hr))
throw HRError("Failed to create constant buffer", hr);
}
for (size_t i = 0; i < params.size(); i++)
gs_shader_set_default(¶ms[i]);
}
(gs_effect_set_vec4)-> effect buffer->(gs_shader_set_val) -> gs buffer ->(gs_shader::UpdateParams
- gs_vertexbuffer_flush
)->常量空间
OBS的着色器全局参数空间的设置如上文所述,设置比较曲折。
在解析后创建的着色器有两种结构,分别为解析后的空间和着色器空间。实些其实都在CPU内部,最终由于着色器常量空间是一片连续的内存,故使用gs_shader::UpdateParam构造一块相同大小的内存空间,使用着色器参数填充其空间内容,然后再整体拷贝到着色器内存空间。
渲染流程
- gs_effect_set_vec4(color, colorVal); //参数到effect buffer
- gs_technique_begin_pass
- gs_load_vertexshader
- ID3D11DeviceContext::VSSetShader - 设置顶点着色器
- ID3D11DeviceContext::IASetInputLayout - 设置顶点着色器的参数布局
- ID3D11DeviceContext::VSSetConstantBuffers - 设置顶点着色器常量空间
- gs_load_pixelshader
- ID3D11DeviceContext::PSSetShader 设置像素着色器
- ID3D11DeviceContext::PSSetConstantBuffers 设置像素着器常量空间
- ID3D11DeviceContext::PSSetSamplers 设置采样状态
- upload_parameters(tech->effect, false)
- upload_shader_params(vshader_params, changed_only);
- gs_shader_set_val()// effect buffer -> gs buffer
- upload_shader_params(pshader_params, changed_only);
- gs_shader_set_val
- upload_shader_params(vshader_params, changed_only);
- gs_load_vertexshader
- gs_draw_sprite(0, 0, context->width, context->height)
- gs_vertexbuffer_flush(graphics->sprite_buffer); //map unmap更新显卡内部顶点数据
- gs_load_vertexbuffer(graphics->sprite_buffer); //设置curVertexBuffer为graphics->sprite_buffer
- gs_load_indexbuffer(NULL); //顶点索引没有用
- gs_draw(GS_TRISTRIP, 0, 0)
- device->FlushOutputViews();//设置OMSetRenderTargets
- gs_effect_update_params(effect)
- upload_parameters(effect, true)
- device->LoadVertexBufferData(); //IASetVertexBuffers
- device->UpdateBlendState(); //OMSetBlendState
- device->UpdateRasterState(); //光栅化配置
- device->UpdateZStencilState(); //OMSetDepthStencilState
- device->UpdateViewProjMatrix();
- device->curVertexShader->UploadParams();//更新顶点着色器参数到着色器常量空间
- device->curPixelShader->UploadParams(); //更新像系着色器参数到着色器常量空间
- device->context->Draw(num_verts, start_vert); //最终绘制D3D11DeviceContext::Draw