diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c index 5f9ac65fbad..9dcf8ab3160 100644 --- a/src/compiler/spirv/spirv_to_nir.c +++ b/src/compiler/spirv/spirv_to_nir.c @@ -367,8 +367,10 @@ vtn_get_image(struct vtn_builder *b, uint32_t value_id, vtn_assert(type->base_type == vtn_base_type_image); if (access) *access |= spirv_to_gl_access_qualifier(b, type->access_qualifier); + nir_variable_mode mode = glsl_type_is_image(type->glsl_image) ? + nir_var_mem_image : nir_var_uniform; return nir_build_deref_cast(&b->nb, vtn_get_nir_ssa(b, value_id), - nir_var_uniform, type->glsl_image, 0); + mode, type->glsl_image, 0); } static void @@ -415,10 +417,16 @@ vtn_get_sampled_image(struct vtn_builder *b, uint32_t value_id) vtn_assert(type->base_type == vtn_base_type_sampled_image); nir_ssa_def *si_vec2 = vtn_get_nir_ssa(b, value_id); + /* Even though this is a sampled image, we can end up here with a storage + * image because OpenCL doesn't distinguish between the two. + */ + const struct glsl_type *image_type = type->image->glsl_image; + nir_variable_mode image_mode = glsl_type_is_image(image_type) ? + nir_var_mem_image : nir_var_uniform; + struct vtn_sampled_image si = { NULL, }; si.image = nir_build_deref_cast(&b->nb, nir_channel(&b->nb, si_vec2, 0), - nir_var_uniform, - type->image->glsl_image, 0); + image_mode, image_type, 0); si.sampler = nir_build_deref_cast(&b->nb, nir_channel(&b->nb, si_vec2, 1), nir_var_uniform, glsl_bare_sampler_type(), 0); @@ -942,6 +950,7 @@ vtn_type_get_nir_type(struct vtn_builder *b, struct vtn_type *type, } case vtn_base_type_image: + vtn_assert(glsl_type_is_sampler(type->glsl_image)); return type->glsl_image; case vtn_base_type_sampler: @@ -955,6 +964,12 @@ vtn_type_get_nir_type(struct vtn_builder *b, struct vtn_type *type, } } + if (mode == vtn_variable_mode_image) { + struct vtn_type *image_type = vtn_type_without_array(type); + vtn_assert(image_type->base_type == vtn_base_type_image); + return wrap_type_in_array(image_type->glsl_image, type->type); + } + /* Layout decorations are allowed but ignored in certain conditions, * to allow SPIR-V generators perform type deduplication. Discard * unnecessary ones when passing to NIR. @@ -2397,18 +2412,15 @@ vtn_mem_semantics_to_nir_var_modes(struct vtn_builder *b, SpvMemorySemanticsAtomicCounterMemoryMask); } - /* TODO: Consider adding nir_var_mem_image mode to NIR so it can be used - * for SpvMemorySemanticsImageMemoryMask. - */ - nir_variable_mode modes = 0; - if (semantics & (SpvMemorySemanticsUniformMemoryMask | - SpvMemorySemanticsImageMemoryMask)) { + if (semantics & SpvMemorySemanticsUniformMemoryMask) { modes |= nir_var_uniform | nir_var_mem_ubo | nir_var_mem_ssbo | nir_var_mem_global; } + if (semantics & SpvMemorySemanticsImageMemoryMask) + modes |= nir_var_mem_image; if (semantics & SpvMemorySemanticsWorkgroupMemoryMask) modes |= nir_var_mem_shared; if (semantics & SpvMemorySemanticsCrossWorkgroupMemoryMask) @@ -6121,22 +6133,25 @@ vtn_emit_kernel_entry_point_wrapper(struct vtn_builder *b, /* input variable */ nir_variable *in_var = rzalloc(b->nb.shader, nir_variable); - in_var->data.mode = nir_var_uniform; - in_var->data.read_only = true; - in_var->data.location = i; - if (param_type->base_type == vtn_base_type_image) { + + if (is_by_val) { + in_var->data.mode = nir_var_uniform; + in_var->type = param_type->deref->type; + } else if (param_type->base_type == vtn_base_type_image) { + in_var->data.mode = nir_var_mem_image; + in_var->type = param_type->glsl_image; in_var->data.access = spirv_to_gl_access_qualifier(b, param_type->access_qualifier); + } else if (param_type->base_type == vtn_base_type_sampler) { + in_var->data.mode = nir_var_uniform; + in_var->type = glsl_bare_sampler_type(); + } else { + in_var->data.mode = nir_var_uniform; + in_var->type = param_type->type; } - if (is_by_val) - in_var->type = param_type->deref->type; - else if (param_type->base_type == vtn_base_type_image) - in_var->type = param_type->glsl_image; - else if (param_type->base_type == vtn_base_type_sampler) - in_var->type = glsl_bare_sampler_type(); - else - in_var->type = param_type->type; + in_var->data.read_only = true; + in_var->data.location = i; nir_shader_add_variable(b->nb.shader, in_var); diff --git a/src/compiler/spirv/vtn_variables.c b/src/compiler/spirv/vtn_variables.c index d2f5118a2ee..1b9c232a5cb 100644 --- a/src/compiler/spirv/vtn_variables.c +++ b/src/compiler/spirv/vtn_variables.c @@ -597,7 +597,8 @@ _vtn_variable_load_store(struct vtn_builder *b, bool load, enum gl_access_qualifier access, struct vtn_ssa_value **inout) { - if (ptr->mode == vtn_variable_mode_uniform) { + if (ptr->mode == vtn_variable_mode_uniform || + ptr->mode == vtn_variable_mode_image) { if (ptr->type->base_type == vtn_base_type_image || ptr->type->base_type == vtn_base_type_sampler) { /* See also our handling of OpTypeSampler and OpTypeImage */ @@ -1415,7 +1416,8 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member, } else if (vtn_var->mode == vtn_variable_mode_call_data || vtn_var->mode == vtn_variable_mode_ray_payload) { /* This location is fine as-is */ - } else if (vtn_var->mode != vtn_variable_mode_uniform) { + } else if (vtn_var->mode != vtn_variable_mode_uniform && + vtn_var->mode != vtn_variable_mode_image) { vtn_warn("Location must be on input, output, uniform, sampler or " "image variable"); return; @@ -1498,7 +1500,19 @@ vtn_storage_class_to_mode(struct vtn_builder *b, nir_mode = nir_var_mem_global; break; case SpvStorageClassUniformConstant: - if (b->shader->info.stage == MESA_SHADER_KERNEL) { + /* interface_type is only NULL when OpTypeForwardPointer is used and + * OpTypeForwardPointer can only be used for struct types, not images or + * acceleration structures. + */ + if (interface_type) + interface_type = vtn_type_without_array(interface_type); + + if (interface_type && + interface_type->base_type == vtn_base_type_image && + glsl_type_is_image(interface_type->glsl_image)) { + mode = vtn_variable_mode_image; + nir_mode = nir_var_mem_image; + } else if (b->shader->info.stage == MESA_SHADER_KERNEL) { mode = vtn_variable_mode_constant; nir_mode = nir_var_mem_constant; } else { @@ -1507,7 +1521,6 @@ vtn_storage_class_to_mode(struct vtn_builder *b, * storage class. */ assert(interface_type != NULL); - interface_type = vtn_type_without_array(interface_type); if (interface_type->base_type == vtn_base_type_accel_struct) { mode = vtn_variable_mode_accel_struct; nir_mode = nir_var_uniform; @@ -1551,7 +1564,7 @@ vtn_storage_class_to_mode(struct vtn_builder *b, break; case SpvStorageClassImage: mode = vtn_variable_mode_image; - nir_mode = nir_var_mem_ubo; + nir_mode = nir_var_mem_image; break; case SpvStorageClassCallableDataKHR: mode = vtn_variable_mode_call_data; @@ -1833,7 +1846,10 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, break; case vtn_variable_mode_image: - vtn_fail("Cannot create a variable with the Image storage class"); + if (storage_class == SpvStorageClassImage) + vtn_fail("Cannot create a variable with the Image storage class"); + else + vtn_assert(storage_class == SpvStorageClassUniformConstant); break; case vtn_variable_mode_phys_ssbo: @@ -1866,6 +1882,7 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, case vtn_variable_mode_constant: case vtn_variable_mode_call_data: case vtn_variable_mode_call_data_in: + case vtn_variable_mode_image: case vtn_variable_mode_ray_payload: case vtn_variable_mode_ray_payload_in: case vtn_variable_mode_hit_attrib: @@ -2006,7 +2023,6 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, break; } - case vtn_variable_mode_image: case vtn_variable_mode_phys_ssbo: case vtn_variable_mode_generic: unreachable("Should have been caught before"); @@ -2105,6 +2121,7 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, } if (var->mode == vtn_variable_mode_uniform || + var->mode == vtn_variable_mode_image || var->mode == vtn_variable_mode_ssbo) { /* SSBOs and images are assumed to not alias in the Simple, GLSL and Vulkan memory models */ var->var->data.access |= b->mem_model != SpvMemoryModelOpenCL ? ACCESS_RESTRICT : 0; @@ -2123,6 +2140,7 @@ vtn_create_variable(struct vtn_builder *b, struct vtn_value *val, } if (var->mode == vtn_variable_mode_uniform || + var->mode == vtn_variable_mode_image || var->mode == vtn_variable_mode_ubo || var->mode == vtn_variable_mode_ssbo || var->mode == vtn_variable_mode_atomic_counter) {