vtn_mode_to_address_format(b, vtn_variable_mode_function));
const struct vtn_type *sampled_type = vtn_get_type(b, w[2]);
- vtn_fail_if(sampled_type->base_type != vtn_base_type_scalar ||
- glsl_get_bit_size(sampled_type->type) != 32,
- "Sampled type of OpTypeImage must be a 32-bit scalar");
+ if (b->shader->info.stage == MESA_SHADER_KERNEL) {
+ vtn_fail_if(sampled_type->base_type != vtn_base_type_void,
+ "Sampled type of OpTypeImage must be void for kernels");
+ } else {
+ vtn_fail_if(sampled_type->base_type != vtn_base_type_scalar ||
+ glsl_get_bit_size(sampled_type->type) != 32,
+ "Sampled type of OpTypeImage must be a 32-bit scalar");
+ }
enum glsl_sampler_dim dim;
switch ((SpvDim)w[3]) {
if (count > 9)
val->type->access_qualifier = w[9];
+ else if (b->shader->info.stage == MESA_SHADER_KERNEL)
+ /* Per the CL C spec: If no qualifier is provided, read_only is assumed. */
+ val->type->access_qualifier = SpvAccessQualifierReadOnly;
else
val->type->access_qualifier = SpvAccessQualifierReadWrite;
} else if (sampled == 2) {
val->type->glsl_image = glsl_image_type(dim, is_array,
sampled_base_type);
+ } else if (b->shader->info.stage == MESA_SHADER_KERNEL) {
+ val->type->glsl_image = glsl_image_type(dim, is_array,
+ GLSL_TYPE_VOID);
} else {
vtn_fail("We need to know if the image will be sampled");
}
val->constant = vtn_null_constant(b, val->type);
break;
- case SpvOpConstantSampler:
- vtn_fail("OpConstantSampler requires Kernel Capability");
- break;
-
default:
vtn_fail_with_opcode("Unhandled opcode", opcode);
}
vtn_foreach_decoration(b, val, handle_workgroup_size_decoration_cb, NULL);
}
-SpvMemorySemanticsMask
-vtn_storage_class_to_memory_semantics(SpvStorageClass sc)
-{
- switch (sc) {
- case SpvStorageClassStorageBuffer:
- case SpvStorageClassPhysicalStorageBuffer:
- return SpvMemorySemanticsUniformMemoryMask;
- case SpvStorageClassWorkgroup:
- return SpvMemorySemanticsWorkgroupMemoryMask;
- default:
- return SpvMemorySemanticsMaskNone;
- }
-}
-
static void
vtn_split_barrier_semantics(struct vtn_builder *b,
SpvMemorySemanticsMask semantics,
SpvMemorySemanticsOutputMemoryMask);
const SpvMemorySemanticsMask other_semantics =
- semantics & ~(order_semantics | av_vis_semantics | storage_semantics);
+ semantics & ~(order_semantics | av_vis_semantics | storage_semantics |
+ SpvMemorySemanticsVolatileMask);
if (other_semantics)
vtn_warn("Ignoring unhandled memory semantics: %u\n", other_semantics);
if (is_array && texop != nir_texop_lod)
coord_components++;
- coord = vtn_get_nir_ssa(b, w[idx++]);
+ struct vtn_ssa_value *coord_val = vtn_ssa_value(b, w[idx++]);
+ coord = coord_val->def;
p->src = nir_src_for_ssa(nir_channels(&b->nb, coord,
(1 << coord_components) - 1));
+
+ /* OpenCL allows integer sampling coordinates */
+ if (glsl_type_is_integer(coord_val->type) &&
+ opcode == SpvOpImageSampleExplicitLod) {
+ vtn_fail_if(b->shader->info.stage != MESA_SHADER_KERNEL,
+ "Unless the Kernel capability is being used, the coordinate parameter "
+ "OpImageSampleExplicitLod must be floating point.");
+
+ p->src = nir_src_for_ssa(nir_i2f32(&b->nb, p->src.ssa));
+ }
+
p->src_type = nir_tex_src_coord;
p++;
break;
if (sampler && (access & ACCESS_NON_UNIFORM))
instr->sampler_non_uniform = true;
- /* for non-query ops, get dest_type from sampler type */
+ /* for non-query ops, get dest_type from SPIR-V return type */
if (dest_type == nir_type_invalid) {
- switch (glsl_get_sampler_result_type(image->type)) {
+ /* the return type should match the image type, unless the image type is
+ * VOID (CL image), in which case the return type dictates the sampler
+ */
+ enum glsl_base_type sampler_base =
+ glsl_get_sampler_result_type(image->type);
+ enum glsl_base_type ret_base = glsl_get_base_type(ret_type->type);
+ vtn_fail_if(sampler_base != ret_base && sampler_base != GLSL_TYPE_VOID,
+ "SPIR-V return type mismatches image type. This is only valid "
+ "for untyped images (OpenCL).");
+ switch (ret_base) {
case GLSL_TYPE_FLOAT: dest_type = nir_type_float; break;
case GLSL_TYPE_INT: dest_type = nir_type_int; break;
case GLSL_TYPE_UINT: dest_type = nir_type_uint; break;
access |= ACCESS_COHERENT;
break;
+ case SpvOpImageQuerySizeLod:
+ res_val = vtn_untyped_value(b, w[3]);
+ image.image = vtn_get_image(b, w[3]);
+ image.coord = NULL;
+ image.sample = NULL;
+ image.lod = vtn_ssa_value(b, w[4])->def;
+ break;
+
case SpvOpImageQuerySize:
res_val = vtn_untyped_value(b, w[3]);
image.image = vtn_get_image(b, w[3]);
image.lod = NULL;
break;
+ case SpvOpImageQueryFormat:
+ case SpvOpImageQueryOrder:
+ res_val = vtn_untyped_value(b, w[3]);
+ image.image = vtn_get_image(b, w[3]);
+ image.coord = NULL;
+ image.sample = NULL;
+ image.lod = NULL;
+ break;
+
case SpvOpImageRead: {
res_val = vtn_untyped_value(b, w[3]);
image.image = vtn_get_image(b, w[3]);
vtn_fail_with_opcode("Invalid image opcode", opcode);
}
+ if (semantics & SpvMemorySemanticsVolatileMask)
+ access |= ACCESS_VOLATILE;
+
nir_intrinsic_op op;
switch (opcode) {
#define OP(S, N) case SpvOp##S: op = nir_intrinsic_image_deref_##N; break;
OP(ImageQuerySize, size)
+ OP(ImageQuerySizeLod, size)
OP(ImageRead, load)
OP(ImageWrite, store)
OP(AtomicLoad, load)
OP(AtomicOr, atomic_or)
OP(AtomicXor, atomic_xor)
OP(AtomicFAddEXT, atomic_fadd)
+ OP(ImageQueryFormat, format)
+ OP(ImageQueryOrder, order)
#undef OP
default:
vtn_fail_with_opcode("Invalid image opcode", opcode);
intrin->src[0] = nir_src_for_ssa(&image.image->dest.ssa);
- /* ImageQuerySize doesn't take any extra parameters */
- if (opcode != SpvOpImageQuerySize) {
+ switch (opcode) {
+ case SpvOpImageQuerySize:
+ case SpvOpImageQuerySizeLod:
+ case SpvOpImageQueryFormat:
+ case SpvOpImageQueryOrder:
+ break;
+ default:
/* The image coordinate is always 4 components but we may not have that
* many. Swizzle to compensate.
*/
intrin->src[1] = nir_src_for_ssa(expand_to_vec4(&b->nb, image.coord));
intrin->src[2] = nir_src_for_ssa(image.sample);
+ break;
}
/* The Vulkan spec says:
nir_intrinsic_set_access(intrin, access);
switch (opcode) {
- case SpvOpAtomicLoad:
+ case SpvOpImageQueryFormat:
+ case SpvOpImageQueryOrder:
+ /* No additional sources */
+ break;
case SpvOpImageQuerySize:
+ intrin->src[1] = nir_src_for_ssa(nir_imm_int(&b->nb, 0));
+ break;
+ case SpvOpImageQuerySizeLod:
+ intrin->src[1] = nir_src_for_ssa(image.lod);
+ break;
+ case SpvOpAtomicLoad:
case SpvOpImageRead:
- if (opcode == SpvOpImageRead || opcode == SpvOpAtomicLoad) {
- /* Only OpImageRead can support a lod parameter if
- * SPV_AMD_shader_image_load_store_lod is used but the current NIR
- * intrinsics definition for atomics requires us to set it for
- * OpAtomicLoad.
- */
- intrin->src[3] = nir_src_for_ssa(image.lod);
- }
+ /* Only OpImageRead can support a lod parameter if
+ * SPV_AMD_shader_image_load_store_lod is used but the current NIR
+ * intrinsics definition for atomics requires us to set it for
+ * OpAtomicLoad.
+ */
+ intrin->src[3] = nir_src_for_ssa(image.lod);
break;
case SpvOpAtomicStore:
case SpvOpImageWrite: {
const uint32_t value_id = opcode == SpvOpAtomicStore ? w[4] : w[3];
- nir_ssa_def *value = vtn_get_nir_ssa(b, value_id);
+ struct vtn_ssa_value *value = vtn_ssa_value(b, value_id);
/* nir_intrinsic_image_deref_store always takes a vec4 value */
assert(op == nir_intrinsic_image_deref_store);
intrin->num_components = 4;
- intrin->src[3] = nir_src_for_ssa(expand_to_vec4(&b->nb, value));
+ intrin->src[3] = nir_src_for_ssa(expand_to_vec4(&b->nb, value->def));
/* Only OpImageWrite can support a lod parameter if
* SPV_AMD_shader_image_load_store_lod is used but the current NIR
* intrinsics definition for atomics requires us to set it for
* OpAtomicStore.
*/
intrin->src[4] = nir_src_for_ssa(image.lod);
+
+ if (opcode == SpvOpImageWrite)
+ nir_intrinsic_set_type(intrin, nir_get_nir_type_for_glsl_type(value->type));
break;
}
result = nir_channels(&b->nb, result, (1 << dest_components) - 1);
vtn_push_nir_ssa(b, w[2], result);
+
+ if (opcode == SpvOpImageRead)
+ nir_intrinsic_set_type(intrin, nir_get_nir_type_for_glsl_type(type->type));
} else {
nir_builder_instr_insert(&b->nb, &intrin->instr);
}
SpvScope scope = SpvScopeInvocation;
SpvMemorySemanticsMask semantics = 0;
+ enum gl_access_qualifier access = 0;
switch (opcode) {
case SpvOpAtomicLoad:
vtn_fail_with_opcode("Invalid SPIR-V atomic", opcode);
}
+ if (semantics & SpvMemorySemanticsVolatileMask)
+ access |= ACCESS_VOLATILE;
+
/* uniform as "atomic counter uniform" */
if (ptr->mode == vtn_variable_mode_atomic_counter) {
nir_deref_instr *deref = vtn_pointer_to_deref(b, ptr);
nir_intrinsic_op op = get_ssbo_nir_atomic_op(b, opcode);
atomic = nir_intrinsic_instr_create(b->nb.shader, op);
- nir_intrinsic_set_access(atomic, ACCESS_COHERENT);
+ nir_intrinsic_set_access(atomic, access | ACCESS_COHERENT);
int src = 0;
switch (opcode) {
atomic->src[0] = nir_src_for_ssa(&deref->dest.ssa);
if (ptr->mode != vtn_variable_mode_workgroup)
- nir_intrinsic_set_access(atomic, ACCESS_COHERENT);
+ access |= ACCESS_COHERENT;
+
+ nir_intrinsic_set_access(atomic, access);
switch (opcode) {
case SpvOpAtomicLoad:
/* Atomic ordering operations will implicitly apply to the atomic operation
* storage class, so include that too.
*/
- semantics |= vtn_storage_class_to_memory_semantics(ptr->ptr_type->storage_class);
+ semantics |= vtn_mode_to_memory_semantics(ptr->mode);
SpvMemorySemanticsMask before_semantics;
SpvMemorySemanticsMask after_semantics;
break;
case SpvCapabilityImageBasic:
+ spv_check_supported(kernel_image, cap);
+ break;
+
+ case SpvCapabilityLiteralSampler:
+ spv_check_supported(literal_sampler, cap);
+ break;
+
case SpvCapabilityImageReadWrite:
case SpvCapabilityImageMipmap:
case SpvCapabilityPipes:
case SpvCapabilityDeviceEnqueue:
- case SpvCapabilityLiteralSampler:
case SpvCapabilityGenericPointer:
vtn_warn("Unsupported OpenCL-style SPIR-V capability: %s",
spirv_capability_to_string(cap));
"AddressingModelPhysical32 only supported for kernels");
b->shader->info.cs.ptr_size = 32;
b->physical_ptrs = true;
- b->options->shared_addr_format = nir_address_format_32bit_global;
- b->options->global_addr_format = nir_address_format_32bit_global;
- b->options->temp_addr_format = nir_address_format_32bit_global;
+ assert(nir_address_format_bit_size(b->options->global_addr_format) == 32);
+ assert(nir_address_format_num_components(b->options->global_addr_format) == 1);
+ assert(nir_address_format_bit_size(b->options->shared_addr_format) == 32);
+ assert(nir_address_format_num_components(b->options->shared_addr_format) == 1);
+ if (!b->options->constant_as_global) {
+ assert(nir_address_format_bit_size(b->options->ubo_addr_format) == 32);
+ assert(nir_address_format_num_components(b->options->ubo_addr_format) == 1);
+ }
break;
case SpvAddressingModelPhysical64:
vtn_fail_if(b->shader->info.stage != MESA_SHADER_KERNEL,
"AddressingModelPhysical64 only supported for kernels");
b->shader->info.cs.ptr_size = 64;
b->physical_ptrs = true;
- b->options->shared_addr_format = nir_address_format_64bit_global;
- b->options->global_addr_format = nir_address_format_64bit_global;
- b->options->temp_addr_format = nir_address_format_64bit_global;
+ assert(nir_address_format_bit_size(b->options->global_addr_format) == 64);
+ assert(nir_address_format_num_components(b->options->global_addr_format) == 1);
+ assert(nir_address_format_bit_size(b->options->shared_addr_format) == 64);
+ assert(nir_address_format_num_components(b->options->shared_addr_format) == 1);
+ if (!b->options->constant_as_global) {
+ assert(nir_address_format_bit_size(b->options->ubo_addr_format) == 64);
+ assert(nir_address_format_num_components(b->options->ubo_addr_format) == 1);
+ }
break;
case SpvAddressingModelLogical:
vtn_fail_if(b->shader->info.stage == MESA_SHADER_KERNEL,
case SpvOpConstantFalse:
case SpvOpConstant:
case SpvOpConstantComposite:
- case SpvOpConstantSampler:
case SpvOpConstantNull:
case SpvOpSpecConstantTrue:
case SpvOpSpecConstantFalse:
case SpvOpUndef:
case SpvOpVariable:
+ case SpvOpConstantSampler:
vtn_handle_variables(b, opcode, w, count);
break;
case SpvOpImageFetch:
case SpvOpImageGather:
case SpvOpImageDrefGather:
- case SpvOpImageQuerySizeLod:
case SpvOpImageQueryLod:
case SpvOpImageQueryLevels:
case SpvOpImageQuerySamples:
case SpvOpImageRead:
case SpvOpImageWrite:
case SpvOpImageTexelPointer:
+ case SpvOpImageQueryFormat:
+ case SpvOpImageQueryOrder:
vtn_handle_image(b, opcode, w, count);
break;
+ case SpvOpImageQuerySizeLod:
case SpvOpImageQuerySize: {
struct vtn_type *image_type = vtn_get_value_type(b, w[3]);
vtn_assert(image_type->base_type == vtn_base_type_image);
/* input variable */
nir_variable *in_var = rzalloc(b->nb.shader, nir_variable);
- in_var->data.mode = nir_var_shader_in;
+ 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) {
+ in_var->data.access = 0;
+ if (param_type->access_qualifier & SpvAccessQualifierReadOnly)
+ in_var->data.access |= ACCESS_NON_WRITEABLE;
+ if (param_type->access_qualifier & SpvAccessQualifierWriteOnly)
+ in_var->data.access |= ACCESS_NON_READABLE;
+ }
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;
nir_copy_var(&b->nb, copy_var, in_var);
call->params[i] =
nir_src_for_ssa(&nir_build_deref_var(&b->nb, copy_var)->dest.ssa);
+ } else if (param_type->base_type == vtn_base_type_image ||
+ param_type->base_type == vtn_base_type_sampler) {
+ /* Don't load the var, just pass a deref of it */
+ call->params[i] = nir_src_for_ssa(&nir_build_deref_var(&b->nb, in_var)->dest.ssa);
} else {
call->params[i] = nir_src_for_ssa(nir_load_var(&b->nb, in_var));
}
return NULL;
}
+ /* Ensure a sane address mode is being used for function temps */
+ assert(nir_address_format_bit_size(b->options->temp_addr_format) == nir_get_ptr_bitsize(b->shader));
+ assert(nir_address_format_num_components(b->options->temp_addr_format) == 1);
+
/* Set shader info defaults */
if (stage == MESA_SHADER_GEOMETRY)
b->shader->info.gs.invocations = 1;
if (entry_point->num_params && b->shader->info.stage == MESA_SHADER_KERNEL)
entry_point = vtn_emit_kernel_entry_point_wrapper(b, entry_point);
+ /* structurize the CFG */
+ nir_lower_goto_ifs(b->shader);
+
entry_point->is_entrypoint = true;
/* When multiple shader stages exist in the same SPIR-V module, we