Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/d3d12/d3d12_pipeline_state.cpp
4570 views
1
/*
2
* Copyright © Microsoft Corporation
3
*
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
10
*
11
* The above copyright notice and this permission notice (including the next
12
* paragraph) shall be included in all copies or substantial portions of the
13
* Software.
14
*
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21
* IN THE SOFTWARE.
22
*/
23
24
#include "d3d12_pipeline_state.h"
25
#include "d3d12_compiler.h"
26
#include "d3d12_context.h"
27
#include "d3d12_screen.h"
28
29
#include "util/hash_table.h"
30
#include "util/set.h"
31
#include "util/u_memory.h"
32
#include "util/u_prim.h"
33
34
#include <dxguids/dxguids.h>
35
36
struct d3d12_pso_entry {
37
struct d3d12_gfx_pipeline_state key;
38
ID3D12PipelineState *pso;
39
};
40
41
static const char *
42
get_semantic_name(int slot, unsigned *index)
43
{
44
*index = 0; /* Default index */
45
46
switch (slot) {
47
48
case VARYING_SLOT_POS:
49
return "SV_Position";
50
51
case VARYING_SLOT_FACE:
52
return "SV_IsFrontFace";
53
54
case VARYING_SLOT_CLIP_DIST1:
55
*index = 1;
56
FALLTHROUGH;
57
case VARYING_SLOT_CLIP_DIST0:
58
return "SV_ClipDistance";
59
60
case VARYING_SLOT_PRIMITIVE_ID:
61
return "SV_PrimitiveID";
62
63
default: {
64
*index = slot - VARYING_SLOT_POS;
65
return "TEXCOORD";
66
}
67
}
68
}
69
70
static void
71
fill_so_declaration(const struct pipe_stream_output_info *info,
72
D3D12_SO_DECLARATION_ENTRY *entries, UINT *num_entries,
73
UINT *strides, UINT *num_strides)
74
{
75
int next_offset[MAX_VERTEX_STREAMS] = { 0 };
76
77
*num_entries = 0;
78
79
for (unsigned i = 0; i < info->num_outputs; i++) {
80
const struct pipe_stream_output *output = &info->output[i];
81
const int buffer = output->output_buffer;
82
unsigned index;
83
84
/* Mesa doesn't store entries for gl_SkipComponents in the Outputs[]
85
* array. Instead, it simply increments DstOffset for the following
86
* input by the number of components that should be skipped.
87
*
88
* DirectX12 requires that we create gap entries.
89
*/
90
int skip_components = output->dst_offset - next_offset[buffer];
91
92
if (skip_components > 0) {
93
entries[*num_entries].Stream = output->stream;
94
entries[*num_entries].SemanticName = NULL;
95
entries[*num_entries].ComponentCount = skip_components;
96
entries[*num_entries].OutputSlot = buffer;
97
(*num_entries)++;
98
}
99
100
next_offset[buffer] = output->dst_offset + output->num_components;
101
102
entries[*num_entries].Stream = output->stream;
103
entries[*num_entries].SemanticName = get_semantic_name(output->register_index, &index);
104
entries[*num_entries].SemanticIndex = index;
105
entries[*num_entries].StartComponent = output->start_component;
106
entries[*num_entries].ComponentCount = output->num_components;
107
entries[*num_entries].OutputSlot = buffer;
108
(*num_entries)++;
109
}
110
111
for (unsigned i = 0; i < MAX_VERTEX_STREAMS; i++)
112
strides[i] = info->stride[i] * 4;
113
*num_strides = MAX_VERTEX_STREAMS;
114
}
115
116
static bool
117
depth_bias(struct d3d12_rasterizer_state *state, enum pipe_prim_type reduced_prim)
118
{
119
/* glPolygonOffset is supposed to be only enabled when rendering polygons.
120
* In d3d12 case, all polygons (and quads) are lowered to triangles */
121
if (reduced_prim != PIPE_PRIM_TRIANGLES)
122
return false;
123
124
unsigned fill_mode = state->base.cull_face == PIPE_FACE_FRONT ? state->base.fill_back
125
: state->base.fill_front;
126
127
switch (fill_mode) {
128
case PIPE_POLYGON_MODE_FILL:
129
return state->base.offset_tri;
130
131
case PIPE_POLYGON_MODE_LINE:
132
return state->base.offset_line;
133
134
case PIPE_POLYGON_MODE_POINT:
135
return state->base.offset_point;
136
137
default:
138
unreachable("unexpected fill mode");
139
}
140
}
141
142
static D3D12_PRIMITIVE_TOPOLOGY_TYPE
143
topology_type(enum pipe_prim_type reduced_prim)
144
{
145
switch (reduced_prim) {
146
case PIPE_PRIM_POINTS:
147
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
148
149
case PIPE_PRIM_LINES:
150
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
151
152
case PIPE_PRIM_TRIANGLES:
153
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
154
155
case PIPE_PRIM_PATCHES:
156
return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
157
158
default:
159
debug_printf("pipe_prim_type: %s\n", u_prim_name(reduced_prim));
160
unreachable("unexpected enum pipe_prim_type");
161
}
162
}
163
164
DXGI_FORMAT
165
d3d12_rtv_format(struct d3d12_context *ctx, unsigned index)
166
{
167
DXGI_FORMAT fmt = ctx->gfx_pipeline_state.rtv_formats[index];
168
169
if (ctx->gfx_pipeline_state.blend->desc.RenderTarget[0].LogicOpEnable &&
170
!ctx->gfx_pipeline_state.has_float_rtv) {
171
switch (fmt) {
172
case DXGI_FORMAT_R8G8B8A8_SNORM:
173
case DXGI_FORMAT_R8G8B8A8_UNORM:
174
case DXGI_FORMAT_B8G8R8A8_UNORM:
175
case DXGI_FORMAT_B8G8R8X8_UNORM:
176
return DXGI_FORMAT_R8G8B8A8_UINT;
177
default:
178
unreachable("unsupported logic-op format");
179
}
180
}
181
182
return fmt;
183
}
184
185
static ID3D12PipelineState *
186
create_gfx_pipeline_state(struct d3d12_context *ctx)
187
{
188
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
189
struct d3d12_gfx_pipeline_state *state = &ctx->gfx_pipeline_state;
190
enum pipe_prim_type reduced_prim = u_reduced_prim(state->prim_type);
191
D3D12_SO_DECLARATION_ENTRY entries[PIPE_MAX_SO_OUTPUTS] = {};
192
UINT strides[PIPE_MAX_SO_OUTPUTS] = { 0 };
193
UINT num_entries = 0, num_strides = 0;
194
195
D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { 0 };
196
pso_desc.pRootSignature = state->root_signature;
197
198
bool last_vertex_stage_writes_pos = false;
199
200
if (state->stages[PIPE_SHADER_VERTEX]) {
201
auto shader = state->stages[PIPE_SHADER_VERTEX];
202
pso_desc.VS.BytecodeLength = shader->bytecode_length;
203
pso_desc.VS.pShaderBytecode = shader->bytecode;
204
last_vertex_stage_writes_pos = (shader->nir->info.outputs_written & VARYING_BIT_POS) != 0;
205
}
206
207
if (state->stages[PIPE_SHADER_GEOMETRY]) {
208
auto shader = state->stages[PIPE_SHADER_GEOMETRY];
209
pso_desc.GS.BytecodeLength = shader->bytecode_length;
210
pso_desc.GS.pShaderBytecode = shader->bytecode;
211
last_vertex_stage_writes_pos = (shader->nir->info.outputs_written & VARYING_BIT_POS) != 0;
212
}
213
214
if (last_vertex_stage_writes_pos && state->stages[PIPE_SHADER_FRAGMENT] &&
215
!state->rast->base.rasterizer_discard) {
216
auto shader = state->stages[PIPE_SHADER_FRAGMENT];
217
pso_desc.PS.BytecodeLength = shader->bytecode_length;
218
pso_desc.PS.pShaderBytecode = shader->bytecode;
219
}
220
221
if (state->num_so_targets)
222
fill_so_declaration(&state->so_info, entries, &num_entries,
223
strides, &num_strides);
224
pso_desc.StreamOutput.NumEntries = num_entries;
225
pso_desc.StreamOutput.pSODeclaration = entries;
226
pso_desc.StreamOutput.RasterizedStream = state->rast->base.rasterizer_discard ? D3D12_SO_NO_RASTERIZED_STREAM : 0;
227
pso_desc.StreamOutput.NumStrides = num_strides;
228
pso_desc.StreamOutput.pBufferStrides = strides;
229
230
pso_desc.BlendState = state->blend->desc;
231
if (state->has_float_rtv)
232
pso_desc.BlendState.RenderTarget[0].LogicOpEnable = FALSE;
233
234
pso_desc.DepthStencilState = state->zsa->desc;
235
pso_desc.SampleMask = state->sample_mask;
236
pso_desc.RasterizerState = state->rast->desc;
237
238
if (reduced_prim != PIPE_PRIM_TRIANGLES)
239
pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
240
241
if (depth_bias(state->rast, reduced_prim)) {
242
pso_desc.RasterizerState.DepthBias = state->rast->base.offset_units * 2;
243
pso_desc.RasterizerState.DepthBiasClamp = state->rast->base.offset_clamp;
244
pso_desc.RasterizerState.SlopeScaledDepthBias = state->rast->base.offset_scale;
245
}
246
247
pso_desc.InputLayout.pInputElementDescs = state->ves->elements;
248
pso_desc.InputLayout.NumElements = state->ves->num_elements;
249
250
pso_desc.IBStripCutValue = state->ib_strip_cut_value;
251
252
pso_desc.PrimitiveTopologyType = topology_type(reduced_prim);
253
254
pso_desc.NumRenderTargets = state->num_cbufs;
255
for (unsigned i = 0; i < state->num_cbufs; ++i)
256
pso_desc.RTVFormats[i] = d3d12_rtv_format(ctx, i);
257
pso_desc.DSVFormat = state->dsv_format;
258
259
pso_desc.SampleDesc.Count = state->samples;
260
pso_desc.SampleDesc.Quality = 0;
261
262
pso_desc.NodeMask = 0;
263
264
pso_desc.CachedPSO.pCachedBlob = NULL;
265
pso_desc.CachedPSO.CachedBlobSizeInBytes = 0;
266
267
pso_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
268
269
ID3D12PipelineState *ret;
270
if (FAILED(screen->dev->CreateGraphicsPipelineState(&pso_desc,
271
IID_PPV_ARGS(&ret)))) {
272
debug_printf("D3D12: CreateGraphicsPipelineState failed!\n");
273
return NULL;
274
}
275
276
return ret;
277
}
278
279
static uint32_t
280
hash_gfx_pipeline_state(const void *key)
281
{
282
return _mesa_hash_data(key, sizeof(struct d3d12_gfx_pipeline_state));
283
}
284
285
static bool
286
equals_gfx_pipeline_state(const void *a, const void *b)
287
{
288
return memcmp(a, b, sizeof(struct d3d12_gfx_pipeline_state)) == 0;
289
}
290
291
ID3D12PipelineState *
292
d3d12_get_gfx_pipeline_state(struct d3d12_context *ctx)
293
{
294
uint32_t hash = hash_gfx_pipeline_state(&ctx->gfx_pipeline_state);
295
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->pso_cache, hash,
296
&ctx->gfx_pipeline_state);
297
if (!entry) {
298
struct d3d12_pso_entry *data = (struct d3d12_pso_entry *)MALLOC(sizeof(struct d3d12_pso_entry));
299
if (!data)
300
return NULL;
301
302
data->key = ctx->gfx_pipeline_state;
303
data->pso = create_gfx_pipeline_state(ctx);
304
if (!data->pso) {
305
FREE(data);
306
return NULL;
307
}
308
309
entry = _mesa_hash_table_insert_pre_hashed(ctx->pso_cache, hash, &data->key, data);
310
assert(entry);
311
}
312
313
return ((struct d3d12_pso_entry *)(entry->data))->pso;
314
}
315
316
void
317
d3d12_gfx_pipeline_state_cache_init(struct d3d12_context *ctx)
318
{
319
ctx->pso_cache = _mesa_hash_table_create(NULL, NULL, equals_gfx_pipeline_state);
320
}
321
322
static void
323
delete_entry(struct hash_entry *entry)
324
{
325
struct d3d12_pso_entry *data = (struct d3d12_pso_entry *)entry->data;
326
data->pso->Release();
327
FREE(data);
328
}
329
330
static void
331
remove_entry(struct d3d12_context *ctx, struct hash_entry *entry)
332
{
333
struct d3d12_pso_entry *data = (struct d3d12_pso_entry *)entry->data;
334
335
if (ctx->current_pso == data->pso)
336
ctx->current_pso = NULL;
337
_mesa_hash_table_remove(ctx->pso_cache, entry);
338
delete_entry(entry);
339
}
340
341
void
342
d3d12_gfx_pipeline_state_cache_destroy(struct d3d12_context *ctx)
343
{
344
_mesa_hash_table_destroy(ctx->pso_cache, delete_entry);
345
}
346
347
void
348
d3d12_gfx_pipeline_state_cache_invalidate(struct d3d12_context *ctx, const void *state)
349
{
350
hash_table_foreach(ctx->pso_cache, entry) {
351
const struct d3d12_gfx_pipeline_state *key = (struct d3d12_gfx_pipeline_state *)entry->key;
352
if (key->blend == state || key->zsa == state || key->rast == state)
353
remove_entry(ctx, entry);
354
}
355
}
356
357
void
358
d3d12_gfx_pipeline_state_cache_invalidate_shader(struct d3d12_context *ctx,
359
enum pipe_shader_type stage,
360
struct d3d12_shader_selector *selector)
361
{
362
struct d3d12_shader *shader = selector->first;
363
364
while (shader) {
365
hash_table_foreach(ctx->pso_cache, entry) {
366
const struct d3d12_gfx_pipeline_state *key = (struct d3d12_gfx_pipeline_state *)entry->key;
367
if (key->stages[stage] == shader)
368
remove_entry(ctx, entry);
369
}
370
shader = shader->next_variant;
371
}
372
}
373
374