duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

d3d12_builders.cpp (11419B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0)
      3 
      4 #include "d3d12_builders.h"
      5 #include "d3d12_device.h"
      6 
      7 #include "common/assert.h"
      8 #include "common/error.h"
      9 #include "common/string_util.h"
     10 
     11 #include <cstdarg>
     12 #include <limits>
     13 
     14 D3D12::GraphicsPipelineBuilder::GraphicsPipelineBuilder()
     15 {
     16   Clear();
     17 }
     18 
     19 void D3D12::GraphicsPipelineBuilder::Clear()
     20 {
     21   std::memset(&m_desc, 0, sizeof(m_desc));
     22   std::memset(m_input_elements.data(), 0, sizeof(D3D12_INPUT_ELEMENT_DESC) * m_input_elements.size());
     23   m_desc.NodeMask = 1;
     24   m_desc.SampleMask = 0xFFFFFFFF;
     25   m_desc.SampleDesc.Count = 1;
     26 }
     27 
     28 Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::GraphicsPipelineBuilder::Create(ID3D12Device* device, Error* error,
     29                                                                                    bool clear)
     30 {
     31   Microsoft::WRL::ComPtr<ID3D12PipelineState> ps;
     32   HRESULT hr = device->CreateGraphicsPipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf()));
     33   if (FAILED(hr))
     34   {
     35     Error::SetHResult(error, "CreateGraphicsPipelineState() failed: ", hr);
     36     return {};
     37   }
     38 
     39   if (clear)
     40     Clear();
     41 
     42   return ps;
     43 }
     44 
     45 void D3D12::GraphicsPipelineBuilder::SetRootSignature(ID3D12RootSignature* rs)
     46 {
     47   m_desc.pRootSignature = rs;
     48 }
     49 
     50 void D3D12::GraphicsPipelineBuilder::SetVertexShader(const ID3DBlob* blob)
     51 {
     52   SetVertexShader(const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
     53                   static_cast<u32>(const_cast<ID3DBlob*>(blob)->GetBufferSize()));
     54 }
     55 
     56 void D3D12::GraphicsPipelineBuilder::SetVertexShader(const void* data, u32 data_size)
     57 {
     58   m_desc.VS.pShaderBytecode = data;
     59   m_desc.VS.BytecodeLength = data_size;
     60 }
     61 
     62 void D3D12::GraphicsPipelineBuilder::SetGeometryShader(const ID3DBlob* blob)
     63 {
     64   SetGeometryShader(const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
     65                     static_cast<u32>(const_cast<ID3DBlob*>(blob)->GetBufferSize()));
     66 }
     67 
     68 void D3D12::GraphicsPipelineBuilder::SetGeometryShader(const void* data, u32 data_size)
     69 {
     70   m_desc.GS.pShaderBytecode = data;
     71   m_desc.GS.BytecodeLength = data_size;
     72 }
     73 
     74 void D3D12::GraphicsPipelineBuilder::SetPixelShader(const ID3DBlob* blob)
     75 {
     76   SetPixelShader(const_cast<ID3DBlob*>(blob)->GetBufferPointer(),
     77                  static_cast<u32>(const_cast<ID3DBlob*>(blob)->GetBufferSize()));
     78 }
     79 
     80 void D3D12::GraphicsPipelineBuilder::SetPixelShader(const void* data, u32 data_size)
     81 {
     82   m_desc.PS.pShaderBytecode = data;
     83   m_desc.PS.BytecodeLength = data_size;
     84 }
     85 
     86 void D3D12::GraphicsPipelineBuilder::AddVertexAttribute(const char* semantic_name, u32 semantic_index,
     87                                                         DXGI_FORMAT format, u32 buffer, u32 offset)
     88 {
     89   const u32 index = m_desc.InputLayout.NumElements;
     90   m_input_elements[index].SemanticIndex = semantic_index;
     91   m_input_elements[index].SemanticName = semantic_name;
     92   m_input_elements[index].Format = format;
     93   m_input_elements[index].AlignedByteOffset = offset;
     94   m_input_elements[index].InputSlot = buffer;
     95   m_input_elements[index].InputSlotClass = D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA;
     96   m_input_elements[index].InstanceDataStepRate = 0;
     97 
     98   m_desc.InputLayout.pInputElementDescs = m_input_elements.data();
     99   m_desc.InputLayout.NumElements++;
    100 }
    101 
    102 void D3D12::GraphicsPipelineBuilder::SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE type)
    103 {
    104   m_desc.PrimitiveTopologyType = type;
    105 }
    106 
    107 void D3D12::GraphicsPipelineBuilder::SetRasterizationState(D3D12_FILL_MODE polygon_mode, D3D12_CULL_MODE cull_mode,
    108                                                            bool front_face_ccw)
    109 {
    110   m_desc.RasterizerState.FillMode = polygon_mode;
    111   m_desc.RasterizerState.CullMode = cull_mode;
    112   m_desc.RasterizerState.FrontCounterClockwise = front_face_ccw;
    113 }
    114 
    115 void D3D12::GraphicsPipelineBuilder::SetMultisamples(u32 multisamples)
    116 {
    117   m_desc.RasterizerState.MultisampleEnable = multisamples > 1;
    118   m_desc.SampleDesc.Count = multisamples;
    119 }
    120 
    121 void D3D12::GraphicsPipelineBuilder::SetNoCullRasterizationState()
    122 {
    123   SetRasterizationState(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE, false);
    124 }
    125 
    126 void D3D12::GraphicsPipelineBuilder::SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op)
    127 {
    128   m_desc.DepthStencilState.DepthEnable = depth_test;
    129   m_desc.DepthStencilState.DepthWriteMask = depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
    130   m_desc.DepthStencilState.DepthFunc = compare_op;
    131 }
    132 
    133 void D3D12::GraphicsPipelineBuilder::SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask,
    134                                                      const D3D12_DEPTH_STENCILOP_DESC& front,
    135                                                      const D3D12_DEPTH_STENCILOP_DESC& back)
    136 {
    137   m_desc.DepthStencilState.StencilEnable = stencil_test;
    138   m_desc.DepthStencilState.StencilReadMask = read_mask;
    139   m_desc.DepthStencilState.StencilWriteMask = write_mask;
    140   m_desc.DepthStencilState.FrontFace = front;
    141   m_desc.DepthStencilState.BackFace = back;
    142 }
    143 
    144 void D3D12::GraphicsPipelineBuilder::SetNoDepthTestState()
    145 {
    146   SetDepthState(false, false, D3D12_COMPARISON_FUNC_ALWAYS);
    147 }
    148 
    149 void D3D12::GraphicsPipelineBuilder::SetNoStencilState()
    150 {
    151   D3D12_DEPTH_STENCILOP_DESC empty = {};
    152   SetStencilState(false, 0, 0, empty, empty);
    153 }
    154 
    155 void D3D12::GraphicsPipelineBuilder::SetBlendState(u32 rt, bool blend_enable, D3D12_BLEND src_factor,
    156                                                    D3D12_BLEND dst_factor, D3D12_BLEND_OP op,
    157                                                    D3D12_BLEND alpha_src_factor, D3D12_BLEND alpha_dst_factor,
    158                                                    D3D12_BLEND_OP alpha_op, u8 write_mask /*= 0xFF*/)
    159 {
    160   m_desc.BlendState.RenderTarget[rt].BlendEnable = blend_enable;
    161   m_desc.BlendState.RenderTarget[rt].SrcBlend = src_factor;
    162   m_desc.BlendState.RenderTarget[rt].DestBlend = dst_factor;
    163   m_desc.BlendState.RenderTarget[rt].BlendOp = op;
    164   m_desc.BlendState.RenderTarget[rt].SrcBlendAlpha = alpha_src_factor;
    165   m_desc.BlendState.RenderTarget[rt].DestBlendAlpha = alpha_dst_factor;
    166   m_desc.BlendState.RenderTarget[rt].BlendOpAlpha = alpha_op;
    167   m_desc.BlendState.RenderTarget[rt].RenderTargetWriteMask = write_mask;
    168 
    169   if (rt > 0)
    170     m_desc.BlendState.IndependentBlendEnable = TRUE;
    171 }
    172 
    173 void D3D12::GraphicsPipelineBuilder::SetColorWriteMask(u32 rt, u8 write_mask /* = D3D12_COLOR_WRITE_ENABLE_ALL */)
    174 {
    175   m_desc.BlendState.RenderTarget[rt].RenderTargetWriteMask = write_mask;
    176 }
    177 
    178 void D3D12::GraphicsPipelineBuilder::SetNoBlendingState()
    179 {
    180   SetBlendState(0, false, D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, D3D12_BLEND_ONE, D3D12_BLEND_ZERO,
    181                 D3D12_BLEND_OP_ADD, D3D12_COLOR_WRITE_ENABLE_ALL);
    182   m_desc.BlendState.IndependentBlendEnable = FALSE;
    183 }
    184 
    185 void D3D12::GraphicsPipelineBuilder::ClearRenderTargets()
    186 {
    187   m_desc.NumRenderTargets = 0;
    188   for (u32 i = 0; i < sizeof(m_desc.RTVFormats) / sizeof(m_desc.RTVFormats[0]); i++)
    189     m_desc.RTVFormats[i] = DXGI_FORMAT_UNKNOWN;
    190 }
    191 
    192 void D3D12::GraphicsPipelineBuilder::SetRenderTarget(u32 rt, DXGI_FORMAT format)
    193 {
    194   m_desc.RTVFormats[rt] = format;
    195   if (rt >= m_desc.NumRenderTargets)
    196     m_desc.NumRenderTargets = rt + 1;
    197 }
    198 
    199 void D3D12::GraphicsPipelineBuilder::ClearDepthStencilFormat()
    200 {
    201   m_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
    202 }
    203 
    204 void D3D12::GraphicsPipelineBuilder::SetDepthStencilFormat(DXGI_FORMAT format)
    205 {
    206   m_desc.DSVFormat = format;
    207 }
    208 
    209 D3D12::ComputePipelineBuilder::ComputePipelineBuilder()
    210 {
    211   Clear();
    212 }
    213 
    214 void D3D12::ComputePipelineBuilder::Clear()
    215 {
    216   std::memset(&m_desc, 0, sizeof(m_desc));
    217 }
    218 
    219 Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::ComputePipelineBuilder::Create(ID3D12Device* device, Error* error,
    220                                                                                   bool clear)
    221 {
    222   Microsoft::WRL::ComPtr<ID3D12PipelineState> ps;
    223   HRESULT hr = device->CreateComputePipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf()));
    224   if (FAILED(hr)) [[unlikely]]
    225   {
    226     Error::SetHResult(error, "CreateComputePipelineState() failed: ", hr);
    227     return {};
    228   }
    229 
    230   if (clear)
    231     Clear();
    232 
    233   return ps;
    234 }
    235 
    236 void D3D12::ComputePipelineBuilder::SetRootSignature(ID3D12RootSignature* rs)
    237 {
    238   m_desc.pRootSignature = rs;
    239 }
    240 
    241 void D3D12::ComputePipelineBuilder::SetShader(const void* data, u32 data_size)
    242 {
    243   m_desc.CS.pShaderBytecode = data;
    244   m_desc.CS.BytecodeLength = data_size;
    245 }
    246 
    247 D3D12::RootSignatureBuilder::RootSignatureBuilder()
    248 {
    249   Clear();
    250 }
    251 
    252 void D3D12::RootSignatureBuilder::Clear()
    253 {
    254   m_desc = {};
    255   m_desc.pParameters = m_params.data();
    256   m_params = {};
    257   m_descriptor_ranges = {};
    258   m_num_descriptor_ranges = 0;
    259 }
    260 
    261 Microsoft::WRL::ComPtr<ID3D12RootSignature> D3D12::RootSignatureBuilder::Create(Error* error, bool clear)
    262 {
    263   Microsoft::WRL::ComPtr<ID3D12RootSignature> rs = D3D12Device::GetInstance().CreateRootSignature(&m_desc, error);
    264   if (!rs)
    265     return {};
    266 
    267   if (clear)
    268     Clear();
    269 
    270   return rs;
    271 }
    272 
    273 void D3D12::RootSignatureBuilder::SetInputAssemblerFlag()
    274 {
    275   m_desc.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
    276 }
    277 
    278 u32 D3D12::RootSignatureBuilder::Add32BitConstants(u32 shader_reg, u32 num_values, D3D12_SHADER_VISIBILITY visibility)
    279 {
    280   const u32 index = m_desc.NumParameters++;
    281 
    282   m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
    283   m_params[index].ShaderVisibility = visibility;
    284   m_params[index].Constants.ShaderRegister = shader_reg;
    285   m_params[index].Constants.RegisterSpace = 0;
    286   m_params[index].Constants.Num32BitValues = num_values;
    287 
    288   return index;
    289 }
    290 
    291 u32 D3D12::RootSignatureBuilder::AddCBVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility)
    292 {
    293   const u32 index = m_desc.NumParameters++;
    294 
    295   m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
    296   m_params[index].ShaderVisibility = visibility;
    297   m_params[index].Descriptor.ShaderRegister = shader_reg;
    298   m_params[index].Descriptor.RegisterSpace = 0;
    299 
    300   return index;
    301 }
    302 
    303 u32 D3D12::RootSignatureBuilder::AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility)
    304 {
    305   const u32 index = m_desc.NumParameters++;
    306 
    307   m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
    308   m_params[index].ShaderVisibility = visibility;
    309   m_params[index].Descriptor.ShaderRegister = shader_reg;
    310   m_params[index].Descriptor.RegisterSpace = 0;
    311 
    312   return index;
    313 }
    314 
    315 u32 D3D12::RootSignatureBuilder::AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE rt, u32 start_shader_reg,
    316                                                     u32 num_shader_regs, D3D12_SHADER_VISIBILITY visibility)
    317 {
    318   const u32 index = m_desc.NumParameters++;
    319   const u32 dr_index = m_num_descriptor_ranges++;
    320 
    321   m_descriptor_ranges[dr_index].RangeType = rt;
    322   m_descriptor_ranges[dr_index].NumDescriptors = num_shader_regs;
    323   m_descriptor_ranges[dr_index].BaseShaderRegister = start_shader_reg;
    324   m_descriptor_ranges[dr_index].RegisterSpace = 0;
    325   m_descriptor_ranges[dr_index].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
    326 
    327   m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
    328   m_params[index].DescriptorTable.pDescriptorRanges = &m_descriptor_ranges[dr_index];
    329   m_params[index].DescriptorTable.NumDescriptorRanges = 1;
    330   m_params[index].ShaderVisibility = visibility;
    331 
    332   return index;
    333 }
    334 
    335 #ifdef _DEBUG
    336 
    337 void D3D12::SetObjectName(ID3D12Object* object, std::string_view name)
    338 {
    339   object->SetName(StringUtil::UTF8StringToWideString(name).c_str());
    340 }
    341 
    342 #endif