From 50d7e97c1d67b38157654824b16599fce83eb407 Mon Sep 17 00:00:00 2001 From: Jesse Natalie Date: Tue, 13 Apr 2021 09:56:05 -0700 Subject: [PATCH] microsoft/compiler: Better support UBO/SSBO references to descriptors Previously UBOs only supported static indices, and SSBOs only supported dynamic indices. UBO support for descriptors was added as an alternative to static indices, but the logic for detecting descriptors to SSBOs couldn't just differentiate on constants vs not. Add a helper which can differentiate cleanly across the board and handle pre-created handles from descriptors, or static/dynamic raw indices. Reviewed-by: Enrico Galli Part-of: --- src/microsoft/compiler/nir_to_dxil.c | 156 +++++++++++++++------------ 1 file changed, 90 insertions(+), 66 deletions(-) diff --git a/src/microsoft/compiler/nir_to_dxil.c b/src/microsoft/compiler/nir_to_dxil.c index b7404423204..58dc11ecc48 100644 --- a/src/microsoft/compiler/nir_to_dxil.c +++ b/src/microsoft/compiler/nir_to_dxil.c @@ -749,6 +749,43 @@ add_resource(struct ntd_context *ctx, enum dxil_resource_type type, ctx->num_resources++; } +static unsigned +get_resource_id(struct ntd_context *ctx, enum dxil_resource_class class, + unsigned space, unsigned binding) +{ + unsigned offset = 0; + unsigned count = 0; + switch (class) { + case DXIL_RESOURCE_CLASS_UAV: + offset = ctx->num_srv_arrays + ctx->num_sampler_arrays + ctx->num_cbv_arrays; + count = ctx->num_uav_arrays; + break; + case DXIL_RESOURCE_CLASS_SRV: + offset = ctx->num_sampler_arrays + ctx->num_cbv_arrays; + count = ctx->num_srv_arrays; + break; + case DXIL_RESOURCE_CLASS_SAMPLER: + offset = ctx->num_cbv_arrays; + count = ctx->num_sampler_arrays; + break; + case DXIL_RESOURCE_CLASS_CBV: + offset = 0; + count = ctx->num_cbv_arrays; + break; + } + assert(offset + count <= ctx->num_resources); + for (unsigned i = offset; i < offset + count; ++i) { + if (ctx->resources[i].space == space && + ctx->resources[i].lower_bound <= binding && + ctx->resources[i].upper_bound >= binding) { + return i - offset; + } + } + + unreachable("Resource access for undeclared range"); + return 0; +} + static bool emit_srv(struct ntd_context *ctx, nir_variable *var, unsigned binding, unsigned count) { @@ -2282,26 +2319,57 @@ emit_gep_for_index(struct ntd_context *ctx, const nir_variable *var, return dxil_emit_gep_inbounds(&ctx->mod, ops, ARRAY_SIZE(ops)); } +static const struct dxil_value * +get_ubo_ssbo_handle(struct ntd_context *ctx, nir_src *src, enum dxil_resource_class class, unsigned base_binding) +{ + assume(class == DXIL_RESOURCE_CLASS_CBV || class == DXIL_RESOURCE_CLASS_UAV); + + /* This source might be one of: + * 1. Constant resource index - just look it up in precomputed handle arrays + * If it's null in that array, create a handle, and store the result + * 2. A handle from load_vulkan_descriptor - just get the stored SSA value + * 3. Dynamic resource index - create a handle for it here + */ + assert(src->ssa->num_components == 1 && src->ssa->bit_size == 32); + nir_const_value *const_block_index = nir_src_as_const_value(*src); + const struct dxil_value **handle_entry = NULL; + if (const_block_index) { + if (class == DXIL_RESOURCE_CLASS_CBV) + handle_entry = &ctx->cbv_handles[const_block_index->u32]; + else + handle_entry = &ctx->uav_handles[const_block_index->u32]; + } + + if (handle_entry && *handle_entry) + return *handle_entry; + + const struct dxil_value *value = get_src_ssa(ctx, src->ssa, 0); + if (ctx->opts->vulkan_environment) { + return value; + } + + const struct dxil_value *handle = emit_createhandle_call(ctx, class, + get_resource_id(ctx, class, 0, base_binding), value, !const_block_index); + if (handle_entry) + *handle_entry = handle; + + return handle; +} + static bool emit_load_ssbo(struct ntd_context *ctx, nir_intrinsic_instr *intr) { const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); - const struct dxil_value *buffer = - get_src(ctx, &intr->src[0], 0, nir_type_uint); + + const struct dxil_value *handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_UAV, 0); const struct dxil_value *offset = get_src(ctx, &intr->src[1], 0, nir_type_uint); - if (!int32_undef || !buffer || !offset) + if (!int32_undef || !handle || !offset) return false; assert(nir_src_bit_size(intr->src[0]) == 32); assert(nir_intrinsic_dest_components(intr) <= 4); - const struct dxil_value *handle = - emit_createhandle_call(ctx, DXIL_RESOURCE_CLASS_UAV, 0, buffer, - nir_src_is_const(intr->src[0])); - if (!handle) - return false; - const struct dxil_value *coord[2] = { offset, int32_undef @@ -2324,17 +2392,10 @@ emit_load_ssbo(struct ntd_context *ctx, nir_intrinsic_instr *intr) static bool emit_store_ssbo(struct ntd_context *ctx, nir_intrinsic_instr *intr) { - const struct dxil_value *buffer = - get_src(ctx, &intr->src[1], 0, nir_type_uint); + const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[1], DXIL_RESOURCE_CLASS_UAV, 0); const struct dxil_value *offset = get_src(ctx, &intr->src[2], 0, nir_type_uint); - if (!buffer || !offset) - return false; - - const struct dxil_value *handle = - emit_createhandle_call(ctx, DXIL_RESOURCE_CLASS_UAV, 0, buffer, - nir_src_is_const(intr->src[1])); - if (!handle) + if (!handle || !offset) return false; assert(nir_src_bit_size(intr->src[0]) == 32); @@ -2374,17 +2435,10 @@ emit_store_ssbo_masked(struct ntd_context *ctx, nir_intrinsic_instr *intr) get_src(ctx, &intr->src[0], 0, nir_type_uint); const struct dxil_value *mask = get_src(ctx, &intr->src[1], 0, nir_type_uint); - const struct dxil_value *buffer = - get_src(ctx, &intr->src[2], 0, nir_type_uint); + const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[2], DXIL_RESOURCE_CLASS_UAV, 0); const struct dxil_value *offset = get_src(ctx, &intr->src[3], 0, nir_type_uint); - if (!value || !mask || !buffer || !offset) - return false; - - const struct dxil_value *handle = - emit_createhandle_call(ctx, DXIL_RESOURCE_CLASS_UAV, 0, buffer, - nir_src_is_const(intr->src[2])); - if (!handle) + if (!value || !mask || !handle || !offset) return false; const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); @@ -2482,16 +2536,10 @@ emit_store_scratch(struct ntd_context *ctx, nir_intrinsic_instr *intr) static bool emit_load_ubo(struct ntd_context *ctx, nir_intrinsic_instr *intr) { - const struct dxil_value* handle = NULL; - nir_const_value* const_block_index = nir_src_as_const_value(intr->src[0]); - if (const_block_index) { - handle = ctx->cbv_handles[const_block_index->u32]; - } else { - assert(nir_src_num_components(intr->src[0]) == 1); - handle = get_src_ssa(ctx, intr->src[0].ssa, 0); - } + const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_CBV, 0); + if (!handle) + return false; - assert(handle); const struct dxil_value *offset; nir_const_value *const_offset = nir_src_as_const_value(intr->src[1]); if (const_offset) { @@ -2521,17 +2569,7 @@ emit_load_ubo_dxil(struct ntd_context *ctx, nir_intrinsic_instr *intr) assert(nir_dest_num_components(intr->dest) <= 4); assert(nir_dest_bit_size(intr->dest) == 32); - nir_const_value *index = nir_src_as_const_value(intr->src[0]); - - const struct dxil_value* handle = NULL; - if (index) { - assert(index && index->u32 < ARRAY_SIZE(ctx->cbv_handles)); - handle = ctx->cbv_handles[index->u32]; - } else { - assert(nir_src_num_components(intr->src[0]) == 1); - handle = get_src_ssa(ctx, intr->src[0].ssa, 0); - } - + const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_CBV, 0); const struct dxil_value *offset = get_src(ctx, &intr->src[1], 0, nir_type_uint); @@ -3065,20 +3103,13 @@ static bool emit_ssbo_atomic(struct ntd_context *ctx, nir_intrinsic_instr *intr, enum dxil_atomic_op op, nir_alu_type type) { - const struct dxil_value *buffer = - get_src(ctx, &intr->src[0], 0, nir_type_uint); + const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_UAV, 0); const struct dxil_value *offset = get_src(ctx, &intr->src[1], 0, nir_type_uint); const struct dxil_value *value = get_src(ctx, &intr->src[2], 0, type); - if (!value || !buffer || !offset) - return false; - - const struct dxil_value *handle = - emit_createhandle_call(ctx, DXIL_RESOURCE_CLASS_UAV, 0, buffer, - nir_src_is_const(intr->src[0])); - if (!handle) + if (!value || !handle || !offset) return false; const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); @@ -3102,8 +3133,7 @@ emit_ssbo_atomic(struct ntd_context *ctx, nir_intrinsic_instr *intr, static bool emit_ssbo_atomic_comp_swap(struct ntd_context *ctx, nir_intrinsic_instr *intr) { - const struct dxil_value *buffer = - get_src(ctx, &intr->src[0], 0, nir_type_uint); + const struct dxil_value* handle = get_ubo_ssbo_handle(ctx, &intr->src[0], DXIL_RESOURCE_CLASS_UAV, 0); const struct dxil_value *offset = get_src(ctx, &intr->src[1], 0, nir_type_uint); const struct dxil_value *cmpval = @@ -3111,13 +3141,7 @@ emit_ssbo_atomic_comp_swap(struct ntd_context *ctx, nir_intrinsic_instr *intr) const struct dxil_value *newval = get_src(ctx, &intr->src[3], 0, nir_type_int); - if (!cmpval || !newval || !buffer || !offset) - return false; - - const struct dxil_value *handle = - emit_createhandle_call(ctx, DXIL_RESOURCE_CLASS_UAV, 0, buffer, - nir_src_is_const(intr->src[0])); - if (!handle) + if (!cmpval || !newval || !handle || !offset) return false; const struct dxil_value *int32_undef = get_int32_undef(&ctx->mod); @@ -3269,7 +3293,7 @@ emit_load_vulkan_descriptor(struct ntd_context *ctx, nir_intrinsic_instr *intr) handle = *handle_entry; if (!handle || !const_index) { handle = emit_createhandle_call(ctx, resource_class, - 0, + get_resource_id(ctx, resource_class, 0, binding), get_src(ctx, &intr->src[0], 0, nir_type_uint32), false); if (const_index) *handle_entry = handle;