[PATCH v2] etnaviv: Generate new sin/cos instructions on GC3000
Wladimir J. van der Laan
laanwj at gmail.com
Tue Jan 31 08:23:51 UTC 2017
Shaders using sin/cos instructions were not working on GC3000.
The reason for this turns out to be that these chips implement sin/cos
in a different way (but using the same opcodes):
- Need their input scaled by 1/pi instead of 2/pi.
- Output an x and y component, which need to be multiplied to
get the result.
- tex_amode needs to be set to 1.
Add a new bit to the compiler specs and generate these instructions
as necessary.
Signed-Off-By: Wladimir J. van der Laan <laanwj at gmail.com>
---
src/gallium/drivers/etnaviv/etnaviv_compiler.c | 37 +++++++++++++++++++++++++-
src/gallium/drivers/etnaviv/etnaviv_internal.h | 2 ++
src/gallium/drivers/etnaviv/etnaviv_screen.c | 2 ++
3 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/src/gallium/drivers/etnaviv/etnaviv_compiler.c b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
index 59e1452..c4519e7 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_compiler.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_compiler.c
@@ -1444,7 +1444,42 @@ static void
trans_trig(const struct instr_translater *t, struct etna_compile *c,
const struct tgsi_full_instruction *inst, struct etna_inst_src *src)
{
- if (c->specs->has_sin_cos_sqrt) {
+ if (c->specs->has_new_sin_cos) { /* Alternative SIN/COS */
+ /* On newer chips alternative SIN/COS instructions are implemented,
+ * which:
+ * - Need their input scaled by 1/pi instead of 2/pi
+ * - Output an x and y component, which need to be multiplied to
+ * get the result
+ */
+ /* TGSI lowering should deal with SCS */
+ assert(inst->Instruction.Opcode != TGSI_OPCODE_SCS);
+
+ struct etna_native_reg temp = etna_compile_get_inner_temp(c); /* only using .xyz */
+ emit_inst(c, &(struct etna_inst) {
+ .opcode = INST_OPCODE_MUL,
+ .sat = 0,
+ .dst = etna_native_to_dst(temp, INST_COMPS_Z),
+ .src[0] = src[0], /* any swizzling happens here */
+ .src[1] = alloc_imm_f32(c, 1.0f / M_PI),
+ });
+ emit_inst(c, &(struct etna_inst) {
+ .opcode = inst->Instruction.Opcode == TGSI_OPCODE_COS
+ ? INST_OPCODE_COS
+ : INST_OPCODE_SIN,
+ .sat = 0,
+ .dst = etna_native_to_dst(temp, INST_COMPS_X | INST_COMPS_Y),
+ .src[2] = etna_native_to_src(temp, SWIZZLE(Z, Z, Z, Z)),
+ .tex = { .amode=1 }, /* Unknown bit needs to be set */
+ });
+ emit_inst(c, &(struct etna_inst) {
+ .opcode = INST_OPCODE_MUL,
+ .sat = inst->Instruction.Saturate,
+ .dst = convert_dst(c, &inst->Dst[0]),
+ .src[0] = etna_native_to_src(temp, SWIZZLE(X, X, X, X)),
+ .src[1] = etna_native_to_src(temp, SWIZZLE(Y, Y, Y, Y)),
+ });
+
+ } else if (c->specs->has_sin_cos_sqrt) {
/* TGSI lowering should deal with SCS */
assert(inst->Instruction.Opcode != TGSI_OPCODE_SCS);
diff --git a/src/gallium/drivers/etnaviv/etnaviv_internal.h b/src/gallium/drivers/etnaviv/etnaviv_internal.h
index f340116..2f09d55 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_internal.h
+++ b/src/gallium/drivers/etnaviv/etnaviv_internal.h
@@ -70,6 +70,8 @@ struct etna_specs {
unsigned has_sign_floor_ceil : 1;
/* can use VS_RANGE, PS_RANGE registers*/
unsigned has_shader_range_registers : 1;
+ /* has the new sin/cos functions */
+ unsigned has_new_sin_cos : 1;
/* can use any kind of wrapping mode on npot textures */
unsigned npot_tex_any_wrap;
/* number of bits per TS tile */
diff --git a/src/gallium/drivers/etnaviv/etnaviv_screen.c b/src/gallium/drivers/etnaviv/etnaviv_screen.c
index 53a31c5..0af7078 100644
--- a/src/gallium/drivers/etnaviv/etnaviv_screen.c
+++ b/src/gallium/drivers/etnaviv/etnaviv_screen.c
@@ -620,6 +620,8 @@ etna_get_specs(struct etna_screen *screen)
screen->model >= 0x1000 || screen->model == 0x880;
screen->specs.npot_tex_any_wrap =
VIV_FEATURE(screen, chipMinorFeatures1, NON_POWER_OF_TWO);
+ screen->specs.has_new_sin_cos =
+ VIV_FEATURE(screen, chipMinorFeatures3, HAS_FAST_TRANSCENDENTALS);
if (instruction_count > 256) { /* unified instruction memory? */
screen->specs.vs_offset = 0xC000;
--
2.7.4
More information about the dri-devel
mailing list