Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/src/util/d3d12_builders.cpp
7333 views
1
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <[email protected]>
2
// SPDX-License-Identifier: CC-BY-NC-ND-4.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::SetDepthState(bool depth_test, bool depth_write, D3D12_COMPARISON_FUNC compare_op)
122
{
123
m_desc.DepthStencilState.DepthEnable = depth_test;
124
m_desc.DepthStencilState.DepthWriteMask = depth_write ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
125
m_desc.DepthStencilState.DepthFunc = compare_op;
126
}
127
128
void D3D12::GraphicsPipelineBuilder::SetStencilState(bool stencil_test, u8 read_mask, u8 write_mask,
129
const D3D12_DEPTH_STENCILOP_DESC& front,
130
const D3D12_DEPTH_STENCILOP_DESC& back)
131
{
132
m_desc.DepthStencilState.StencilEnable = stencil_test;
133
m_desc.DepthStencilState.StencilReadMask = read_mask;
134
m_desc.DepthStencilState.StencilWriteMask = write_mask;
135
m_desc.DepthStencilState.FrontFace = front;
136
m_desc.DepthStencilState.BackFace = back;
137
}
138
139
void D3D12::GraphicsPipelineBuilder::SetNoStencilState()
140
{
141
D3D12_DEPTH_STENCILOP_DESC empty = {};
142
SetStencilState(false, 0, 0, empty, empty);
143
}
144
145
void D3D12::GraphicsPipelineBuilder::SetBlendState(u32 rt, bool blend_enable, D3D12_BLEND src_factor,
146
D3D12_BLEND dst_factor, D3D12_BLEND_OP op,
147
D3D12_BLEND alpha_src_factor, D3D12_BLEND alpha_dst_factor,
148
D3D12_BLEND_OP alpha_op, u8 write_mask /*= 0xFF*/)
149
{
150
m_desc.BlendState.RenderTarget[rt].BlendEnable = blend_enable;
151
m_desc.BlendState.RenderTarget[rt].SrcBlend = src_factor;
152
m_desc.BlendState.RenderTarget[rt].DestBlend = dst_factor;
153
m_desc.BlendState.RenderTarget[rt].BlendOp = op;
154
m_desc.BlendState.RenderTarget[rt].SrcBlendAlpha = alpha_src_factor;
155
m_desc.BlendState.RenderTarget[rt].DestBlendAlpha = alpha_dst_factor;
156
m_desc.BlendState.RenderTarget[rt].BlendOpAlpha = alpha_op;
157
m_desc.BlendState.RenderTarget[rt].RenderTargetWriteMask = write_mask;
158
159
if (rt > 0)
160
m_desc.BlendState.IndependentBlendEnable = TRUE;
161
}
162
163
void D3D12::GraphicsPipelineBuilder::ClearRenderTargets()
164
{
165
m_desc.NumRenderTargets = 0;
166
for (u32 i = 0; i < sizeof(m_desc.RTVFormats) / sizeof(m_desc.RTVFormats[0]); i++)
167
m_desc.RTVFormats[i] = DXGI_FORMAT_UNKNOWN;
168
}
169
170
void D3D12::GraphicsPipelineBuilder::SetRenderTarget(u32 rt, DXGI_FORMAT format)
171
{
172
m_desc.RTVFormats[rt] = format;
173
if (rt >= m_desc.NumRenderTargets)
174
m_desc.NumRenderTargets = rt + 1;
175
}
176
177
void D3D12::GraphicsPipelineBuilder::ClearDepthStencilFormat()
178
{
179
m_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
180
}
181
182
void D3D12::GraphicsPipelineBuilder::SetDepthStencilFormat(DXGI_FORMAT format)
183
{
184
m_desc.DSVFormat = format;
185
}
186
187
D3D12::ComputePipelineBuilder::ComputePipelineBuilder()
188
{
189
Clear();
190
}
191
192
void D3D12::ComputePipelineBuilder::Clear()
193
{
194
std::memset(&m_desc, 0, sizeof(m_desc));
195
}
196
197
Microsoft::WRL::ComPtr<ID3D12PipelineState> D3D12::ComputePipelineBuilder::Create(ID3D12Device* device, Error* error,
198
bool clear)
199
{
200
Microsoft::WRL::ComPtr<ID3D12PipelineState> ps;
201
HRESULT hr = device->CreateComputePipelineState(&m_desc, IID_PPV_ARGS(ps.GetAddressOf()));
202
if (FAILED(hr)) [[unlikely]]
203
{
204
Error::SetHResult(error, "CreateComputePipelineState() failed: ", hr);
205
return {};
206
}
207
208
if (clear)
209
Clear();
210
211
return ps;
212
}
213
214
void D3D12::ComputePipelineBuilder::SetRootSignature(ID3D12RootSignature* rs)
215
{
216
m_desc.pRootSignature = rs;
217
}
218
219
void D3D12::ComputePipelineBuilder::SetShader(const void* data, u32 data_size)
220
{
221
m_desc.CS.pShaderBytecode = data;
222
m_desc.CS.BytecodeLength = data_size;
223
}
224
225
D3D12::RootSignatureBuilder::RootSignatureBuilder()
226
{
227
Clear();
228
}
229
230
void D3D12::RootSignatureBuilder::Clear()
231
{
232
m_desc = {};
233
m_desc.pParameters = m_params.data();
234
m_params = {};
235
m_descriptor_ranges = {};
236
m_num_descriptor_ranges = 0;
237
}
238
239
Microsoft::WRL::ComPtr<ID3D12RootSignature> D3D12::RootSignatureBuilder::Create(Error* error, bool clear)
240
{
241
Microsoft::WRL::ComPtr<ID3D12RootSignature> rs = D3D12Device::GetInstance().CreateRootSignature(&m_desc, error);
242
if (!rs)
243
return {};
244
245
if (clear)
246
Clear();
247
248
return rs;
249
}
250
251
void D3D12::RootSignatureBuilder::SetInputAssemblerFlag()
252
{
253
m_desc.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
254
}
255
256
u32 D3D12::RootSignatureBuilder::Add32BitConstants(u32 shader_reg, u32 num_values, D3D12_SHADER_VISIBILITY visibility)
257
{
258
const u32 index = m_desc.NumParameters++;
259
DebugAssert(index < MAX_PARAMETERS);
260
261
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
262
m_params[index].ShaderVisibility = visibility;
263
m_params[index].Constants.ShaderRegister = shader_reg;
264
m_params[index].Constants.RegisterSpace = 0;
265
m_params[index].Constants.Num32BitValues = num_values;
266
267
return index;
268
}
269
270
u32 D3D12::RootSignatureBuilder::AddCBVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility)
271
{
272
const u32 index = m_desc.NumParameters++;
273
DebugAssert(index < MAX_PARAMETERS);
274
275
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV;
276
m_params[index].ShaderVisibility = visibility;
277
m_params[index].Descriptor.ShaderRegister = shader_reg;
278
m_params[index].Descriptor.RegisterSpace = 0;
279
280
return index;
281
}
282
283
u32 D3D12::RootSignatureBuilder::AddSRVParameter(u32 shader_reg, D3D12_SHADER_VISIBILITY visibility)
284
{
285
const u32 index = m_desc.NumParameters++;
286
DebugAssert(index < MAX_PARAMETERS);
287
288
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_SRV;
289
m_params[index].ShaderVisibility = visibility;
290
m_params[index].Descriptor.ShaderRegister = shader_reg;
291
m_params[index].Descriptor.RegisterSpace = 0;
292
293
return index;
294
}
295
296
u32 D3D12::RootSignatureBuilder::AddDescriptorTable(D3D12_DESCRIPTOR_RANGE_TYPE rt, u32 start_shader_reg,
297
u32 num_shader_regs, D3D12_SHADER_VISIBILITY visibility)
298
{
299
const u32 index = m_desc.NumParameters++;
300
const u32 dr_index = m_num_descriptor_ranges++;
301
DebugAssert(index < MAX_PARAMETERS);
302
DebugAssert(dr_index < MAX_DESCRIPTOR_RANGES);
303
304
m_descriptor_ranges[dr_index].RangeType = rt;
305
m_descriptor_ranges[dr_index].NumDescriptors = num_shader_regs;
306
m_descriptor_ranges[dr_index].BaseShaderRegister = start_shader_reg;
307
m_descriptor_ranges[dr_index].RegisterSpace = 0;
308
m_descriptor_ranges[dr_index].OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND;
309
310
m_params[index].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
311
m_params[index].DescriptorTable.pDescriptorRanges = &m_descriptor_ranges[dr_index];
312
m_params[index].DescriptorTable.NumDescriptorRanges = 1;
313
m_params[index].ShaderVisibility = visibility;
314
315
return index;
316
}
317
318
u32 D3D12::RootSignatureBuilder::AddStaticSampler(u32 shader_reg, const D3D12_SAMPLER_DESC& sampler_desc,
319
D3D12_SHADER_VISIBILITY visibility)
320
{
321
static constexpr const std::pair<std::array<float, 4>, D3D12_STATIC_BORDER_COLOR> border_color_mapping[] = {
322
{{{0.0f, 0.0f, 0.0f, 0.0f}}, D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK},
323
{{{0.0f, 0.0f, 0.0f, 1.0f}}, D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK},
324
{{{1.0f, 1.0f, 1.0f, 1.0f}}, D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE},
325
};
326
327
const u32 index = m_desc.NumStaticSamplers++;
328
DebugAssert(index < MAX_STATIC_SAMPLERS);
329
m_desc.pStaticSamplers = m_static_samplers.data();
330
331
D3D12_STATIC_SAMPLER_DESC& ssdesc = m_static_samplers[index];
332
ssdesc.Filter = sampler_desc.Filter;
333
ssdesc.AddressU = sampler_desc.AddressU;
334
ssdesc.AddressV = sampler_desc.AddressV;
335
ssdesc.AddressW = sampler_desc.AddressW;
336
ssdesc.MipLODBias = sampler_desc.MipLODBias;
337
ssdesc.MaxAnisotropy = sampler_desc.MaxAnisotropy;
338
ssdesc.ComparisonFunc = sampler_desc.ComparisonFunc;
339
ssdesc.BorderColor = D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK;
340
if (sampler_desc.AddressU == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
341
sampler_desc.AddressV == D3D12_TEXTURE_ADDRESS_MODE_BORDER ||
342
sampler_desc.AddressW == D3D12_TEXTURE_ADDRESS_MODE_BORDER)
343
{
344
u32 i;
345
for (i = 0; i < static_cast<u32>(std::size(border_color_mapping)); i++)
346
{
347
if (std::memcmp(border_color_mapping[i].first.data(), sampler_desc.BorderColor, sizeof(float) * 4) == 0)
348
break;
349
}
350
if (i == std::size(border_color_mapping))
351
Panic("Unsupported border color");
352
else
353
ssdesc.BorderColor = border_color_mapping[i].second;
354
}
355
356
ssdesc.MinLOD = sampler_desc.MinLOD;
357
ssdesc.MaxLOD = sampler_desc.MaxLOD;
358
ssdesc.ShaderRegister = shader_reg;
359
ssdesc.RegisterSpace = 0;
360
ssdesc.ShaderVisibility = visibility;
361
362
return index;
363
}
364
365
#ifdef ENABLE_GPU_OBJECT_NAMES
366
367
void D3D12::SetObjectName(ID3D12Object* object, std::string_view name)
368
{
369
object->SetName(StringUtil::UTF8StringToWideString(name).c_str());
370
}
371
372
#endif
373
374