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