diff mbox

[v2] etnaviv: Generate new sin/cos instructions on GC3000

Message ID 20170131082351.GA27316@amethyst.visucore.com (mailing list archive)
State New, archived
Headers show

Commit Message

Wladimir J. van der Laan Jan. 31, 2017, 8:23 a.m. UTC
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@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(-)

Comments

Christian Gmeiner Jan. 31, 2017, 6:23 p.m. UTC | #1
2017-01-31 9:23 GMT+01:00 Wladimir J. van der Laan <laanwj@gmail.com>:
> 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@gmail.com>

Acked-by: Christian Gmeiner <christian.gmeiner@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
>


greets
--
Christian Gmeiner, MSc

https://www.youtube.com/user/AloryOFFICIAL
https://soundcloud.com/christian-gmeiner
diff mbox

Patch

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;