nir/spirv: Add support for image_load_store

This commit is contained in:
Jason Ekstrand 2015-11-13 17:26:22 -08:00
parent 164b3ca164
commit 99494b96f0
2 changed files with 193 additions and 2 deletions

View file

@ -1689,7 +1689,6 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
case SpvOpCopyMemorySized:
case SpvOpArrayLength:
case SpvOpImageTexelPointer:
default:
unreachable("Unhandled opcode");
}
@ -1911,6 +1910,163 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
nir_builder_instr_insert(&b->nb, &instr->instr);
}
static nir_ssa_def *
get_image_coord(struct vtn_builder *b, uint32_t value)
{
struct vtn_ssa_value *coord = vtn_ssa_value(b, value);
/* The image_load_store intrinsics assume a 4-dim coordinate */
unsigned dim = glsl_get_vector_elements(coord->type);
unsigned swizzle[4];
for (unsigned i = 0; i < 4; i++)
swizzle[i] = MIN2(i, dim - 1);
return nir_swizzle(&b->nb, coord->def, swizzle, 4, false);
}
static void
vtn_handle_image(struct vtn_builder *b, SpvOp opcode,
const uint32_t *w, unsigned count)
{
/* Just get this one out of the way */
if (opcode == SpvOpImageTexelPointer) {
struct vtn_value *val =
vtn_push_value(b, w[2], vtn_value_type_image_pointer);
val->image = ralloc(b, struct vtn_image_pointer);
val->image->deref = vtn_value(b, w[3], vtn_value_type_deref)->deref;
val->image->coord = get_image_coord(b, w[4]);
val->image->sample = vtn_ssa_value(b, w[5])->def;
return;
}
struct vtn_image_pointer image;
switch (opcode) {
case SpvOpAtomicExchange:
case SpvOpAtomicCompareExchange:
case SpvOpAtomicCompareExchangeWeak:
case SpvOpAtomicIIncrement:
case SpvOpAtomicIDecrement:
case SpvOpAtomicIAdd:
case SpvOpAtomicISub:
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:
case SpvOpAtomicSMax:
case SpvOpAtomicUMax:
case SpvOpAtomicAnd:
case SpvOpAtomicOr:
case SpvOpAtomicXor:
image = *vtn_value(b, w[3], vtn_value_type_image_pointer)->image;
break;
case SpvOpImageRead:
image.deref = vtn_value(b, w[3], vtn_value_type_deref)->deref;
image.coord = get_image_coord(b, w[4]);
if (count > 5 && (w[5] & SpvImageOperandsSampleMask)) {
assert(w[5] == SpvImageOperandsSampleMask);
image.sample = vtn_ssa_value(b, w[6])->def;
} else {
image.sample = nir_ssa_undef(&b->nb, 1);
}
break;
case SpvOpImageWrite:
image.deref = vtn_value(b, w[1], vtn_value_type_deref)->deref;
image.coord = get_image_coord(b, w[2]);
/* texel = w[3] */
if (count > 4 && (w[4] & SpvImageOperandsSampleMask)) {
assert(w[4] == SpvImageOperandsSampleMask);
image.sample = vtn_ssa_value(b, w[5])->def;
} else {
image.sample = nir_ssa_undef(&b->nb, 1);
}
default:
unreachable("Invalid image opcode");
}
nir_intrinsic_op op;
switch (opcode) {
#define OP(S, N) case SpvOp##S: op = nir_intrinsic_image_##N; break;
OP(ImageRead, load)
OP(ImageWrite, store)
OP(AtomicExchange, atomic_exchange)
OP(AtomicCompareExchange, atomic_comp_swap)
OP(AtomicIIncrement, atomic_add)
OP(AtomicIDecrement, atomic_add)
OP(AtomicIAdd, atomic_add)
OP(AtomicISub, atomic_add)
OP(AtomicSMin, atomic_min)
OP(AtomicUMin, atomic_min)
OP(AtomicSMax, atomic_max)
OP(AtomicUMax, atomic_max)
OP(AtomicAnd, atomic_and)
OP(AtomicOr, atomic_or)
OP(AtomicXor, atomic_xor)
#undef OP
default:
unreachable("Invalid image opcode");
}
nir_intrinsic_instr *intrin = nir_intrinsic_instr_create(b->shader, op);
intrin->variables[0] =
nir_deref_as_var(nir_copy_deref(&intrin->instr, &image.deref->deref));
intrin->src[0] = nir_src_for_ssa(image.coord);
intrin->src[1] = nir_src_for_ssa(image.sample);
switch (opcode) {
case SpvOpImageRead:
break;
case SpvOpImageWrite:
intrin->src[2] = nir_src_for_ssa(vtn_ssa_value(b, w[3])->def);
break;
case SpvOpAtomicIIncrement:
intrin->src[2] = nir_src_for_ssa(nir_imm_int(&b->nb, 1));
break;
case SpvOpAtomicIDecrement:
intrin->src[2] = nir_src_for_ssa(nir_imm_int(&b->nb, -1));
break;
case SpvOpAtomicExchange:
case SpvOpAtomicIAdd:
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:
case SpvOpAtomicSMax:
case SpvOpAtomicUMax:
case SpvOpAtomicAnd:
case SpvOpAtomicOr:
case SpvOpAtomicXor:
intrin->src[2] = nir_src_for_ssa(vtn_ssa_value(b, w[6])->def);
break;
case SpvOpAtomicCompareExchange:
intrin->src[2] = nir_src_for_ssa(vtn_ssa_value(b, w[7])->def);
intrin->src[3] = nir_src_for_ssa(vtn_ssa_value(b, w[6])->def);
break;
case SpvOpAtomicISub:
intrin->src[2] = nir_src_for_ssa(nir_ineg(&b->nb, vtn_ssa_value(b, w[6])->def));
break;
default:
unreachable("Invalid image opcode");
}
if (opcode != SpvOpImageWrite) {
struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type;
nir_ssa_dest_init(&intrin->instr, &intrin->dest,
glsl_get_vector_elements(type->type), NULL);
val->ssa = vtn_create_ssa_value(b, type->type);
val->ssa->def = &intrin->dest.ssa;
}
nir_builder_instr_insert(&b->nb, &intrin->instr);
}
static nir_alu_instr *
create_vec(void *mem_ctx, unsigned num_components)
@ -3076,7 +3232,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
case SpvOpAccessChain:
case SpvOpInBoundsAccessChain:
case SpvOpArrayLength:
case SpvOpImageTexelPointer:
vtn_handle_variables(b, opcode, w, count);
break;
@ -3103,6 +3258,34 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
vtn_handle_texture(b, opcode, w, count);
break;
case SpvOpImageRead:
case SpvOpImageWrite:
case SpvOpImageTexelPointer:
vtn_handle_image(b, opcode, w, count);
break;
case SpvOpAtomicExchange:
case SpvOpAtomicCompareExchange:
case SpvOpAtomicCompareExchangeWeak:
case SpvOpAtomicIIncrement:
case SpvOpAtomicIDecrement:
case SpvOpAtomicIAdd:
case SpvOpAtomicISub:
case SpvOpAtomicSMin:
case SpvOpAtomicUMin:
case SpvOpAtomicSMax:
case SpvOpAtomicUMax:
case SpvOpAtomicAnd:
case SpvOpAtomicOr:
case SpvOpAtomicXor: {
struct vtn_value *pointer = vtn_untyped_value(b, w[3]);
if (pointer->value_type == vtn_value_type_image_pointer) {
vtn_handle_image(b, opcode, w, count);
} else {
assert(!"Atomic buffers not yet implemented");
}
}
case SpvOpSNegate:
case SpvOpFNegate:
case SpvOpNot:

View file

@ -45,6 +45,7 @@ enum vtn_value_type {
vtn_value_type_block,
vtn_value_type_ssa,
vtn_value_type_extension,
vtn_value_type_image_pointer,
};
struct vtn_block {
@ -120,6 +121,12 @@ struct vtn_type {
SpvBuiltIn builtin;
};
struct vtn_image_pointer {
nir_deref_var *deref;
nir_ssa_def *coord;
nir_ssa_def *sample;
};
struct vtn_value {
enum vtn_value_type value_type;
const char *name;
@ -136,6 +143,7 @@ struct vtn_value {
nir_deref_var *deref;
struct vtn_type *deref_type;
};
struct vtn_image_pointer *image;
struct vtn_function *func;
struct vtn_block *block;
struct vtn_ssa_value *ssa;