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 *
get_semantic_name(int slot,unsigned * index)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
fill_so_declaration(const struct pipe_stream_output_info * info,D3D12_SO_DECLARATION_ENTRY * entries,UINT * num_entries,UINT * strides,UINT * num_strides)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
depth_bias(struct d3d12_rasterizer_state * state,enum pipe_prim_type reduced_prim)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
topology_type(enum pipe_prim_type reduced_prim)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
d3d12_rtv_format(struct d3d12_context * ctx,unsigned index)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 *
create_gfx_pipeline_state(struct d3d12_context * ctx)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
hash_gfx_pipeline_state(const void * key)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
equals_gfx_pipeline_state(const void * a,const void * b)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 *
d3d12_get_gfx_pipeline_state(struct d3d12_context * ctx)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
d3d12_gfx_pipeline_state_cache_init(struct d3d12_context * ctx)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
delete_entry(struct hash_entry * entry)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
remove_entry(struct d3d12_context * ctx,struct hash_entry * entry)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
d3d12_gfx_pipeline_state_cache_destroy(struct d3d12_context * ctx)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
d3d12_gfx_pipeline_state_cache_invalidate(struct d3d12_context * ctx,const void * state)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
d3d12_gfx_pipeline_state_cache_invalidate_shader(struct d3d12_context * ctx,enum pipe_shader_type stage,struct d3d12_shader_selector * selector)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