summaryrefslogtreecommitdiffstats
path: root/src/gallium/auxiliary/tgsi/tgsi_exec.c
diff options
context:
space:
mode:
authorDave Airlie <[email protected]>2016-03-22 07:53:48 +1000
committerDave Airlie <[email protected]>2016-03-31 09:14:05 +1000
commit22d1296013825a4dce84e6f579581202a18767c7 (patch)
tree4518a8dccc2dc96f9bf61f0ca628d2b9a143f838 /src/gallium/auxiliary/tgsi/tgsi_exec.c
parent493eab76792307d066489bc1d88798f14a5df31d (diff)
tgsi: add support for image operations to tgsi_exec. (v2.1)
This adds support for load/store/atomic operations on images along with image tracking support. v2: add RESQ support. (Ilia) v2.1: constify interface (Brian) split get_image_coord_dim (Brian) Reviewed-by: Brian Paul <[email protected]> Signed-off-by: Dave Airlie <[email protected]>
Diffstat (limited to 'src/gallium/auxiliary/tgsi/tgsi_exec.c')
-rw-r--r--src/gallium/auxiliary/tgsi/tgsi_exec.c273
1 files changed, 272 insertions, 1 deletions
diff --git a/src/gallium/auxiliary/tgsi/tgsi_exec.c b/src/gallium/auxiliary/tgsi/tgsi_exec.c
index fa1c9161bcc..53d5937b2df 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_exec.c
+++ b/src/gallium/auxiliary/tgsi/tgsi_exec.c
@@ -853,7 +853,8 @@ void
tgsi_exec_machine_bind_shader(
struct tgsi_exec_machine *mach,
const struct tgsi_token *tokens,
- struct tgsi_sampler *sampler)
+ struct tgsi_sampler *sampler,
+ struct tgsi_image *image)
{
uint k;
struct tgsi_parse_context parse;
@@ -871,6 +872,7 @@ tgsi_exec_machine_bind_shader(
mach->Tokens = tokens;
mach->Sampler = sampler;
+ mach->Image = image;
if (!tokens) {
/* unbind and free all */
@@ -3706,6 +3708,247 @@ exec_dfracexp(struct tgsi_exec_machine *mach,
}
}
+static int
+get_image_coord_dim(unsigned tgsi_tex)
+{
+ int dim;
+ switch (tgsi_tex) {
+ case TGSI_TEXTURE_BUFFER:
+ case TGSI_TEXTURE_1D:
+ dim = 1;
+ break;
+ case TGSI_TEXTURE_2D:
+ case TGSI_TEXTURE_RECT:
+ case TGSI_TEXTURE_1D_ARRAY:
+ case TGSI_TEXTURE_2D_MSAA:
+ dim = 2;
+ break;
+ case TGSI_TEXTURE_3D:
+ case TGSI_TEXTURE_CUBE:
+ case TGSI_TEXTURE_2D_ARRAY:
+ case TGSI_TEXTURE_2D_ARRAY_MSAA:
+ case TGSI_TEXTURE_CUBE_ARRAY:
+ dim = 3;
+ break;
+ default:
+ assert(!"unknown texture target");
+ dim = 0;
+ break;
+ }
+
+ return dim;
+}
+
+static int
+get_image_coord_sample(unsigned tgsi_tex)
+{
+ int sample = 0;
+ switch (tgsi_tex) {
+ case TGSI_TEXTURE_2D_MSAA:
+ sample = 3;
+ break;
+ case TGSI_TEXTURE_2D_ARRAY_MSAA:
+ sample = 4;
+ break;
+ default:
+ break;
+ }
+ return sample;
+}
+
+static void
+exec_load(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_exec_channel r[4], sample_r;
+ uint unit;
+ int sample;
+ int i, j;
+ int dim;
+ uint chan;
+ float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
+ struct tgsi_image_params params;
+ int kilmask = mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0];
+
+ unit = fetch_sampler_unit(mach, inst, 0);
+ dim = get_image_coord_dim(inst->Memory.Texture);
+ sample = get_image_coord_sample(inst->Memory.Texture);
+ assert(dim <= 3);
+
+ params.execmask = mach->ExecMask & mach->NonHelperMask & ~kilmask;
+ params.unit = unit;
+ params.tgsi_tex_instr = inst->Memory.Texture;
+ params.format = inst->Memory.Format;
+
+ for (i = 0; i < dim; i++) {
+ IFETCH(&r[i], 1, TGSI_CHAN_X + i);
+ }
+
+ if (sample)
+ IFETCH(&sample_r, 1, TGSI_CHAN_X + sample);
+
+ mach->Image->load(mach->Image, &params,
+ r[0].i, r[1].i, r[2].i, sample_r.i,
+ rgba);
+ for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+ r[0].f[j] = rgba[0][j];
+ r[1].f[j] = rgba[1][j];
+ r[2].f[j] = rgba[2][j];
+ r[3].f[j] = rgba[3][j];
+ }
+ for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
+ if (inst->Dst[0].Register.WriteMask & (1 << chan)) {
+ store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT);
+ }
+ }
+}
+
+static void
+exec_store(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_exec_channel r[3], sample_r;
+ union tgsi_exec_channel value[4];
+ float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
+ struct tgsi_image_params params;
+ int dim;
+ int sample;
+ int i, j;
+ uint unit;
+ int kilmask = mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0];
+ unit = inst->Dst[0].Register.Index;
+ dim = get_image_coord_dim(inst->Memory.Texture);
+ sample = get_image_coord_sample(inst->Memory.Texture);
+ assert(dim <= 3);
+
+ params.execmask = mach->ExecMask & mach->NonHelperMask & ~kilmask;
+ params.unit = unit;
+ params.tgsi_tex_instr = inst->Memory.Texture;
+ params.format = inst->Memory.Format;
+
+ for (i = 0; i < dim; i++) {
+ IFETCH(&r[i], 0, TGSI_CHAN_X + i);
+ }
+
+ for (i = 0; i < 4; i++) {
+ FETCH(&value[i], 1, TGSI_CHAN_X + i);
+ }
+ if (sample)
+ IFETCH(&sample_r, 0, TGSI_CHAN_X + sample);
+
+ for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+ rgba[0][j] = value[0].f[j];
+ rgba[1][j] = value[1].f[j];
+ rgba[2][j] = value[2].f[j];
+ rgba[3][j] = value[3].f[j];
+ }
+
+ mach->Image->store(mach->Image, &params,
+ r[0].i, r[1].i, r[2].i, sample_r.i,
+ rgba);
+}
+
+static void
+exec_atomop(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ union tgsi_exec_channel r[3], sample_r;
+ union tgsi_exec_channel value[4], value2[4];
+ float rgba[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
+ float rgba2[TGSI_NUM_CHANNELS][TGSI_QUAD_SIZE];
+ struct tgsi_image_params params;
+ int dim;
+ int sample;
+ int i, j;
+ uint unit, chan;
+ int kilmask = mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0];
+ unit = fetch_sampler_unit(mach, inst, 0);
+ dim = get_image_coord_dim(inst->Memory.Texture);
+ sample = get_image_coord_sample(inst->Memory.Texture);
+ assert(dim <= 3);
+
+ params.execmask = mach->ExecMask & mach->NonHelperMask & ~kilmask;
+ params.unit = unit;
+ params.tgsi_tex_instr = inst->Memory.Texture;
+ params.format = inst->Memory.Format;
+
+ for (i = 0; i < dim; i++) {
+ IFETCH(&r[i], 1, TGSI_CHAN_X + i);
+ }
+
+ for (i = 0; i < 4; i++) {
+ FETCH(&value[i], 2, TGSI_CHAN_X + i);
+ if (inst->Instruction.Opcode == TGSI_OPCODE_ATOMCAS)
+ FETCH(&value2[i], 3, TGSI_CHAN_X + i);
+ }
+ if (sample)
+ IFETCH(&sample_r, 1, TGSI_CHAN_X + sample);
+
+ for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+ rgba[0][j] = value[0].f[j];
+ rgba[1][j] = value[1].f[j];
+ rgba[2][j] = value[2].f[j];
+ rgba[3][j] = value[3].f[j];
+ }
+ if (inst->Instruction.Opcode == TGSI_OPCODE_ATOMCAS) {
+ for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+ rgba2[0][j] = value2[0].f[j];
+ rgba2[1][j] = value2[1].f[j];
+ rgba2[2][j] = value2[2].f[j];
+ rgba2[3][j] = value2[3].f[j];
+ }
+ }
+
+ mach->Image->op(mach->Image, &params, inst->Instruction.Opcode,
+ r[0].i, r[1].i, r[2].i, sample_r.i,
+ rgba, rgba2);
+
+ for (j = 0; j < TGSI_QUAD_SIZE; j++) {
+ r[0].f[j] = rgba[0][j];
+ r[1].f[j] = rgba[1][j];
+ r[2].f[j] = rgba[2][j];
+ r[3].f[j] = rgba[3][j];
+ }
+ for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
+ if (inst->Dst[0].Register.WriteMask & (1 << chan)) {
+ store_dest(mach, &r[chan], &inst->Dst[0], inst, chan, TGSI_EXEC_DATA_FLOAT);
+ }
+ }
+}
+
+static void
+exec_resq(struct tgsi_exec_machine *mach,
+ const struct tgsi_full_instruction *inst)
+{
+ int result[4];
+ union tgsi_exec_channel r[4];
+ uint unit;
+ int i, chan, j;
+ struct tgsi_image_params params;
+ int kilmask = mach->Temps[TEMP_KILMASK_I].xyzw[TEMP_KILMASK_C].u[0];
+
+ unit = fetch_sampler_unit(mach, inst, 0);
+
+ params.execmask = mach->ExecMask & mach->NonHelperMask & ~kilmask;
+ params.unit = unit;
+ params.tgsi_tex_instr = inst->Memory.Texture;
+ params.format = inst->Memory.Format;
+
+ mach->Image->get_dims(mach->Image, &params, result);
+
+ for (i = 0; i < TGSI_QUAD_SIZE; i++) {
+ for (j = 0; j < 4; j++) {
+ r[j].i[i] = result[j];
+ }
+ }
+
+ for (chan = 0; chan < TGSI_NUM_CHANNELS; chan++) {
+ if (inst->Dst[0].Register.WriteMask & (1 << chan)) {
+ store_dest(mach, &r[chan], &inst->Dst[0], inst, chan,
+ TGSI_EXEC_DATA_INT);
+ }
+ }
+}
static void
micro_i2f(union tgsi_exec_channel *dst,
@@ -5172,6 +5415,34 @@ exec_instruction(
case TGSI_OPCODE_D2U:
exec_d2u(mach, inst);
break;
+
+ case TGSI_OPCODE_LOAD:
+ exec_load(mach, inst);
+ break;
+
+ case TGSI_OPCODE_STORE:
+ exec_store(mach, inst);
+ break;
+
+ case TGSI_OPCODE_ATOMUADD:
+ case TGSI_OPCODE_ATOMXCHG:
+ case TGSI_OPCODE_ATOMCAS:
+ case TGSI_OPCODE_ATOMAND:
+ case TGSI_OPCODE_ATOMOR:
+ case TGSI_OPCODE_ATOMXOR:
+ case TGSI_OPCODE_ATOMUMIN:
+ case TGSI_OPCODE_ATOMUMAX:
+ case TGSI_OPCODE_ATOMIMIN:
+ case TGSI_OPCODE_ATOMIMAX:
+ exec_atomop(mach, inst);
+ break;
+
+ case TGSI_OPCODE_RESQ:
+ exec_resq(mach, inst);
+ break;
+ case TGSI_OPCODE_BARRIER:
+ case TGSI_OPCODE_MEMBAR:
+ break;
default:
assert( 0 );
}