Mesa (main): virgl: Add workarounds for virglrenderer input/sv signedness bugs.

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Mon Feb 14 23:34:34 UTC 2022


Module: Mesa
Branch: main
Commit: bc912bace1cf8cd03793c5ae34bd5a2afd015019
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=bc912bace1cf8cd03793c5ae34bd5a2afd015019

Author: Emma Anholt <emma at anholt.net>
Date:   Wed Sep 15 17:00:11 2021 -0700

virgl: Add workarounds for virglrenderer input/sv signedness bugs.

GLSL-to-TGSI would emit some MOVs that made things OK, but NTT
successfully copy-propagates the inputs and sysvals more, triggering bugs
in virglrenderer when the signedness of the input is different from that
of the ALU op.

Reviewed-by: Gert Wollny <gert.wollny at collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/15014>

---

 src/gallium/drivers/virgl/virgl_tgsi.c | 131 +++++++++++++++++++++++++++++++++
 1 file changed, 131 insertions(+)

diff --git a/src/gallium/drivers/virgl/virgl_tgsi.c b/src/gallium/drivers/virgl/virgl_tgsi.c
index 10e6c38ba0f..4b71c7e87b7 100644
--- a/src/gallium/drivers/virgl/virgl_tgsi.c
+++ b/src/gallium/drivers/virgl/virgl_tgsi.c
@@ -31,6 +31,27 @@
 #include "virgl_context.h"
 #include "virgl_screen.h"
 
+struct virgl_input_temp {
+   enum tgsi_file_type file;
+
+   /* Index within in the INPUT or SV files, or ~0 if no DCL of this input */
+   unsigned index;
+
+   /* TGSI_FILE_TEMPORARY index it will be mapped to. */
+   unsigned temp;
+
+   bool sint;
+};
+
+enum virgl_input_temps {
+   INPUT_TEMP_LAYER,
+   INPUT_TEMP_VIEWPORT_INDEX,
+   INPUT_TEMP_BLOCK_ID,
+   INPUT_TEMP_HELPER_INVOCATION,
+   INPUT_TEMP_SAMPLEMASK,
+   INPUT_TEMP_COUNT,
+};
+
 struct virgl_transform_context {
    struct tgsi_transform_context base;
    bool cull_enabled;
@@ -42,8 +63,21 @@ struct virgl_transform_context {
    unsigned writemask_fixup_outs[5];
    unsigned writemask_fixup_temps;
    unsigned num_writemask_fixups;
+
+   struct virgl_input_temp input_temp[INPUT_TEMP_COUNT];
 };
 
+static void
+virgl_tgsi_transform_declaration_input_temp(const struct tgsi_full_declaration *decl,
+                                            struct virgl_input_temp *input_temp,
+                                            enum tgsi_semantic semantic_name)
+{
+   if (decl->Semantic.Name == semantic_name) {
+      input_temp->file = decl->Declaration.File;
+      input_temp->index = decl->Range.First;
+   }
+}
+
 static void
 virgl_tgsi_transform_declaration(struct tgsi_transform_context *ctx,
                                  struct tgsi_full_declaration *decl)
@@ -57,6 +91,20 @@ virgl_tgsi_transform_declaration(struct tgsi_transform_context *ctx,
             decl->Declaration.Dimension = 0;
       }
       break;
+   case TGSI_FILE_INPUT:
+      virgl_tgsi_transform_declaration_input_temp(decl, &vtctx->input_temp[INPUT_TEMP_LAYER],
+                                                   TGSI_SEMANTIC_LAYER);
+      virgl_tgsi_transform_declaration_input_temp(decl, &vtctx->input_temp[INPUT_TEMP_VIEWPORT_INDEX],
+                                                   TGSI_SEMANTIC_VIEWPORT_INDEX);
+      break;
+   case TGSI_FILE_SYSTEM_VALUE:
+      virgl_tgsi_transform_declaration_input_temp(decl, &vtctx->input_temp[INPUT_TEMP_BLOCK_ID],
+                                                   TGSI_SEMANTIC_BLOCK_ID);
+      virgl_tgsi_transform_declaration_input_temp(decl, &vtctx->input_temp[INPUT_TEMP_HELPER_INVOCATION],
+                                                   TGSI_SEMANTIC_HELPER_INVOCATION);
+      virgl_tgsi_transform_declaration_input_temp(decl, &vtctx->input_temp[INPUT_TEMP_SAMPLEMASK],
+                                                   TGSI_SEMANTIC_SAMPLEMASK);
+      break;
    case TGSI_FILE_OUTPUT:
       switch (decl->Semantic.Name) {
       case TGSI_SEMANTIC_CLIPDIST:
@@ -106,6 +154,29 @@ virgl_tgsi_transform_property(struct tgsi_transform_context *ctx,
    }
 }
 
+static void
+virgl_mov_input_temp_sint(struct tgsi_transform_context * ctx,
+                          struct virgl_input_temp *temp)
+{
+   if (temp->index != ~0) {
+      tgsi_transform_op2_inst(ctx, TGSI_OPCODE_IMAX,
+                              TGSI_FILE_TEMPORARY, temp->temp, TGSI_WRITEMASK_XYZW,
+                              temp->file, temp->index,
+                              temp->file, temp->index, 0);
+   }
+}
+
+static void
+virgl_mov_input_temp_uint(struct tgsi_transform_context * ctx,
+                          struct virgl_input_temp *temp)
+{
+   if (temp->index != ~0) {
+      tgsi_transform_op1_inst(ctx, TGSI_OPCODE_MOV,
+                              TGSI_FILE_TEMPORARY, temp->temp, TGSI_WRITEMASK_XYZW,
+                              temp->file, temp->index);
+   }
+}
+
 static void
 virgl_tgsi_transform_prolog(struct tgsi_transform_context * ctx)
 {
@@ -118,6 +189,60 @@ virgl_tgsi_transform_prolog(struct tgsi_transform_context * ctx)
                                 vtctx->writemask_fixup_temps,
                                 vtctx->writemask_fixup_temps + vtctx->num_writemask_fixups - 1);
    }
