1138
need_custom_buffer_descriptor(struct dzn_device *device, const struct dzn_buffer_desc *info)
1140
if (info->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
1141
info->type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) {
1142
uint64_t upper_bound = info->range == VK_WHOLE_SIZE ? info->buffer->size :
1143
info->offset + info->range;
1144
/* The buffer's default CBV only addresses the first 64KiB. If this view needs a higher
1145
* upper bound, then we need a custom descriptor. */
1146
if (upper_bound > D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 4 * sizeof(float)) {
1147
/* It's invalid to use WHOLE_SIZE if it would address more than 64KiB, so if they're
1148
* using it on a buffer that large, it better have an offset. */
1149
assert(info->range != VK_WHOLE_SIZE || info->offset > 0);
1153
/* Addressing the whole buffer, no custom descriptor needed. */
1154
if (info->range == VK_WHOLE_SIZE ||
1155
info->offset + info->range == info->buffer->size)
1157
/* We need proper out-of-bounds behavior, we need a descriptor with the right size. */
1158
if (device->vk.enabled_features.robustBufferAccess ||
1159
device->vk.enabled_features.robustBufferAccess2)
1161
/* We can just apply an offset in the shader */
1166
1135
dzn_bindless_descriptor_set_write_buffer_desc(struct dzn_device *device,
1167
struct dxil_spirv_bindless_entry *map,
1136
volatile struct dxil_spirv_bindless_entry *map,
1168
1137
uint32_t desc_offset,
1169
1138
const struct dzn_buffer_desc *info)
1171
if (!need_custom_buffer_descriptor(device, info)) {
1172
switch (info->type) {
1173
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1174
map[desc_offset].buffer_idx = info->buffer->cbv_bindless_slot;
1176
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1177
map[desc_offset].buffer_idx = info->buffer->uav_bindless_slot;
1180
unreachable("Unexpected descriptor type");
1140
dzn_buffer_get_bindless_buffer_descriptor(device, info, &map[desc_offset]);
1144
need_custom_buffer_descriptor(struct dzn_device *device, const struct dzn_buffer_desc *info,
1145
struct dzn_buffer_desc *out_desc)
1148
uint32_t upper_bound_default_descriptor;
1149
uint32_t size_align, offset_align;
1150
/* Canonicalize descriptor types for hash/compare, and get size/align info */
1151
switch (info->type) {
1152
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
1153
out_desc->type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1155
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1156
upper_bound_default_descriptor =
1157
MIN2(D3D12_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * sizeof(float) * 4, info->buffer->size);
1158
size_align = offset_align = D3D12_CONSTANT_BUFFER_DATA_PLACEMENT_ALIGNMENT;
1160
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
1161
out_desc->type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
1164
upper_bound_default_descriptor = MIN2(UINT32_MAX, info->buffer->size);
1165
offset_align = D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT;
1170
uint64_t upper_bound = info->range == VK_WHOLE_SIZE ?
1171
info->buffer->size :
1172
info->offset + info->range;
1173
/* Addressing the whole buffer, no custom descriptor needed. */
1174
if (upper_bound == upper_bound_default_descriptor)
1177
out_desc->range = ALIGN_POT(upper_bound, size_align);
1178
if (out_desc->range <= upper_bound_default_descriptor) {
1179
/* Use a larger descriptor with the hope that we'll be more likely
1180
* to be able to re-use it. The shader is already doing the offset
1181
* add, so there's not really a cost to putting a nonzero value there. */
1182
out_desc->offset = 0;
1184
/* At least align-down the base offset to ensure that's a valid view to create */
1185
out_desc->offset = (out_desc->offset / offset_align) * offset_align;
1186
out_desc->range -= out_desc->offset;
1192
hash_buffer_desc(const void *data)
1194
const struct dzn_buffer_desc *bdesc = data;
1195
/* Avoid any potential padding in the struct */
1196
uint32_t type_hash = _mesa_hash_data(&bdesc->type, sizeof(bdesc->type));
1197
return _mesa_hash_data_with_seed(&bdesc->range, sizeof(bdesc->range) * 2, type_hash);
1201
compare_buffer_desc(const void *_a, const void *_b)
1203
const struct dzn_buffer_desc *a = _a, *b = _b;
1204
assert(a->buffer == b->buffer);
1205
/* Avoid any potential padding in the struct */
1206
return a->type == b->type &&
1207
a->range == b->range &&
1208
a->offset == b->offset;
1212
handle_custom_descriptor_cache(struct dzn_device *device,
1213
const struct dzn_buffer_desc *stack_desc)
1215
/* Buffer lock is held */
1217
/* Initialize hash map */
1218
if (!stack_desc->buffer->custom_views)
1219
stack_desc->buffer->custom_views = _mesa_hash_table_create(NULL, hash_buffer_desc, compare_buffer_desc);
1221
if (!stack_desc->buffer->custom_views)
1224
uint32_t hash = hash_buffer_desc(stack_desc);
1225
struct hash_entry *entry = _mesa_hash_table_search_pre_hashed(stack_desc->buffer->custom_views, hash, stack_desc);
1227
return (int)(intptr_t)entry->data;
1229
int slot = dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1233
struct dzn_buffer_desc *key = malloc(sizeof(*stack_desc));
1235
dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, slot);
1240
entry = _mesa_hash_table_insert_pre_hashed(stack_desc->buffer->custom_views, hash, key, (void *)(intptr_t)slot);
1243
dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, slot);
1247
dzn_descriptor_heap_write_buffer_desc(device, &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap,
1248
slot, key->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, key);
1253
dzn_buffer_get_bindless_buffer_descriptor(struct dzn_device *device,
1254
const struct dzn_buffer_desc *bdesc,
1255
volatile struct dxil_spirv_bindless_entry *out)
1258
uint32_t offset = bdesc->offset;
1259
switch (bdesc->type) {
1260
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
1261
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
1262
slot = bdesc->buffer->cbv_bindless_slot;
1264
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
1265
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
1266
slot = bdesc->buffer->uav_bindless_slot;
1269
unreachable("Unexpected descriptor type");
1272
struct dzn_buffer_desc local_desc;
1273
if (need_custom_buffer_descriptor(device, bdesc, &local_desc)) {
1274
mtx_lock(&bdesc->buffer->bindless_view_lock);
1276
int new_slot = handle_custom_descriptor_cache(device, &local_desc);
1277
if (new_slot >= 0) {
1279
offset = bdesc->offset - local_desc.offset;
1182
map[desc_offset].buffer_offset = info->offset;
1183
if (*info->bindless_descriptor_slot >= 0)
1184
dzn_device_descriptor_heap_free_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, *info->bindless_descriptor_slot);
1186
if (*info->bindless_descriptor_slot < 0)
1187
*info->bindless_descriptor_slot =
1188
dzn_device_descriptor_heap_alloc_slot(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
1189
uint32_t offset = (info->offset / D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT) * D3D12_RAW_UAV_SRV_BYTE_ALIGNMENT;
1191
struct dzn_buffer_desc local_info = *info;
1192
local_info.offset = offset;
1195
dzn_descriptor_heap_write_buffer_desc(device, &device->device_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV].heap,
1196
*info->bindless_descriptor_slot, info->type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, info);
1197
map[desc_offset].buffer_idx = *info->bindless_descriptor_slot;
1198
map[desc_offset].buffer_offset = info->offset - offset;
1281
/* In the case of cache failure, just use the base view and try
1282
* shader-based offsetting, it'll probably still work in most cases. */
1284
mtx_unlock(&bdesc->buffer->bindless_view_lock);
1287
out->buffer_idx = slot;
1288
out->buffer_offset = offset;