1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "d3d12_pipeline_state.h"
25bf215546Sopenharmony_ci#include "d3d12_compiler.h"
26bf215546Sopenharmony_ci#include "d3d12_context.h"
27bf215546Sopenharmony_ci#include "d3d12_screen.h"
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "util/hash_table.h"
30bf215546Sopenharmony_ci#include "util/set.h"
31bf215546Sopenharmony_ci#include "util/u_memory.h"
32bf215546Sopenharmony_ci#include "util/u_prim.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include <dxguids/dxguids.h>
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_cistruct d3d12_gfx_pso_entry {
37bf215546Sopenharmony_ci   struct d3d12_gfx_pipeline_state key;
38bf215546Sopenharmony_ci   ID3D12PipelineState *pso;
39bf215546Sopenharmony_ci};
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_cistruct d3d12_compute_pso_entry {
42bf215546Sopenharmony_ci   struct d3d12_compute_pipeline_state key;
43bf215546Sopenharmony_ci   ID3D12PipelineState *pso;
44bf215546Sopenharmony_ci};
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_cistatic const char *
47bf215546Sopenharmony_ciget_semantic_name(int location, int driver_location, unsigned *index)
48bf215546Sopenharmony_ci{
49bf215546Sopenharmony_ci   *index = 0; /* Default index */
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   switch (location) {
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci   case VARYING_SLOT_POS:
54bf215546Sopenharmony_ci      return "SV_Position";
55bf215546Sopenharmony_ci
56bf215546Sopenharmony_ci    case VARYING_SLOT_FACE:
57bf215546Sopenharmony_ci      return "SV_IsFrontFace";
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   case VARYING_SLOT_CLIP_DIST1:
60bf215546Sopenharmony_ci      *index = 1;
61bf215546Sopenharmony_ci      FALLTHROUGH;
62bf215546Sopenharmony_ci   case VARYING_SLOT_CLIP_DIST0:
63bf215546Sopenharmony_ci      return "SV_ClipDistance";
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   case VARYING_SLOT_PRIMITIVE_ID:
66bf215546Sopenharmony_ci      return "SV_PrimitiveID";
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_ci   case VARYING_SLOT_VIEWPORT:
69bf215546Sopenharmony_ci      return "SV_ViewportArrayIndex";
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci   case VARYING_SLOT_LAYER:
72bf215546Sopenharmony_ci      return "SV_RenderTargetArrayIndex";
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   default: {
75bf215546Sopenharmony_ci         *index = driver_location;
76bf215546Sopenharmony_ci         return "TEXCOORD";
77bf215546Sopenharmony_ci      }
78bf215546Sopenharmony_ci   }
79bf215546Sopenharmony_ci}
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_cistatic nir_variable *
82bf215546Sopenharmony_cifind_so_variable(nir_shader *s, int location, unsigned location_frac, unsigned num_components)
83bf215546Sopenharmony_ci{
84bf215546Sopenharmony_ci   nir_foreach_variable_with_modes(var, s, nir_var_shader_out) {
85bf215546Sopenharmony_ci      if (var->data.location != location || var->data.location_frac > location_frac)
86bf215546Sopenharmony_ci         continue;
87bf215546Sopenharmony_ci      unsigned var_num_components = var->data.compact ?
88bf215546Sopenharmony_ci         glsl_get_length(var->type) : glsl_get_components(var->type);
89bf215546Sopenharmony_ci      if (var->data.location_frac <= location_frac &&
90bf215546Sopenharmony_ci          var->data.location_frac + var_num_components >= location_frac + num_components)
91bf215546Sopenharmony_ci         return var;
92bf215546Sopenharmony_ci   }
93bf215546Sopenharmony_ci   return nullptr;
94bf215546Sopenharmony_ci}
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_cistatic void
97bf215546Sopenharmony_cifill_so_declaration(const struct pipe_stream_output_info *info,
98bf215546Sopenharmony_ci                    nir_shader *last_vertex_stage,
99bf215546Sopenharmony_ci                    D3D12_SO_DECLARATION_ENTRY *entries, UINT *num_entries,
100bf215546Sopenharmony_ci                    UINT *strides, UINT *num_strides)
101bf215546Sopenharmony_ci{
102bf215546Sopenharmony_ci   int next_offset[MAX_VERTEX_STREAMS] = { 0 };
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   *num_entries = 0;
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci   for (unsigned i = 0; i < info->num_outputs; i++) {
107bf215546Sopenharmony_ci      const struct pipe_stream_output *output = &info->output[i];
108bf215546Sopenharmony_ci      const int buffer = output->output_buffer;
109bf215546Sopenharmony_ci      unsigned index;
110bf215546Sopenharmony_ci
111bf215546Sopenharmony_ci      /* Mesa doesn't store entries for gl_SkipComponents in the Outputs[]
112bf215546Sopenharmony_ci       * array.  Instead, it simply increments DstOffset for the following
113bf215546Sopenharmony_ci       * input by the number of components that should be skipped.
114bf215546Sopenharmony_ci       *
115bf215546Sopenharmony_ci       * DirectX12 requires that we create gap entries.
116bf215546Sopenharmony_ci       */
117bf215546Sopenharmony_ci      int skip_components = output->dst_offset - next_offset[buffer];
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci      if (skip_components > 0) {
120bf215546Sopenharmony_ci         entries[*num_entries].Stream = output->stream;
121bf215546Sopenharmony_ci         entries[*num_entries].SemanticName = NULL;
122bf215546Sopenharmony_ci         entries[*num_entries].ComponentCount = skip_components;
123bf215546Sopenharmony_ci         entries[*num_entries].OutputSlot = buffer;
124bf215546Sopenharmony_ci         (*num_entries)++;
125bf215546Sopenharmony_ci      }
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci      next_offset[buffer] = output->dst_offset + output->num_components;
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ci      entries[*num_entries].Stream = output->stream;
130bf215546Sopenharmony_ci      nir_variable *var = find_so_variable(last_vertex_stage,
131bf215546Sopenharmony_ci         output->register_index, output->start_component, output->num_components);
132bf215546Sopenharmony_ci      assert((var->data.stream & ~NIR_STREAM_PACKED) == output->stream);
133bf215546Sopenharmony_ci      entries[*num_entries].SemanticName = get_semantic_name(var->data.location,
134bf215546Sopenharmony_ci         var->data.driver_location, &index);
135bf215546Sopenharmony_ci      entries[*num_entries].SemanticIndex = index;
136bf215546Sopenharmony_ci      entries[*num_entries].StartComponent = output->start_component - var->data.location_frac;
137bf215546Sopenharmony_ci      entries[*num_entries].ComponentCount = output->num_components;
138bf215546Sopenharmony_ci      entries[*num_entries].OutputSlot = buffer;
139bf215546Sopenharmony_ci      (*num_entries)++;
140bf215546Sopenharmony_ci   }
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   for (unsigned i = 0; i < MAX_VERTEX_STREAMS; i++)
143bf215546Sopenharmony_ci      strides[i] = info->stride[i] * 4;
144bf215546Sopenharmony_ci   *num_strides = MAX_VERTEX_STREAMS;
145bf215546Sopenharmony_ci}
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_cistatic bool
148bf215546Sopenharmony_cidepth_bias(struct d3d12_rasterizer_state *state, enum pipe_prim_type reduced_prim)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   /* glPolygonOffset is supposed to be only enabled when rendering polygons.
151bf215546Sopenharmony_ci    * In d3d12 case, all polygons (and quads) are lowered to triangles */
152bf215546Sopenharmony_ci   if (reduced_prim != PIPE_PRIM_TRIANGLES)
153bf215546Sopenharmony_ci      return false;
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   unsigned fill_mode = state->base.cull_face == PIPE_FACE_FRONT ? state->base.fill_back
156bf215546Sopenharmony_ci                                                                 : state->base.fill_front;
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci   switch (fill_mode) {
159bf215546Sopenharmony_ci   case PIPE_POLYGON_MODE_FILL:
160bf215546Sopenharmony_ci      return state->base.offset_tri;
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_ci   case PIPE_POLYGON_MODE_LINE:
163bf215546Sopenharmony_ci      return state->base.offset_line;
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   case PIPE_POLYGON_MODE_POINT:
166bf215546Sopenharmony_ci      return state->base.offset_point;
167bf215546Sopenharmony_ci
168bf215546Sopenharmony_ci   default:
169bf215546Sopenharmony_ci      unreachable("unexpected fill mode");
170bf215546Sopenharmony_ci   }
171bf215546Sopenharmony_ci}
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_cistatic D3D12_PRIMITIVE_TOPOLOGY_TYPE
174bf215546Sopenharmony_citopology_type(enum pipe_prim_type reduced_prim)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci   switch (reduced_prim) {
177bf215546Sopenharmony_ci   case PIPE_PRIM_POINTS:
178bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT;
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   case PIPE_PRIM_LINES:
181bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE;
182bf215546Sopenharmony_ci
183bf215546Sopenharmony_ci   case PIPE_PRIM_TRIANGLES:
184bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci   case PIPE_PRIM_PATCHES:
187bf215546Sopenharmony_ci      return D3D12_PRIMITIVE_TOPOLOGY_TYPE_PATCH;
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci   default:
190bf215546Sopenharmony_ci      debug_printf("pipe_prim_type: %s\n", u_prim_name(reduced_prim));
191bf215546Sopenharmony_ci      unreachable("unexpected enum pipe_prim_type");
192bf215546Sopenharmony_ci   }
193bf215546Sopenharmony_ci}
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ciDXGI_FORMAT
196bf215546Sopenharmony_cid3d12_rtv_format(struct d3d12_context *ctx, unsigned index)
197bf215546Sopenharmony_ci{
198bf215546Sopenharmony_ci   DXGI_FORMAT fmt = ctx->gfx_pipeline_state.rtv_formats[index];
199bf215546Sopenharmony_ci
200bf215546Sopenharmony_ci   if (ctx->gfx_pipeline_state.blend->desc.RenderTarget[0].LogicOpEnable &&
201bf215546Sopenharmony_ci       !ctx->gfx_pipeline_state.has_float_rtv) {
202bf215546Sopenharmony_ci      switch (fmt) {
203bf215546Sopenharmony_ci      case DXGI_FORMAT_R8G8B8A8_SNORM:
204bf215546Sopenharmony_ci      case DXGI_FORMAT_R8G8B8A8_UNORM:
205bf215546Sopenharmony_ci      case DXGI_FORMAT_B8G8R8A8_UNORM:
206bf215546Sopenharmony_ci      case DXGI_FORMAT_B8G8R8X8_UNORM:
207bf215546Sopenharmony_ci         return DXGI_FORMAT_R8G8B8A8_UINT;
208bf215546Sopenharmony_ci      default:
209bf215546Sopenharmony_ci         unreachable("unsupported logic-op format");
210bf215546Sopenharmony_ci      }
211bf215546Sopenharmony_ci   }
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci   return fmt;
214bf215546Sopenharmony_ci}
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_cistatic ID3D12PipelineState *
217bf215546Sopenharmony_cicreate_gfx_pipeline_state(struct d3d12_context *ctx)
218bf215546Sopenharmony_ci{
219bf215546Sopenharmony_ci   struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
220bf215546Sopenharmony_ci   struct d3d12_gfx_pipeline_state *state = &ctx->gfx_pipeline_state;
221bf215546Sopenharmony_ci   enum pipe_prim_type reduced_prim = state->prim_type == PIPE_PRIM_PATCHES ?
222bf215546Sopenharmony_ci      PIPE_PRIM_PATCHES : u_reduced_prim(state->prim_type);
223bf215546Sopenharmony_ci   D3D12_SO_DECLARATION_ENTRY entries[PIPE_MAX_SO_OUTPUTS] = {};
224bf215546Sopenharmony_ci   UINT strides[PIPE_MAX_SO_OUTPUTS] = { 0 };
225bf215546Sopenharmony_ci   UINT num_entries = 0, num_strides = 0;
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci   D3D12_GRAPHICS_PIPELINE_STATE_DESC pso_desc = { 0 };
228bf215546Sopenharmony_ci   pso_desc.pRootSignature = state->root_signature;
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   nir_shader *last_vertex_stage_nir = NULL;
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   if (state->stages[PIPE_SHADER_VERTEX]) {
233bf215546Sopenharmony_ci      auto shader = state->stages[PIPE_SHADER_VERTEX];
234bf215546Sopenharmony_ci      pso_desc.VS.BytecodeLength = shader->bytecode_length;
235bf215546Sopenharmony_ci      pso_desc.VS.pShaderBytecode = shader->bytecode;
236bf215546Sopenharmony_ci      last_vertex_stage_nir = shader->nir;
237bf215546Sopenharmony_ci   }
238bf215546Sopenharmony_ci
239bf215546Sopenharmony_ci   if (state->stages[PIPE_SHADER_TESS_CTRL]) {
240bf215546Sopenharmony_ci      auto shader = state->stages[PIPE_SHADER_TESS_CTRL];
241bf215546Sopenharmony_ci      pso_desc.HS.BytecodeLength = shader->bytecode_length;
242bf215546Sopenharmony_ci      pso_desc.HS.pShaderBytecode = shader->bytecode;
243bf215546Sopenharmony_ci      last_vertex_stage_nir = shader->nir;
244bf215546Sopenharmony_ci   }
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   if (state->stages[PIPE_SHADER_TESS_EVAL]) {
247bf215546Sopenharmony_ci      auto shader = state->stages[PIPE_SHADER_TESS_EVAL];
248bf215546Sopenharmony_ci      pso_desc.DS.BytecodeLength = shader->bytecode_length;
249bf215546Sopenharmony_ci      pso_desc.DS.pShaderBytecode = shader->bytecode;
250bf215546Sopenharmony_ci      last_vertex_stage_nir = shader->nir;
251bf215546Sopenharmony_ci   }
252bf215546Sopenharmony_ci
253bf215546Sopenharmony_ci   if (state->stages[PIPE_SHADER_GEOMETRY]) {
254bf215546Sopenharmony_ci      auto shader = state->stages[PIPE_SHADER_GEOMETRY];
255bf215546Sopenharmony_ci      pso_desc.GS.BytecodeLength = shader->bytecode_length;
256bf215546Sopenharmony_ci      pso_desc.GS.pShaderBytecode = shader->bytecode;
257bf215546Sopenharmony_ci      last_vertex_stage_nir = shader->nir;
258bf215546Sopenharmony_ci   }
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   bool last_vertex_stage_writes_pos = (last_vertex_stage_nir->info.outputs_written & VARYING_BIT_POS) != 0;
261bf215546Sopenharmony_ci   if (last_vertex_stage_writes_pos && state->stages[PIPE_SHADER_FRAGMENT] &&
262bf215546Sopenharmony_ci       !state->rast->base.rasterizer_discard) {
263bf215546Sopenharmony_ci      auto shader = state->stages[PIPE_SHADER_FRAGMENT];
264bf215546Sopenharmony_ci      pso_desc.PS.BytecodeLength = shader->bytecode_length;
265bf215546Sopenharmony_ci      pso_desc.PS.pShaderBytecode = shader->bytecode;
266bf215546Sopenharmony_ci   }
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci   if (state->num_so_targets)
269bf215546Sopenharmony_ci      fill_so_declaration(&state->so_info, last_vertex_stage_nir, entries, &num_entries, strides, &num_strides);
270bf215546Sopenharmony_ci   pso_desc.StreamOutput.NumEntries = num_entries;
271bf215546Sopenharmony_ci   pso_desc.StreamOutput.pSODeclaration = entries;
272bf215546Sopenharmony_ci   pso_desc.StreamOutput.RasterizedStream = state->rast->base.rasterizer_discard ? D3D12_SO_NO_RASTERIZED_STREAM : 0;
273bf215546Sopenharmony_ci   pso_desc.StreamOutput.NumStrides = num_strides;
274bf215546Sopenharmony_ci   pso_desc.StreamOutput.pBufferStrides = strides;
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   pso_desc.BlendState = state->blend->desc;
277bf215546Sopenharmony_ci   if (state->has_float_rtv)
278bf215546Sopenharmony_ci      pso_desc.BlendState.RenderTarget[0].LogicOpEnable = FALSE;
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   pso_desc.DepthStencilState = state->zsa->desc;
281bf215546Sopenharmony_ci   pso_desc.SampleMask = state->sample_mask;
282bf215546Sopenharmony_ci   pso_desc.RasterizerState = state->rast->desc;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci   if (reduced_prim != PIPE_PRIM_TRIANGLES)
285bf215546Sopenharmony_ci      pso_desc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE;
286bf215546Sopenharmony_ci
287bf215546Sopenharmony_ci   if (depth_bias(state->rast, reduced_prim)) {
288bf215546Sopenharmony_ci      pso_desc.RasterizerState.DepthBias = state->rast->base.offset_units * 2;
289bf215546Sopenharmony_ci      pso_desc.RasterizerState.DepthBiasClamp = state->rast->base.offset_clamp;
290bf215546Sopenharmony_ci      pso_desc.RasterizerState.SlopeScaledDepthBias = state->rast->base.offset_scale;
291bf215546Sopenharmony_ci   }
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   pso_desc.InputLayout.pInputElementDescs = state->ves->elements;
294bf215546Sopenharmony_ci   pso_desc.InputLayout.NumElements = state->ves->num_elements;
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci   pso_desc.IBStripCutValue = state->ib_strip_cut_value;
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci   pso_desc.PrimitiveTopologyType = topology_type(reduced_prim);
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci   pso_desc.NumRenderTargets = state->num_cbufs;
301bf215546Sopenharmony_ci   for (unsigned i = 0; i < state->num_cbufs; ++i)
302bf215546Sopenharmony_ci      pso_desc.RTVFormats[i] = d3d12_rtv_format(ctx, i);
303bf215546Sopenharmony_ci   pso_desc.DSVFormat = state->dsv_format;
304bf215546Sopenharmony_ci
305bf215546Sopenharmony_ci   if (state->num_cbufs || state->dsv_format != DXGI_FORMAT_UNKNOWN) {
306bf215546Sopenharmony_ci      pso_desc.SampleDesc.Count = state->samples;
307bf215546Sopenharmony_ci      if (!state->zsa->desc.DepthEnable &&
308bf215546Sopenharmony_ci          !state->zsa->desc.StencilEnable &&
309bf215546Sopenharmony_ci          !state->rast->desc.MultisampleEnable &&
310bf215546Sopenharmony_ci          state->samples > 1) {
311bf215546Sopenharmony_ci         pso_desc.RasterizerState.ForcedSampleCount = 1;
312bf215546Sopenharmony_ci         pso_desc.DSVFormat = DXGI_FORMAT_UNKNOWN;
313bf215546Sopenharmony_ci      }
314bf215546Sopenharmony_ci   } else if (state->samples > 1) {
315bf215546Sopenharmony_ci      pso_desc.SampleDesc.Count = 1;
316bf215546Sopenharmony_ci      pso_desc.RasterizerState.ForcedSampleCount = state->samples;
317bf215546Sopenharmony_ci   }
318bf215546Sopenharmony_ci   pso_desc.SampleDesc.Quality = 0;
319bf215546Sopenharmony_ci
320bf215546Sopenharmony_ci   pso_desc.NodeMask = 0;
321bf215546Sopenharmony_ci
322bf215546Sopenharmony_ci   pso_desc.CachedPSO.pCachedBlob = NULL;
323bf215546Sopenharmony_ci   pso_desc.CachedPSO.CachedBlobSizeInBytes = 0;
324bf215546Sopenharmony_ci
325bf215546Sopenharmony_ci   pso_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci   ID3D12PipelineState *ret;
328bf215546Sopenharmony_ci   if (FAILED(screen->dev->CreateGraphicsPipelineState(&pso_desc,
329bf215546Sopenharmony_ci                                                       IID_PPV_ARGS(&ret)))) {
330bf215546Sopenharmony_ci      debug_printf("D3D12: CreateGraphicsPipelineState failed!\n");
331bf215546Sopenharmony_ci      return NULL;
332bf215546Sopenharmony_ci   }
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   return ret;
335bf215546Sopenharmony_ci}
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_cistatic uint32_t
338bf215546Sopenharmony_cihash_gfx_pipeline_state(const void *key)
339bf215546Sopenharmony_ci{
340bf215546Sopenharmony_ci   return _mesa_hash_data(key, sizeof(struct d3d12_gfx_pipeline_state));
341bf215546Sopenharmony_ci}
342bf215546Sopenharmony_ci
343bf215546Sopenharmony_cistatic bool
344bf215546Sopenharmony_ciequals_gfx_pipeline_state(const void *a, const void *b)
345bf215546Sopenharmony_ci{
346bf215546Sopenharmony_ci   return memcmp(a, b, sizeof(struct d3d12_gfx_pipeline_state)) == 0;
347bf215546Sopenharmony_ci}
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ciID3D12PipelineState *
350bf215546Sopenharmony_cid3d12_get_gfx_pipeline_state(struct d3d12_context *ctx)
351bf215546Sopenharmony_ci{
352bf215546Sopenharmony_ci   uint32_t hash = hash_gfx_pipeline_state(&ctx->gfx_pipeline_state);
353bf215546Sopenharmony_ci   struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->pso_cache, hash,
354bf215546Sopenharmony_ci                                                                 &ctx->gfx_pipeline_state);
355bf215546Sopenharmony_ci   if (!entry) {
356bf215546Sopenharmony_ci      struct d3d12_gfx_pso_entry *data = (struct d3d12_gfx_pso_entry *)MALLOC(sizeof(struct d3d12_gfx_pso_entry));
357bf215546Sopenharmony_ci      if (!data)
358bf215546Sopenharmony_ci         return NULL;
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_ci      data->key = ctx->gfx_pipeline_state;
361bf215546Sopenharmony_ci      data->pso = create_gfx_pipeline_state(ctx);
362bf215546Sopenharmony_ci      if (!data->pso) {
363bf215546Sopenharmony_ci         FREE(data);
364bf215546Sopenharmony_ci         return NULL;
365bf215546Sopenharmony_ci      }
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci      entry = _mesa_hash_table_insert_pre_hashed(ctx->pso_cache, hash, &data->key, data);
368bf215546Sopenharmony_ci      assert(entry);
369bf215546Sopenharmony_ci   }
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci   return ((struct d3d12_gfx_pso_entry *)(entry->data))->pso;
372bf215546Sopenharmony_ci}
373bf215546Sopenharmony_ci
374bf215546Sopenharmony_civoid
375bf215546Sopenharmony_cid3d12_gfx_pipeline_state_cache_init(struct d3d12_context *ctx)
376bf215546Sopenharmony_ci{
377bf215546Sopenharmony_ci   ctx->pso_cache = _mesa_hash_table_create(NULL, NULL, equals_gfx_pipeline_state);
378bf215546Sopenharmony_ci}
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_cistatic void
381bf215546Sopenharmony_cidelete_gfx_entry(struct hash_entry *entry)
382bf215546Sopenharmony_ci{
383bf215546Sopenharmony_ci   struct d3d12_gfx_pso_entry *data = (struct d3d12_gfx_pso_entry *)entry->data;
384bf215546Sopenharmony_ci   data->pso->Release();
385bf215546Sopenharmony_ci   FREE(data);
386bf215546Sopenharmony_ci}
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_cistatic void
389bf215546Sopenharmony_ciremove_gfx_entry(struct d3d12_context *ctx, struct hash_entry *entry)
390bf215546Sopenharmony_ci{
391bf215546Sopenharmony_ci   struct d3d12_gfx_pso_entry *data = (struct d3d12_gfx_pso_entry *)entry->data;
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   if (ctx->current_gfx_pso == data->pso)
394bf215546Sopenharmony_ci      ctx->current_gfx_pso = NULL;
395bf215546Sopenharmony_ci   _mesa_hash_table_remove(ctx->pso_cache, entry);
396bf215546Sopenharmony_ci   delete_gfx_entry(entry);
397bf215546Sopenharmony_ci}
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_civoid
400bf215546Sopenharmony_cid3d12_gfx_pipeline_state_cache_destroy(struct d3d12_context *ctx)
401bf215546Sopenharmony_ci{
402bf215546Sopenharmony_ci   _mesa_hash_table_destroy(ctx->pso_cache, delete_gfx_entry);
403bf215546Sopenharmony_ci}
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_civoid
406bf215546Sopenharmony_cid3d12_gfx_pipeline_state_cache_invalidate(struct d3d12_context *ctx, const void *state)
407bf215546Sopenharmony_ci{
408bf215546Sopenharmony_ci   hash_table_foreach(ctx->pso_cache, entry) {
409bf215546Sopenharmony_ci      const struct d3d12_gfx_pipeline_state *key = (struct d3d12_gfx_pipeline_state *)entry->key;
410bf215546Sopenharmony_ci      if (key->blend == state || key->zsa == state || key->rast == state)
411bf215546Sopenharmony_ci         remove_gfx_entry(ctx, entry);
412bf215546Sopenharmony_ci   }
413bf215546Sopenharmony_ci}
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_civoid
416bf215546Sopenharmony_cid3d12_gfx_pipeline_state_cache_invalidate_shader(struct d3d12_context *ctx,
417bf215546Sopenharmony_ci                                                 enum pipe_shader_type stage,
418bf215546Sopenharmony_ci                                                 struct d3d12_shader_selector *selector)
419bf215546Sopenharmony_ci{
420bf215546Sopenharmony_ci   struct d3d12_shader *shader = selector->first;
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_ci   while (shader) {
423bf215546Sopenharmony_ci      hash_table_foreach(ctx->pso_cache, entry) {
424bf215546Sopenharmony_ci         const struct d3d12_gfx_pipeline_state *key = (struct d3d12_gfx_pipeline_state *)entry->key;
425bf215546Sopenharmony_ci         if (key->stages[stage] == shader)
426bf215546Sopenharmony_ci            remove_gfx_entry(ctx, entry);
427bf215546Sopenharmony_ci      }
428bf215546Sopenharmony_ci      shader = shader->next_variant;
429bf215546Sopenharmony_ci   }
430bf215546Sopenharmony_ci}
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_cistatic ID3D12PipelineState *
433bf215546Sopenharmony_cicreate_compute_pipeline_state(struct d3d12_context *ctx)
434bf215546Sopenharmony_ci{
435bf215546Sopenharmony_ci   struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
436bf215546Sopenharmony_ci   struct d3d12_compute_pipeline_state *state = &ctx->compute_pipeline_state;
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   D3D12_COMPUTE_PIPELINE_STATE_DESC pso_desc = { 0 };
439bf215546Sopenharmony_ci   pso_desc.pRootSignature = state->root_signature;
440bf215546Sopenharmony_ci
441bf215546Sopenharmony_ci   if (state->stage) {
442bf215546Sopenharmony_ci      auto shader = state->stage;
443bf215546Sopenharmony_ci      pso_desc.CS.BytecodeLength = shader->bytecode_length;
444bf215546Sopenharmony_ci      pso_desc.CS.pShaderBytecode = shader->bytecode;
445bf215546Sopenharmony_ci   }
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci   pso_desc.NodeMask = 0;
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ci   pso_desc.CachedPSO.pCachedBlob = NULL;
450bf215546Sopenharmony_ci   pso_desc.CachedPSO.CachedBlobSizeInBytes = 0;
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci   pso_desc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE;
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci   ID3D12PipelineState *ret;
455bf215546Sopenharmony_ci   if (FAILED(screen->dev->CreateComputePipelineState(&pso_desc,
456bf215546Sopenharmony_ci                                                      IID_PPV_ARGS(&ret)))) {
457bf215546Sopenharmony_ci      debug_printf("D3D12: CreateComputePipelineState failed!\n");
458bf215546Sopenharmony_ci      return NULL;
459bf215546Sopenharmony_ci   }
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci   return ret;
462bf215546Sopenharmony_ci}
463bf215546Sopenharmony_ci
464bf215546Sopenharmony_cistatic uint32_t
465bf215546Sopenharmony_cihash_compute_pipeline_state(const void *key)
466bf215546Sopenharmony_ci{
467bf215546Sopenharmony_ci   return _mesa_hash_data(key, sizeof(struct d3d12_compute_pipeline_state));
468bf215546Sopenharmony_ci}
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_cistatic bool
471bf215546Sopenharmony_ciequals_compute_pipeline_state(const void *a, const void *b)
472bf215546Sopenharmony_ci{
473bf215546Sopenharmony_ci   return memcmp(a, b, sizeof(struct d3d12_compute_pipeline_state)) == 0;
474bf215546Sopenharmony_ci}
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ciID3D12PipelineState *
477bf215546Sopenharmony_cid3d12_get_compute_pipeline_state(struct d3d12_context *ctx)
478bf215546Sopenharmony_ci{
479bf215546Sopenharmony_ci   uint32_t hash = hash_compute_pipeline_state(&ctx->compute_pipeline_state);
480bf215546Sopenharmony_ci   struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(ctx->compute_pso_cache, hash,
481bf215546Sopenharmony_ci                                                                 &ctx->compute_pipeline_state);
482bf215546Sopenharmony_ci   if (!entry) {
483bf215546Sopenharmony_ci      struct d3d12_compute_pso_entry *data = (struct d3d12_compute_pso_entry *)MALLOC(sizeof(struct d3d12_compute_pso_entry));
484bf215546Sopenharmony_ci      if (!data)
485bf215546Sopenharmony_ci         return NULL;
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci      data->key = ctx->compute_pipeline_state;
488bf215546Sopenharmony_ci      data->pso = create_compute_pipeline_state(ctx);
489bf215546Sopenharmony_ci      if (!data->pso) {
490bf215546Sopenharmony_ci         FREE(data);
491bf215546Sopenharmony_ci         return NULL;
492bf215546Sopenharmony_ci      }
493bf215546Sopenharmony_ci
494bf215546Sopenharmony_ci      entry = _mesa_hash_table_insert_pre_hashed(ctx->compute_pso_cache, hash, &data->key, data);
495bf215546Sopenharmony_ci      assert(entry);
496bf215546Sopenharmony_ci   }
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_ci   return ((struct d3d12_compute_pso_entry *)(entry->data))->pso;
499bf215546Sopenharmony_ci}
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_civoid
502bf215546Sopenharmony_cid3d12_compute_pipeline_state_cache_init(struct d3d12_context *ctx)
503bf215546Sopenharmony_ci{
504bf215546Sopenharmony_ci   ctx->compute_pso_cache = _mesa_hash_table_create(NULL, NULL, equals_compute_pipeline_state);
505bf215546Sopenharmony_ci}
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_cistatic void
508bf215546Sopenharmony_cidelete_compute_entry(struct hash_entry *entry)
509bf215546Sopenharmony_ci{
510bf215546Sopenharmony_ci   struct d3d12_compute_pso_entry *data = (struct d3d12_compute_pso_entry *)entry->data;
511bf215546Sopenharmony_ci   data->pso->Release();
512bf215546Sopenharmony_ci   FREE(data);
513bf215546Sopenharmony_ci}
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_cistatic void
516bf215546Sopenharmony_ciremove_compute_entry(struct d3d12_context *ctx, struct hash_entry *entry)
517bf215546Sopenharmony_ci{
518bf215546Sopenharmony_ci   struct d3d12_compute_pso_entry *data = (struct d3d12_compute_pso_entry *)entry->data;
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ci   if (ctx->current_compute_pso == data->pso)
521bf215546Sopenharmony_ci      ctx->current_compute_pso = NULL;
522bf215546Sopenharmony_ci   _mesa_hash_table_remove(ctx->compute_pso_cache, entry);
523bf215546Sopenharmony_ci   delete_compute_entry(entry);
524bf215546Sopenharmony_ci}
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_civoid
527bf215546Sopenharmony_cid3d12_compute_pipeline_state_cache_destroy(struct d3d12_context *ctx)
528bf215546Sopenharmony_ci{
529bf215546Sopenharmony_ci   _mesa_hash_table_destroy(ctx->compute_pso_cache, delete_compute_entry);
530bf215546Sopenharmony_ci}
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_civoid
533bf215546Sopenharmony_cid3d12_compute_pipeline_state_cache_invalidate_shader(struct d3d12_context *ctx,
534bf215546Sopenharmony_ci                                                     struct d3d12_shader_selector *selector)
535bf215546Sopenharmony_ci{
536bf215546Sopenharmony_ci   struct d3d12_shader *shader = selector->first;
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci   while (shader) {
539bf215546Sopenharmony_ci      hash_table_foreach(ctx->compute_pso_cache, entry) {
540bf215546Sopenharmony_ci         const struct d3d12_compute_pipeline_state *key = (struct d3d12_compute_pipeline_state *)entry->key;
541bf215546Sopenharmony_ci         if (key->stage == shader)
542bf215546Sopenharmony_ci            remove_compute_entry(ctx, entry);
543bf215546Sopenharmony_ci      }
544bf215546Sopenharmony_ci      shader = shader->next_variant;
545bf215546Sopenharmony_ci   }
546bf215546Sopenharmony_ci}
547