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