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 default: 55 unreachable("unknown shader stage"); 56 } 57} 58 59static inline void 60init_constant_root_param(D3D12_ROOT_PARAMETER1 *param, 61 unsigned reg, 62 unsigned size, 63 D3D12_SHADER_VISIBILITY visibility) 64{ 65 param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; 66 param->ShaderVisibility = visibility; 67 param->Constants.RegisterSpace = 0; 68 param->Constants.ShaderRegister = reg; 69 param->Constants.Num32BitValues = size; 70} 71 72static inline void 73init_range_root_param(D3D12_ROOT_PARAMETER1 *param, 74 D3D12_DESCRIPTOR_RANGE1 *range, 75 D3D12_DESCRIPTOR_RANGE_TYPE type, 76 uint32_t num_descs, 77 D3D12_SHADER_VISIBILITY visibility, 78 uint32_t base_shader_register) 79{ 80 range->RangeType = type; 81 range->NumDescriptors = num_descs; 82 range->BaseShaderRegister = base_shader_register; 83 range->RegisterSpace = 0; 84 if (type == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) 85 range->Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; 86 else 87 range->Flags = D3D12_DESCRIPTOR_RANGE_FLAG_DESCRIPTORS_STATIC_KEEPING_BUFFER_BOUNDS_CHECKS; 88 range->OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; 89 90 param->ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; 91 param->DescriptorTable.NumDescriptorRanges = 1; 92 param->DescriptorTable.pDescriptorRanges = range; 93 param->ShaderVisibility = visibility; 94} 95 96static ID3D12RootSignature * 97create_root_signature(struct d3d12_context *ctx, struct d3d12_root_signature_key *key) 98{ 99 struct d3d12_screen *screen = d3d12_screen(ctx->base.screen); 100 D3D12_ROOT_PARAMETER1 root_params[D3D12_GFX_SHADER_STAGES * D3D12_NUM_BINDING_TYPES]; 101 D3D12_DESCRIPTOR_RANGE1 desc_ranges[D3D12_GFX_SHADER_STAGES * D3D12_NUM_BINDING_TYPES]; 102 unsigned num_params = 0; 103 104 for (unsigned i = 0; i < D3D12_GFX_SHADER_STAGES; ++i) { 105 D3D12_SHADER_VISIBILITY visibility = get_shader_visibility((enum pipe_shader_type)i); 106 107 if (key->stages[i].num_cb_bindings > 0) { 108 assert(num_params < PIPE_SHADER_TYPES * D3D12_NUM_BINDING_TYPES); 109 init_range_root_param(&root_params[num_params], 110 &desc_ranges[num_params], 111 D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 112 key->stages[i].num_cb_bindings, 113 visibility, 114 key->stages[i].has_default_ubo0 ? 0 : 1); 115 num_params++; 116 } 117 118 if (key->stages[i].end_srv_binding > 0) { 119 init_range_root_param(&root_params[num_params], 120 &desc_ranges[num_params], 121 D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 122 key->stages[i].end_srv_binding - key->stages[i].begin_srv_binding, 123 visibility, 124 key->stages[i].begin_srv_binding); 125 num_params++; 126 } 127 128 if (key->stages[i].end_srv_binding > 0) { 129 init_range_root_param(&root_params[num_params], 130 &desc_ranges[num_params], 131 D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 132 key->stages[i].end_srv_binding - key->stages[i].begin_srv_binding, 133 visibility, 134 key->stages[i].begin_srv_binding); 135 num_params++; 136 } 137 138 if (key->stages[i].state_vars_size > 0) { 139 init_constant_root_param(&root_params[num_params], 140 key->stages[i].num_cb_bindings + (key->stages[i].has_default_ubo0 ? 0 : 1), 141 key->stages[i].state_vars_size, 142 visibility); 143 num_params++; 144 } 145 } 146 147 D3D12_VERSIONED_ROOT_SIGNATURE_DESC root_sig_desc; 148 root_sig_desc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; 149 root_sig_desc.Desc_1_1.NumParameters = num_params; 150 root_sig_desc.Desc_1_1.pParameters = (num_params > 0) ? root_params : NULL; 151 root_sig_desc.Desc_1_1.NumStaticSamplers = 0; 152 root_sig_desc.Desc_1_1.pStaticSamplers = NULL; 153 root_sig_desc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_NONE; 154 155 /* TODO Only enable this flag when needed (optimization) */ 156 root_sig_desc.Desc_1_1.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; 157 158 if (key->has_stream_output) 159 root_sig_desc.Desc_1_1.Flags |= D3D12_ROOT_SIGNATURE_FLAG_ALLOW_STREAM_OUTPUT; 160 161 ComPtr<ID3DBlob> sig, error; 162 if (FAILED(ctx->D3D12SerializeVersionedRootSignature(&root_sig_desc, 163 &sig, &error))) { 164 debug_printf("D3D12SerializeRootSignature failed\n"); 165 return NULL; 166 } 167 168 ID3D12RootSignature *ret; 169 if (FAILED(screen->dev->CreateRootSignature(0, 170 sig->GetBufferPointer(), 171 sig->GetBufferSize(), 172 IID_PPV_ARGS(&ret)))) { 173 debug_printf("CreateRootSignature failed\n"); 174 return NULL; 175 } 176 return ret; 177} 178 179static void 180fill_key(struct d3d12_context *ctx, struct d3d12_root_signature_key *key) 181{ 182 memset(key, 0, sizeof(struct d3d12_root_signature_key)); 183 184 for (unsigned i = 0; i < D3D12_GFX_SHADER_STAGES; ++i) { 185 struct d3d12_shader *shader = ctx->gfx_pipeline_state.stages[i]; 186 187 if (shader) { 188 key->stages[i].num_cb_bindings = shader->num_cb_bindings; 189 key->stages[i].end_srv_binding = shader->end_srv_binding; 190 key->stages[i].begin_srv_binding = shader->begin_srv_binding; 191 key->stages[i].state_vars_size = shader->state_vars_size; 192 key->stages[i].has_default_ubo0 = shader->has_default_ubo0; 193 194 if (ctx->gfx_stages[i]->so_info.num_outputs > 0) 195 key->has_stream_output = true; 196 } 197 } 198} 199 200ID3D12RootSignature * 201d3d12_get_root_signature(struct d3d12_context *ctx) 202{ 203 struct d3d12_root_signature_key key; 204 205 fill_key(ctx, &key); 206 struct hash_entry *entry = _mesa_hash_table_search(ctx->root_signature_cache, &key); 207 if (!entry) { 208 struct d3d12_root_signature *data = 209 (struct d3d12_root_signature *)MALLOC(sizeof(struct d3d12_root_signature)); 210 if (!data) 211 return NULL; 212 213 data->key = key; 214 data->sig = create_root_signature(ctx, &key); 215 if (!data->sig) { 216 FREE(data); 217 return NULL; 218 } 219 220 entry = _mesa_hash_table_insert(ctx->root_signature_cache, &data->key, data); 221 assert(entry); 222 } 223 224 return ((struct d3d12_root_signature *)entry->data)->sig; 225} 226 227static uint32_t 228hash_root_signature_key(const void *key) 229{ 230 return _mesa_hash_data(key, sizeof(struct d3d12_root_signature_key)); 231} 232 233static bool 234equals_root_signature_key(const void *a, const void *b) 235{ 236 return memcmp(a, b, sizeof(struct d3d12_root_signature_key)) == 0; 237} 238 239void 240d3d12_root_signature_cache_init(struct d3d12_context *ctx) 241{ 242 ctx->root_signature_cache = _mesa_hash_table_create(NULL, 243 hash_root_signature_key, 244 equals_root_signature_key); 245} 246 247static void 248delete_entry(struct hash_entry *entry) 249{ 250 struct d3d12_root_signature *data = (struct d3d12_root_signature *)entry->data; 251 data->sig->Release(); 252 FREE(data); 253} 254 255void 256d3d12_root_signature_cache_destroy(struct d3d12_context *ctx) 257{ 258 _mesa_hash_table_destroy(ctx->root_signature_cache, delete_entry); 259} 260