D3D11 HLSL注意项

memetao 于 2023-08-26 发布

纹理

DXGI FORMAT对应HLSL中的类型

| DXGI | HLSL | | —————————— | ———— | | DXGI_FORMAT_R32_FLOAT | float | | DXGI_FORMAT_R32G32_FLOAT | float2 | | DXGI_FORMAT_R32G32B32A32_FLOAT | float4 | | DXGI_FORMAT_R32_UINT | uint | | DXGI_FORMAT_R32G32_UINT | uint2 | | DXGI_FORMAT_R32G32B32A32_UINT | uint4 | | DXGI_FORMAT_R32_SINT | int | | DXGI_FORMAT_R32G32_SINT | int2 | | DXGI_FORMAT_R32G32B32A32_SINT | int4 | | DXGI_FORMAT_R16G16B16A16_FLOAT | float4 | | DXGI_FORMAT_R8G8B8A8_UNORM | unorm float4 | | DXGI_FORMAT_R8G8B8A8_SNORM | snorm float4 |

其中unorm float表示的是一个32位无符号的,规格化的浮点数,可以表示范围0到1 而与之对应的snorm float表示的是32位有符号的,规格化的浮点数,可以表示范围-1到1

USAGE

| D3D11_USAGE | CPU读 | CPU写 | GPU读 | GPU写 | | ——————— | —– | —– | —– | —– | | D3D11_USAGE_DEFAULT | | | √ | √ | | D3D11_USAGE_IMMUTABLE | √ | | | | | D3D11_USAGE_DYNAMIC | | √ | √ | | | D3D11_USAGE_STAGING | √ | √ | √ | √ |

BindFlag

| D3D11_BIND_FLAG | 描述 | | ————————— | ———————————————————– | | D3D11_BIND_SHADER_RESOURCE | 纹理可以作为着色器资源绑定到渲染管线 | | D3D11_BIND_STREAM_OUTPUT | 纹理可以作为流输出阶段的输出点 | | D3D11_BIND_RENDER_TARGET | 纹理可以作为渲染目标的输出点,并且指定它可以用于生成mipmaps | | D3D11_BIND_DEPTH_STENCIL | 纹理可以作为深度/模板缓冲区 | | D3D11_BIND_UNORDERED_ACCESS | 纹理可以绑定到无序访问视图作为输出 |

CPU ACESS

D3D11_CPU_ACCESS_FLAG 描述
D3D11_CPU_ACCESS_WRITE 允许通过映射方式从CPU写入,它不能作为管线的输出,且只能用于D3D11_USAGE_DYNAMIC和D3D11_USAGE_STAGING绑定的资源
D3D11_CPU_ACCESS_READ 允许通过映射方式给CPU读取,它不能作为管线的输入或输出,且只能用于D3D11_USAGE_STAGING绑定的资源

Vertex Shadler

D3D11_INPUT_ELEMENT_DESC input_desc[] =
{
    // 我们知道DXGI_FORMAT_R32G32B32_FLOAT是12字节的
    {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0},
    {"COLOR",    0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
CreateInputLayout(VERTEX::input_desc, std::size(VERTEX::input_desc), ...);

当我们在C++里面写入上述代码的时候, 是告诉D3D11已”Position”和”Color”解析输入的Vertex数据。

于是, 我们将下面的数据传给D3D11:

VERTEX OurVertices[] = {
    // 每组数据3 * 4 + 3 * 4 = 24字节
    {DirectX::XMFLOAT3{0.0f, 0.5f, 0.0f}, DirectX::XMFLOAT3(1.0f, 0.0f, 0.0f)},
    {DirectX::XMFLOAT3{0.45f, -0.5, 0.0f}, DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f)},
    {DirectX::XMFLOAT3{-0.45f, -0.5f, 0.0f}, DirectX::XMFLOAT3(0.0f, 0.0f, 1.0f)},
};
CreateBuffer(&vertex_buf_);
IASetVertexBuffers(vertex_buf_);

关键字语义

Semantic Description
POSITION A float4 value that stores position. It is used to denote the position of vertices, usually (but not necessarily) in 3D space.
COLOR A float4 value that stored color
SV_POSITION A float4 value that stores position. It is used to denote the position in normalized screen coordinates, not 3D coordinates.
SV_TARGET A float4 value telling the output-merger to draw the given color on the render target.

// 为什么是float4, 而不是float3?搞不懂
// 实测float3也可以work
struct VOut {
    float4 position : SV_POSITION;
    float4 color : COLOR;
};


VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
    VOut output;
    output.position = position;
    output.color = color;
    return output;
}

// 使用的是normailized坐标, 返回值是给输出合并阶段的用的, 输出到render Target上
float4 PShader(float4 position : SV_POSITION,
    float4 color: COLOR): SV_TARGET
{
    return color;
}

为什么是float4?

顶点声明中的默认纹理坐标:

提供给像素着色器的纹理坐标必须具有四个分量, (u、v、w、q) 。 如果缺少 u、v 或 w 组件,硬件或驱动程序必须向该组件提供默认值 0。 如果缺少 q 组件,硬件或驱动程序必须向该组件提供默认值 1。 因此,如果缺少所有组件,则默认值 (0,0,0,1) 。 例如,如果将 2D 纹理坐标发送到使用 3D 纹理坐标的像素着色器,则硬件或驱动程序会分别向第 3 和第 4 个分量提供默认值 0 和 1。

也就是说即使我们的input_layout里面说了是12字节, 但是驱动会默认对齐到16字节?

HLSL 结构对齐的问题

下面是常量缓冲区的对齐规则, 但是顶点缓冲区的对齐规则又是咋样的, 为什么大家都是写float4?

see: https://www.cnblogs.com/X-Jun/p/9376474.html

不知道用什么工具可以对GPU数据进行DEBUG呢?

参考文档