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_root_signature.h"
25bf215546Sopenharmony_ci#include "d3d12_compiler.h"
26bf215546Sopenharmony_ci#include "d3d12_screen.h"
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include "util/u_memory.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include <dxguids/dxguids.h>
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include <wrl/client.h>
33bf215546Sopenharmony_ciusing Microsoft::WRL::ComPtr;
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_cistruct d3d12_root_signature {
36bf215546Sopenharmony_ci   struct d3d12_root_signature_key key;
37bf215546Sopenharmony_ci   ID3D12RootSignature *sig;
38bf215546Sopenharmony_ci};
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_cistatic D3D12_SHADER_VISIBILITY
41bf215546Sopenharmony_ciget_shader_visibility(enum pipe_shader_type stage)
42bf215546Sopenharmony_ci{
43bf215546Sopenharmony_ci   switch (stage) {
44bf215546Sopenharmony_ci   case PIPE_SHADER_VERTEX:
45bf215546Sopenharmony_ci      return D3D12_SHADER_VISIBILITY_VERTEX;
46bf215546Sopenharmony_ci   case PIPE_SHADER_FRAGMENT:
47bf215546Sopenharmony_ci      return D3D12_SHADER_VISIBILITY_PIXEL;
48bf215546Sopenharmony_ci   case PIPE_SHADER_GEOMETRY:
49bf215546Sopenharmony_ci      return D3D12_SHADER_VISIBILITY_GEOMETRY;
50bf215546Sopenharmony_ci   case PIPE_SHADER_TESS_CTRL:
51bf215546Sopenharmony_ci      return D3D12_SHADER_VISIBILITY_HULL;
52bf215546Sopenharmony_ci   case PIPE_SHADER_TESS_EVAL:
53bf215546Sopenharmony_ci      return D3D12_SHADER_VISIBILITY_DOMAIN;
54bf215546Sopenharmony_ci   case PIPE_SHADER_COMPUTE:
55bf215546Sopenharmony_ci      return D3D12_SHADER_VISIBILITY_ALL;
56bf215546Sopenharmony_ci   default:
57bf215546Sopenharmony_ci      unreachable("unknown shader stage");
58bf215546Sopenharmony_ci   }
59bf215546Sopenharmony_ci}
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_cistatic inline void
62bf215546Sopenharmony_ciinit_constant_root_param(D3D12_ROOT_PARAMETER1 *param,
63bf215546Sopenharmony_ci                         unsigned reg,
64bf215546Sopenharmony_ci                         unsigned size,
65bf215546Sopenharmony_ci                         D3D12_SHADER_VISIBILITY visibility)
66bf215546Sopenharmony_ci{
67bf215546Sopenharmony_ci   param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS;
68bf215546Sopenharmony_ci   param->ShaderVisibility = visibility;
69bf215546Sopenharmony_ci   param->Constants.RegisterSpace = 0;
70bf215546Sopenharmony_ci   param->Constants.ShaderRegister = reg;
71bf215546Sopenharmony_ci   param->Constants.Num32BitValues = size;
72bf215546Sopenharmony_ci}
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_cistatic inline void
75bf215546Sopenharmony_ciinit_range(D3D12_DESCRIPTOR_RANGE1 *range,
76bf215546Sopenharmony_ci           D3D12_DESCRIPTOR_RANGE_TYPE type,
77bf215546Sopenharmony_ci           uint32_t num_descs,
78bf215546Sopenharmony_ci           uint32_t base_shader_register,
79bf215546Sopenharmony_ci           uint32_t register_space,
80bf215546Sopenharmony_ci           uint32_t offset_from_start)
81bf215546Sopenharmony_ci{
82bf215546Sopenharmony_ci   range->RangeType = type;
83bf215546Sopenharmony_ci   range->NumDescriptors = num_descs;
84bf215546Sopenharmony_ci   range->BaseShaderRegister = base_shader_register;
85bf215546Sopenharmony_ci   range->RegisterSpace = register_space;
86bf215546Sopenharmony_ci   if (type == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER ||
87bf215546Sopenharmony_ci       type == D3D12_DESCRIPTOR_RANGE_TYPE_UAV)
88bf215546Sopenharmony_ci      range->Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE;
89bf215546Sopenharmony_ci   else
90bf215546Sopenharmony_ci      range->Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS;
91bf215546Sopenharmony_ci   range->OffsetInDescriptorsFromTableStart = offset_from_start;
92bf215546Sopenharmony_ci}
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_cistatic inline void
95bf215546Sopenharmony_ciinit_range_root_param(D3D12_ROOT_PARAMETER1 *param,
96bf215546Sopenharmony_ci                      D3D12_DESCRIPTOR_RANGE1 *range,
97bf215546Sopenharmony_ci                      D3D12_DESCRIPTOR_RANGE_TYPE type,
98bf215546Sopenharmony_ci                      uint32_t num_descs,
99bf215546Sopenharmony_ci                      D3D12_SHADER_VISIBILITY visibility,
100bf215546Sopenharmony_ci                      uint32_t base_shader_register,
101bf215546Sopenharmony_ci                      uint32_t register_space)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci   init_range(range, type, num_descs, base_shader_register, register_space, D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND);
104bf215546Sopenharmony_ci   param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE;
105bf215546Sopenharmony_ci   param->DescriptorTable.NumDescriptorRanges = 1;
106bf215546Sopenharmony_ci   param->DescriptorTable.pDescriptorRanges = range;
107bf215546Sopenharmony_ci   param->ShaderVisibility = visibility;
108bf215546Sopenharmony_ci}
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_cistatic ID3D12RootSignature *
111bf215546Sopenharmony_cicreate_root_signature(struct d3d12_context *ctx, struct d3d12_root_signature_key *key)
112bf215546Sopenharmony_ci{
113bf215546Sopenharmony_ci   struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
114bf215546Sopenharmony_ci   D3D12_ROOT_PARAMETER1 root_params[D3D12_GFX_SHADER_STAGES * D3D12_NUM_BINDING_TYPES];
115bf215546Sopenharmony_ci   D3D12_DESCRIPTOR_RANGE1 desc_ranges[D3D12_GFX_SHADER_STAGES * (D3D12_NUM_BINDING_TYPES + 1)];
116bf215546Sopenharmony_ci   unsigned num_params = 0;
117bf215546Sopenharmony_ci   unsigned num_ranges = 0;
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_ci   unsigned count = key->compute ? 1 : D3D12_GFX_SHADER_STAGES;
120bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; ++i) {
121bf215546Sopenharmony_ci      unsigned stage = key->compute ? PIPE_SHADER_COMPUTE : i;
122bf215546Sopenharmony_ci      D3D12_SHADER_VISIBILITY visibility = get_shader_visibility((enum pipe_shader_type)stage);
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci      if (key->stages[i].num_cb_bindings > 0) {
125bf215546Sopenharmony_ci         init_range_root_param(&root_params[num_params++],
126bf215546Sopenharmony_ci                               &desc_ranges[num_ranges++],
127bf215546Sopenharmony_ci                               D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
128bf215546Sopenharmony_ci                               key->stages[i].num_cb_bindings,
129bf215546Sopenharmony_ci                               visibility,
130bf215546Sopenharmony_ci                               key->stages[i].has_default_ubo0 ? 0 : 1,
131bf215546Sopenharmony_ci                               0);
132bf215546Sopenharmony_ci      }
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci      if (key->stages[i].end_srv_binding > 0) {
135bf215546Sopenharmony_ci         init_range_root_param(&root_params[num_params++],
136bf215546Sopenharmony_ci                               &desc_ranges[num_ranges++],
137bf215546Sopenharmony_ci                               D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
138bf215546Sopenharmony_ci                               key->stages[i].end_srv_binding - key->stages[i].begin_srv_binding,
139bf215546Sopenharmony_ci                               visibility,
140bf215546Sopenharmony_ci                               key->stages[i].begin_srv_binding,
141bf215546Sopenharmony_ci                               0);
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci         init_range_root_param(&root_params[num_params++],
144bf215546Sopenharmony_ci                               &desc_ranges[num_ranges++],
145bf215546Sopenharmony_ci                               D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER,
146bf215546Sopenharmony_ci                               key->stages[i].end_srv_binding - key->stages[i].begin_srv_binding,
147bf215546Sopenharmony_ci                               visibility,
148bf215546Sopenharmony_ci                               key->stages[i].begin_srv_binding,
149bf215546Sopenharmony_ci                               0);
150bf215546Sopenharmony_ci      }
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci      if (key->stages[i].num_ssbos > 0) {
153bf215546Sopenharmony_ci         init_range_root_param(&root_params[num_params],
154bf215546Sopenharmony_ci                               &desc_ranges[num_ranges++],
155bf215546Sopenharmony_ci                               D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
156bf215546Sopenharmony_ci                               key->stages[i].num_ssbos,
157bf215546Sopenharmony_ci                               visibility,
158bf215546Sopenharmony_ci                               0,
159bf215546Sopenharmony_ci                               0);
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci         /* To work around a WARP bug, bind these descriptors a second time in descriptor
162bf215546Sopenharmony_ci          * space 2. Space 0 will be used for static indexing, while space 2 will be used
163bf215546Sopenharmony_ci          * for dynamic indexing. Space 0 will be individual SSBOs in the DXIL shader, while
164bf215546Sopenharmony_ci          * space 2 will be a single array.
165bf215546Sopenharmony_ci          */
166bf215546Sopenharmony_ci         root_params[num_params++].DescriptorTable.NumDescriptorRanges++;
167bf215546Sopenharmony_ci         init_range(&desc_ranges[num_ranges++],
168bf215546Sopenharmony_ci                    D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
169bf215546Sopenharmony_ci                    key->stages[i].num_ssbos,
170bf215546Sopenharmony_ci                    0,
171bf215546Sopenharmony_ci                    2,
172bf215546Sopenharmony_ci                    0);
173bf215546Sopenharmony_ci      }
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci      if (key->stages[i].num_images > 0) {
176bf215546Sopenharmony_ci         init_range_root_param(&root_params[num_params++],
177bf215546Sopenharmony_ci                               &desc_ranges[num_ranges++],
178bf215546Sopenharmony_ci                               D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
179bf215546Sopenharmony_ci                               key->stages[i].num_images,
180bf215546Sopenharmony_ci                               visibility,
181bf215546Sopenharmony_ci                               0,
182bf215546Sopenharmony_ci                               1);
183bf215546Sopenharmony_ci      }
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci      if (key->stages[i].state_vars_size > 0) {
186bf215546Sopenharmony_ci         init_constant_root_param(&root_params[num_params++],
187bf215546Sopenharmony_ci            key->stages[i].num_cb_bindings + (key->stages[i].has_default_ubo0 ? 0 : 1),
188bf215546Sopenharmony_ci            key->stages[i].state_vars_size,
189bf215546Sopenharmony_ci            visibility);
190bf215546Sopenharmony_ci      }
191bf215546Sopenharmony_ci      assert(num_params < PIPE_SHADER_TYPES * D3D12_NUM_BINDING_TYPES);
192bf215546Sopenharmony_ci      assert(num_ranges < PIPE_SHADER_TYPES * (D3D12_NUM_BINDING_TYPES + 1));
193bf215546Sopenharmony_ci   }
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci   D3D12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc;
196bf215546Sopenharmony_ci   root_sig_desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1;
197bf215546Sopenharmony_ci   root_sig_desc.Desc_1_1.NumParameters = num_params;
198bf215546Sopenharmony_ci   root_sig_desc.Desc_1_1.pParameters = (num_params > 0) ? root_params : NULL;
199bf215546Sopenharmony_ci   root_sig_desc.Desc_1_1.NumStaticSamplers = 0;
200bf215546Sopenharmony_ci   root_sig_desc.Desc_1_1.pStaticSamplers = NULL;
201bf215546Sopenharmony_ci   root_sig_desc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE;
202bf215546Sopenharmony_ci
203bf215546Sopenharmony_ci   /* TODO Only enable this flag when needed (optimization) */
204bf215546Sopenharmony_ci   if (!key->compute)
205bf215546Sopenharmony_ci      root_sig_desc.Desc_1_1.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT;
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci   if (key->has_stream_output)
208bf215546Sopenharmony_ci      root_sig_desc.Desc_1_1.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT;
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   ComPtr<ID3DBlob> sig, error;
211bf215546Sopenharmony_ci   if (FAILED(ctx->D3D12SerializeVersionedRootSignature(&root_sig_desc,
212bf215546Sopenharmony_ci                                                        &sig, &error))) {
213bf215546Sopenharmony_ci      debug_printf("D3D12SerializeRootSignature failed\n");
214bf215546Sopenharmony_ci      return NULL;
215bf215546Sopenharmony_ci   }
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_ci   ID3D12RootSignature *ret;
218bf215546Sopenharmony_ci   if (FAILED(screen->dev->CreateRootSignature(0,
219bf215546Sopenharmony_ci                                               sig->GetBufferPointer(),
220bf215546Sopenharmony_ci                                               sig->GetBufferSize(),
221bf215546Sopenharmony_ci                                               IID_PPV_ARGS(&ret)))) {
222bf215546Sopenharmony_ci      debug_printf("CreateRootSignature failed\n");
223bf215546Sopenharmony_ci      return NULL;
224bf215546Sopenharmony_ci   }
225bf215546Sopenharmony_ci   return ret;
226bf215546Sopenharmony_ci}
227bf215546Sopenharmony_ci
228bf215546Sopenharmony_cistatic void
229bf215546Sopenharmony_cifill_key(struct d3d12_context *ctx, struct d3d12_root_signature_key *key, bool compute)
230bf215546Sopenharmony_ci{
231bf215546Sopenharmony_ci   memset(key, 0, sizeof(struct d3d12_root_signature_key));
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   key->compute = compute;
234bf215546Sopenharmony_ci   unsigned count = compute ? 1 : D3D12_GFX_SHADER_STAGES;
235bf215546Sopenharmony_ci   for (unsigned i = 0; i < count; ++i) {
236bf215546Sopenharmony_ci      struct d3d12_shader *shader = compute ?
237bf215546Sopenharmony_ci         ctx->compute_pipeline_state.stage :
238bf215546Sopenharmony_ci         ctx->gfx_pipeline_state.stages[i];
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci      if (shader) {
241bf215546Sopenharmony_ci         key->stages[i].num_cb_bindings = shader->num_cb_bindings;
242bf215546Sopenharmony_ci         key->stages[i].end_srv_binding = shader->end_srv_binding;
243bf215546Sopenharmony_ci         key->stages[i].begin_srv_binding = shader->begin_srv_binding;
244bf215546Sopenharmony_ci         key->stages[i].state_vars_size = shader->state_vars_size;
245bf215546Sopenharmony_ci         key->stages[i].has_default_ubo0 = shader->has_default_ubo0;
246bf215546Sopenharmony_ci         key->stages[i].num_ssbos = shader->nir->info.num_ssbos;
247bf215546Sopenharmony_ci         key->stages[i].num_images = shader->nir->info.num_images;
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_ci         if (!compute && ctx->gfx_stages[i]->so_info.num_outputs > 0)
250bf215546Sopenharmony_ci            key->has_stream_output = true;
251bf215546Sopenharmony_ci      }
252bf215546Sopenharmony_ci   }
253bf215546Sopenharmony_ci}
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ciID3D12RootSignature *
256bf215546Sopenharmony_cid3d12_get_root_signature(struct d3d12_context *ctx, bool compute)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci   struct d3d12_root_signature_key key;
259bf215546Sopenharmony_ci
260bf215546Sopenharmony_ci   fill_key(ctx, &key, compute);
261bf215546Sopenharmony_ci   struct hash_entry *entry = _mesa_hash_table_search(ctx->root_signature_cache, &key);
262bf215546Sopenharmony_ci   if (!entry) {
263bf215546Sopenharmony_ci      struct d3d12_root_signature *data =
264bf215546Sopenharmony_ci         (struct d3d12_root_signature *)MALLOC(sizeof(struct d3d12_root_signature));
265bf215546Sopenharmony_ci      if (!data)
266bf215546Sopenharmony_ci         return NULL;
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci      data->key = key;
269bf215546Sopenharmony_ci      data->sig = create_root_signature(ctx, &key);
270bf215546Sopenharmony_ci      if (!data->sig) {
271bf215546Sopenharmony_ci         FREE(data);
272bf215546Sopenharmony_ci         return NULL;
273bf215546Sopenharmony_ci      }
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci      entry = _mesa_hash_table_insert(ctx->root_signature_cache, &data->key, data);
276bf215546Sopenharmony_ci      assert(entry);
277bf215546Sopenharmony_ci   }
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_ci   return ((struct d3d12_root_signature *)entry->data)->sig;
280bf215546Sopenharmony_ci}
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_cistatic uint32_t
283bf215546Sopenharmony_cihash_root_signature_key(const void *key)
284bf215546Sopenharmony_ci{
285bf215546Sopenharmony_ci   return _mesa_hash_data(key, sizeof(struct d3d12_root_signature_key));
286bf215546Sopenharmony_ci}
287bf215546Sopenharmony_ci
288bf215546Sopenharmony_cistatic bool
289bf215546Sopenharmony_ciequals_root_signature_key(const void *a, const void *b)
290bf215546Sopenharmony_ci{
291bf215546Sopenharmony_ci   return memcmp(a, b, sizeof(struct d3d12_root_signature_key)) == 0;
292bf215546Sopenharmony_ci}
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_civoid
295bf215546Sopenharmony_cid3d12_root_signature_cache_init(struct d3d12_context *ctx)
296bf215546Sopenharmony_ci{
297bf215546Sopenharmony_ci   ctx->root_signature_cache = _mesa_hash_table_create(NULL,
298bf215546Sopenharmony_ci                                                       hash_root_signature_key,
299bf215546Sopenharmony_ci                                                       equals_root_signature_key);
300bf215546Sopenharmony_ci}
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_cistatic void
303bf215546Sopenharmony_cidelete_entry(struct hash_entry *entry)
304bf215546Sopenharmony_ci{
305bf215546Sopenharmony_ci   struct d3d12_root_signature *data = (struct d3d12_root_signature *)entry->data;
306bf215546Sopenharmony_ci   data->sig->Release();
307bf215546Sopenharmony_ci   FREE(data);
308bf215546Sopenharmony_ci}
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_civoid
311bf215546Sopenharmony_cid3d12_root_signature_cache_destroy(struct d3d12_context *ctx)
312bf215546Sopenharmony_ci{
313bf215546Sopenharmony_ci   _mesa_hash_table_destroy(ctx->root_signature_cache, delete_entry);
314bf215546Sopenharmony_ci}
315