+
+   /* Assign input temps before we emit any instructions, but after we parsed
+    * existing temp decls.
+    */
+   for (int i = 0; i < ARRAY_SIZE(vtctx->input_temp); i++) {
+      if (vtctx->input_temp[i].index != ~0) {
+         vtctx->input_temp[i].temp = vtctx->next_temp++;
+         tgsi_transform_temp_decl(ctx, vtctx->input_temp[i].temp);
+      }
+   }
+
+   /* virglrenderer makes mistakes in the types of layer/viewport input
+    * references from unsigned ops, so we use a temp that we do a no-op signed
+    * op to at the top of the shader.
+    *
+    * https://gitlab.freedesktop.org/virgl/virglrenderer/-/merge_requests/615
+    */
+   virgl_mov_input_temp_sint(ctx, &vtctx->input_temp[INPUT_TEMP_LAYER]);
+   virgl_mov_input_temp_sint(ctx, &vtctx->input_temp[INPUT_TEMP_VIEWPORT_INDEX]);
+   virgl_mov_input_temp_sint(ctx, &vtctx->input_temp[INPUT_TEMP_SAMPLEMASK]);
+
+   /* virglrenderer also makes mistakes in the types of block id input
+    * references from signed ops, so we use a temp that we do a plain MOV to at
+    * the top of the shader.  Also, it falls over if an unused channel's swizzle
+    * uses the .w of the block id.
+    */
+   if (vtctx->input_temp[INPUT_TEMP_BLOCK_ID].index != ~0) {
+      struct tgsi_full_instruction inst = tgsi_default_full_instruction();
+      inst.Instruction.Opcode = TGSI_OPCODE_MOV;
+      inst.Instruction.NumDstRegs = 1;
+      inst.Dst[0].Register.File = TGSI_FILE_TEMPORARY,
+      inst.Dst[0].Register.Index = vtctx->input_temp[INPUT_TEMP_BLOCK_ID].temp;
+      inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZ;
+      inst.Instruction.NumSrcRegs = 1;
+      tgsi_transform_src_reg_xyzw(&inst.Src[0],
+                                  vtctx->input_temp[INPUT_TEMP_BLOCK_ID].file,
+                                  vtctx->input_temp[INPUT_TEMP_BLOCK_ID].index);
+      inst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X;
+      inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_Y;
+      inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_Z;
+      inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_Z;
+      ctx->emit_instruction(ctx, &inst);
+   }
+
+   virgl_mov_input_temp_uint(ctx, &vtctx->input_temp[INPUT_TEMP_HELPER_INVOCATION]);
+}
+
+static void
+virgl_tgsi_rewrite_src_for_input_temp(struct virgl_input_temp *temp, struct tgsi_full_src_register *src)
+{
+   if (src->Register.File == temp->file && src->Register.Index == temp->index) {
+      src->Register.File = TGSI_FILE_TEMPORARY;
+      src->Register.Index = temp->temp;
+   }
 }
 
 static void
@@ -158,6 +283,9 @@ virgl_tgsi_transform_instruction(struct tgsi_transform_context *ctx,
           inst->Src[i].Register.Dimension &&
           inst->Src[i].Dimension.Index == 0)
          inst->Src[i].Register.Dimension = 0;
+
+      for (int j = 0; j < ARRAY_SIZE(vtctx->input_temp); j++)
+         virgl_tgsi_rewrite_src_for_input_temp(&vtctx->input_temp[j], &inst->Src[i]);
    }
    ctx->emit_instruction(ctx, inst);
 
@@ -195,6 +323,9 @@ struct tgsi_token *virgl_tgsi_transform(struct virgl_screen *vscreen, const stru
    transform.fake_fp64 =
       vscreen->caps.caps.v2.capability_bits & VIRGL_CAP_FAKE_FP64;
 
+   for (int i = 0; i < ARRAY_SIZE(transform.input_temp); i++)
+      transform.input_temp[i].index = ~0;
+
    tgsi_transform_shader(tokens_in, new_tokens, newLen, &transform.base);
 
    return new_tokens;



More information about the mesa-commit mailing list