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