Mesa (master): util: Add util functionality for GL4.1 support

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Fri Jun 5 06:56:08 UTC 2020


Module: Mesa
Branch: master
Commit: 48a7456f4df53b94f0335f8b605ca2da9ed16d81
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=48a7456f4df53b94f0335f8b605ca2da9ed16d81

Author: Neha Bhende <bhenden at vmware.com>
Date:   Tue May 26 21:31:14 2020 +0530

util: Add util functionality for GL4.1 support

This patch adds the following tgsi utilities

* tgsi_dynamic_indexing: This utility flattens out the dyanamic indexing of constant buffers
* tgsi_vpos: This utility writes zeros to position at index 0 in vertex shader.
  This utility can be used if there is no shader output in vertex shader
* util_make_tess_ctrl_passthrough_shader: This adds passthough tessellation control shader.
  Input of passthrough tess ctrl shader is output of vertex shader
  and output is input of tessellation eval shader.
  If program has tessellation eval shader but no tessellation control shader,
  this utility can be used to create passthrough tessellation control shader.

Reviewed-by: Brian Paul <brianp at vmware.com>
Reviewed-by: Charmaine Lee <charmainel at vmware.com>
Signed-off-by: Neha Bhende <bhenden at vmware.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5317>

---

 src/gallium/auxiliary/meson.build                  |   2 +
 src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.c | 361 +++++++++++++++++++++
 src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.h |  38 +++
 src/gallium/auxiliary/tgsi/tgsi_transform.h        |  18 +
 src/gallium/auxiliary/tgsi/tgsi_vpos.c             | 109 +++++++
 src/gallium/auxiliary/tgsi/tgsi_vpos.h             |  35 ++
 src/gallium/auxiliary/util/u_simple_shaders.c      | 108 ++++++
 src/gallium/auxiliary/util/u_simple_shaders.h      |   9 +
 8 files changed, 680 insertions(+)

diff --git a/src/gallium/auxiliary/meson.build b/src/gallium/auxiliary/meson.build
index 3e91a6c2723..76dd0e1f4a5 100644
--- a/src/gallium/auxiliary/meson.build
+++ b/src/gallium/auxiliary/meson.build
@@ -183,6 +183,7 @@ files_libgallium = files(
   'tgsi/tgsi_build.h',
   'tgsi/tgsi_dump.c',
   'tgsi/tgsi_dump.h',
+  'tgsi/tgsi_dynamic_indexing.c',
   'tgsi/tgsi_exec.c',
   'tgsi/tgsi_exec.h',
   'tgsi/tgsi_emulate.c',
@@ -217,6 +218,7 @@ files_libgallium = files(
   'tgsi/tgsi_ureg.h',
   'tgsi/tgsi_util.c',
   'tgsi/tgsi_util.h',
+  'tgsi/tgsi_vpos.c',
   'translate/translate.c',
   'translate/translate.h',
   'translate/translate_cache.c',
diff --git a/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.c b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.c
new file mode 100644
index 00000000000..3f3a3ba523e
--- /dev/null
+++ b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.c
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2018 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * This utility transforms the shader to support dynamic array indexing
+ * for samplers and constant buffers.
+ * It calculates dynamic array index first and then compare it with each
+ * index and operation will be performed with matching index
+ */
+
+#include "util/u_debug.h"
+#include "util/u_math.h"
+#include "tgsi_info.h"
+#include "tgsi_dynamic_indexing.h"
+#include "tgsi_transform.h"
+#include "tgsi_dump.h"
+#include "pipe/p_state.h"
+
+
+struct dIndexing_transform_context
+{
+   struct tgsi_transform_context base;
+   unsigned orig_num_tmp;
+   unsigned orig_num_imm;
+   unsigned num_const_bufs;
+   unsigned num_samplers;
+   unsigned num_iterations;
+   unsigned const_buf_range[PIPE_MAX_CONSTANT_BUFFERS];
+};
+
+
+static inline struct dIndexing_transform_context *
+dIndexing_transform_context(struct tgsi_transform_context *ctx)
+{
+   return (struct dIndexing_transform_context *) ctx;
+}
+
+
+/**
+ * TGSI declaration transform callback.
+ */
+static void
+dIndexing_decl(struct tgsi_transform_context *ctx,
+               struct tgsi_full_declaration *decl)
+{
+   struct dIndexing_transform_context *dc = dIndexing_transform_context(ctx);
+
+   if (decl->Declaration.File == TGSI_FILE_TEMPORARY) {
+      /**
+       * Emit some extra temporary register to use in keeping track of
+       * dynamic index.
+       */
+      dc->orig_num_tmp = decl->Range.Last;
+      decl->Range.Last = decl->Range.Last + 3;
+   }
+   else if (decl->Declaration.File == TGSI_FILE_CONSTANT) {
+      /* Keep track of number of constants in each buffer */
+      dc->const_buf_range[decl->Dim.Index2D] = decl->Range.Last;
+   }
+   ctx->emit_declaration(ctx, decl);
+}
+
+
+/**
+ * TGSI transform prolog callback.
+ */
+static void
+dIndexing_prolog(struct tgsi_transform_context *ctx)
+{
+   tgsi_transform_immediate_int_decl(ctx, 0, 1, 2, 3);
+   tgsi_transform_immediate_int_decl(ctx, 4, 5, 6, 7);
+}
+
+
+/**
+ * This function emits some extra instruction to remove dynamic array
+ * indexing of constant buffers / samplers from the shader.
+ * It calculates dynamic array index first and compare it with each index for
+ * declared constants/samplers.
+ */
+static void
+remove_dynamic_indexes(struct tgsi_transform_context *ctx,
+                       struct tgsi_full_instruction *orig_inst,
+                       const struct tgsi_full_src_register *reg)
+{
+   struct dIndexing_transform_context *dc = dIndexing_transform_context(ctx);
+   int i, j;
+   int tmp_loopIdx = dc->orig_num_tmp + 1;
+   int tmp_cond = dc->orig_num_tmp + 2;
+   int tmp_arrayIdx = dc->orig_num_tmp + 3;
+   int imm_index = dc->orig_num_imm;
+   struct tgsi_full_instruction inst;
+   unsigned INVALID_INDEX = 99999;
+   unsigned file = TGSI_FILE_NULL, index = INVALID_INDEX;
+   unsigned imm_swz_index = INVALID_INDEX;
+
+   /* calculate dynamic array index store it in tmp_arrayIdx.x */
+   inst = tgsi_default_full_instruction();
+   inst.Instruction.Opcode = TGSI_OPCODE_UADD;
+   inst.Instruction.NumDstRegs = 1;
+   tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY,
+                          tmp_arrayIdx, TGSI_WRITEMASK_X);
+   inst.Instruction.NumSrcRegs = 2;
+   if (reg->Register.File == TGSI_FILE_CONSTANT) {
+      file = reg->DimIndirect.File;
+      index = reg->DimIndirect.Index;
+      imm_swz_index = reg->Dimension.Index;
+   }
+   else if (reg->Register.File == TGSI_FILE_SAMPLER) {
+      file = reg->Indirect.File;
+      index = reg->Indirect.Index;
+      imm_swz_index = reg->Register.Index;
+   }
+   tgsi_transform_src_reg(&inst.Src[0], file,
+                          index, TGSI_SWIZZLE_X,
+                          TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, TGSI_SWIZZLE_X);
+   tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_IMMEDIATE,
+                          imm_index + (imm_swz_index / 4),
+                          imm_swz_index % 4,
+                          imm_swz_index % 4,
+                          imm_swz_index % 4,
+                          imm_swz_index % 4);
+   ctx->emit_instruction(ctx, &inst);
+
+   /* initialize counter to zero: tmp_loopIdx = 0 */
+   inst = tgsi_default_full_instruction();
+   inst.Instruction.Opcode = TGSI_OPCODE_MOV;
+   inst.Instruction.NumDstRegs = 1;
+   tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY,
+                          tmp_loopIdx, TGSI_WRITEMASK_X);
+   inst.Instruction.NumSrcRegs = 1;
+   tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_IMMEDIATE,
+                          imm_index, TGSI_SWIZZLE_X,
+                          TGSI_SWIZZLE_X, TGSI_SWIZZLE_X,
+                          TGSI_SWIZZLE_X);
+   ctx->emit_instruction(ctx, &inst);
+
+   for (i = 0; i < dc->num_iterations; i++) {
+      boolean out_of_bound_index = FALSE;
+      /**
+       * Make sure we are not exceeding index limit of constant buffer
+       *
+       * For example, In declaration, We have
+       *
+       * DCL CONST[0][0..1]
+       * DCL CONST[1][0..2]
+       * DCL CONST[2][0]
+       *
+       * and our dynamic index instruction is
+       * MOV TEMP[0], CONST[ADDR[0].x][1]
+       *
+       * We have to make sure to skip unrolling for CONST[2] because
+       * it has only one constant in the buffer
+       */
+      if ((reg->Register.File == TGSI_FILE_CONSTANT) &&
+          (!reg->Register.Indirect &&
+           (reg->Register.Index > dc->const_buf_range[i]))) {
+         out_of_bound_index = TRUE;
+      }
+
+      if (!out_of_bound_index) {
+         /**
+          * If we have an instruction of the format:
+          * OPCODE dst, src..., CONST[K][foo], src...
+          * where K is dynamic and tmp_loopIdx = i (loopcount),
+          * replace it with:
+          *
+          * if (K == tmp_loopIdx)
+          *    OPCODE dst, src... where src is CONST[i][foo] and i is constant
+          * }
+          *
+          * Similarly, If instruction uses dynamic array index for samplers
+          * e.g. OPCODE dst, src, SAMPL[k] ..
+          * replace it with:
+          * if (K == tmp_loopIdx)
+          *    OPCODE dst, src, SAMPL[i][foo]... where i is constant.
+          * }
+          */
+         inst = tgsi_default_full_instruction();
+         inst.Instruction.Opcode = TGSI_OPCODE_USEQ;
+         inst.Instruction.NumDstRegs = 1;
+         tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY,
+                                tmp_cond, TGSI_WRITEMASK_X);
+         inst.Instruction.NumSrcRegs = 2;
+         tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY,
+                                tmp_arrayIdx, TGSI_SWIZZLE_X,
+                                TGSI_SWIZZLE_X, TGSI_SWIZZLE_X,
+                                TGSI_SWIZZLE_X);
+         tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_TEMPORARY,
+                                tmp_loopIdx, TGSI_SWIZZLE_X,
+                                TGSI_SWIZZLE_X, TGSI_SWIZZLE_X,
+                                TGSI_SWIZZLE_X);
+         ctx->emit_instruction(ctx, &inst);
+
+         inst = tgsi_default_full_instruction();
+         inst.Instruction.Opcode = TGSI_OPCODE_UIF;
+         inst.Instruction.NumDstRegs = 0;
+         inst.Instruction.NumSrcRegs = 1;
+         tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY,
+                                tmp_cond, TGSI_SWIZZLE_X,
+                                TGSI_SWIZZLE_X, TGSI_SWIZZLE_X,
+                                TGSI_SWIZZLE_X);
+         ctx->emit_instruction(ctx, &inst);
+
+         /* emit instruction with new, non-dynamic source registers */
+         inst = *orig_inst;
+         for (j = 0; j < inst.Instruction.NumSrcRegs; j++) {
+            if (inst.Src[j].Dimension.Indirect &&
+                inst.Src[j].Register.File == TGSI_FILE_CONSTANT) {
+               inst.Src[j].Register.Dimension = 1;
+               inst.Src[j].Dimension.Index = i;
+               inst.Src[j].Dimension.Indirect = 0;
+            }
+            else if (inst.Src[j].Register.Indirect &&
+                     inst.Src[j].Register.File == TGSI_FILE_SAMPLER) {
+               inst.Src[j].Register.Indirect = 0;
+               inst.Src[j].Register.Index = i;
+            }
+         }
+         ctx->emit_instruction(ctx, &inst);
+
+         inst = tgsi_default_full_instruction();
+         inst.Instruction.Opcode = TGSI_OPCODE_ENDIF;
+         inst.Instruction.NumDstRegs = 0;
+         inst.Instruction.NumSrcRegs = 0;
+         ctx->emit_instruction(ctx, &inst);
+      }
+
+      /**
+       * Increment counter
+       * UADD tmp_loopIdx.x tmp_loopIdx.x imm(1)
+       */
+      inst = tgsi_default_full_instruction();
+      inst.Instruction.Opcode = TGSI_OPCODE_UADD;
+      inst.Instruction.NumDstRegs = 1;
+      tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_TEMPORARY,
+                             tmp_loopIdx, TGSI_WRITEMASK_X);
+      inst.Instruction.NumSrcRegs = 2;
+      tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_TEMPORARY,
+                              tmp_loopIdx, TGSI_SWIZZLE_X,
+                              TGSI_SWIZZLE_X, TGSI_SWIZZLE_X, TGSI_SWIZZLE_X);
+      tgsi_transform_src_reg(&inst.Src[1], TGSI_FILE_IMMEDIATE, imm_index,
+                             TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y,
+                             TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Y);
+
+      ctx->emit_instruction(ctx, &inst);
+   }
+}
+
+
+/**
+ * TGSI instruction transform callback.
+ */
+static void
+dIndexing_inst(struct tgsi_transform_context *ctx,
+               struct tgsi_full_instruction *inst)
+{
+   int i;
+   boolean indexing = FALSE;
+   struct dIndexing_transform_context *dc = dIndexing_transform_context(ctx);
+
+   for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
+      struct tgsi_full_src_register *src;
+      src = &inst->Src[i];
+      /* check if constant buffer/sampler is using dynamic index */
+      if ((src->Dimension.Indirect &&
+           src->Register.File == TGSI_FILE_CONSTANT) ||
+          (src->Register.Indirect &&
+           src->Register.File == TGSI_FILE_SAMPLER)) {
+
+         if (indexing)
+            assert("More than one src has dynamic indexing");
+
+         if (src->Register.File == TGSI_FILE_CONSTANT)
+            dc->num_iterations = dc->num_const_bufs;
+         else
+            dc->num_iterations = dc->num_samplers;
+
+         remove_dynamic_indexes(ctx, inst, src);
+         indexing = TRUE;
+      }
+   }
+
+   if (!indexing) {
+      ctx->emit_instruction(ctx, inst);
+   }
+}
+
+/**
+ * TGSI utility to remove dynamic array indexing for constant buffers and
+ * samplers.
+ *
+ * This utility accepts bitmask of declared constant buffers and samplers,
+ * number of immediates used in shader.
+ *
+ * If dynamic array index is used for constant buffers and samplers, this
+ * utility removes those dynamic indexes from shader. It also makes sure
+ * that it has same output as per original shader.
+ * This is achieved by calculating dynamic array index first and then compare
+ * it with each constant buffer/ sampler index and replace that dynamic index
+ * with static index.
+ */
+struct tgsi_token *
+tgsi_remove_dynamic_indexing(const struct tgsi_token *tokens_in,
+                             unsigned const_buffers_declared_bitmask,
+                             unsigned samplers_declared_bitmask,
+                             unsigned imm_count)
+{
+   struct dIndexing_transform_context transform;
+   const uint num_new_tokens = 1000; /* should be enough */
+   const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens;
+   struct tgsi_token *new_tokens;
+
+   /* setup transformation context */
+   memset(&transform, 0, sizeof(transform));
+   transform.base.transform_declaration = dIndexing_decl;
+   transform.base.transform_instruction = dIndexing_inst;
+   transform.base.prolog = dIndexing_prolog;
+
+   transform.orig_num_tmp = 0;
+   transform.orig_num_imm = imm_count;
+   /* get count of declared const buffers and sampler from their bitmasks*/
+   transform.num_const_bufs = log2(const_buffers_declared_bitmask + 1);
+   transform.num_samplers = log2(samplers_declared_bitmask + 1);
+   transform.num_iterations = 0;
+
+   /* allocate new tokens buffer */
+   new_tokens = tgsi_alloc_tokens(new_len);
+   if (!new_tokens)
+      return NULL;
+
+   /* transform the shader */
+   tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
+
+   return new_tokens;
+}
+
+
diff --git a/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.h b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.h
new file mode 100644
index 00000000000..c1b0d6f34f5
--- /dev/null
+++ b/src/gallium/auxiliary/tgsi/tgsi_dynamic_indexing.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef TGSI_DYNAMIC_INDEXING_H
+#define TGSI_DYNAMIC_INDEXING_H
+
+struct tgsi_token;
+struct tgsi_shader_info;
+
+struct tgsi_token *
+tgsi_remove_dynamic_indexing(const struct tgsi_token *tokens_in,
+                             unsigned const_buffers_declared,
+                             unsigned samplers_declared,
+                             unsigned imm_count);
+
+#endif /* TGSI_DYNAMIC_INDEXING_H */
diff --git a/src/gallium/auxiliary/tgsi/tgsi_transform.h b/src/gallium/auxiliary/tgsi/tgsi_transform.h
index 018e4a06d82..727edeb05ac 100644
--- a/src/gallium/auxiliary/tgsi/tgsi_transform.h
+++ b/src/gallium/auxiliary/tgsi/tgsi_transform.h
@@ -223,6 +223,24 @@ tgsi_transform_immediate_decl(struct tgsi_transform_context *ctx,
    ctx->emit_immediate(ctx, &immed);
 }
 
+static inline void
+tgsi_transform_immediate_int_decl(struct tgsi_transform_context *ctx,
+                                  int x, int y, int z, int w)
+{
+   struct tgsi_full_immediate immed;
+   unsigned size = 4;
+
+   immed = tgsi_default_full_immediate();
+   immed.Immediate.DataType = TGSI_IMM_INT32;
+   immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
+   immed.u[0].Int = x;
+   immed.u[1].Int = y;
+   immed.u[2].Int = z;
+   immed.u[3].Int = w;
+
+   ctx->emit_immediate(ctx, &immed);
+}
+
 static inline void
 tgsi_transform_dst_reg(struct tgsi_full_dst_register *reg,
                        unsigned file, unsigned index, unsigned writemask)
diff --git a/src/gallium/auxiliary/tgsi/tgsi_vpos.c b/src/gallium/auxiliary/tgsi/tgsi_vpos.c
new file mode 100644
index 00000000000..daae4f4aeca
--- /dev/null
+++ b/src/gallium/auxiliary/tgsi/tgsi_vpos.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2018 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * TGSI utility transforms the shader to write imm(0, 0, 0, 1) to vertex
+ * position
+ */
+
+#include "util/u_debug.h"
+#include "util/u_math.h"
+#include "tgsi_vpos.h"
+#include "tgsi_transform.h"
+#include "tgsi_dump.h"
+#include "pipe/p_state.h"
+
+
+struct write_vpos_context
+{
+   struct tgsi_transform_context base;
+   unsigned imm_index;
+};
+
+
+static inline struct write_vpos_context *
+write_vpos_context(struct tgsi_transform_context *ctx)
+{
+   return (struct write_vpos_context *) ctx;
+}
+
+
+/**
+ * TGSI transform prolog callback.
+ */
+static void
+write_vpos_prolog(struct tgsi_transform_context *ctx)
+{
+   struct write_vpos_context *vc = write_vpos_context(ctx);
+   struct tgsi_full_instruction inst;
+
+   tgsi_transform_immediate_decl(ctx, 0.0, 0.0, 0.0, 1.0);
+   tgsi_transform_output_decl(ctx, 0,
+                             TGSI_SEMANTIC_POSITION, 0,
+                             0);
+   inst = tgsi_default_full_instruction();
+   inst.Instruction.Opcode = TGSI_OPCODE_MOV;
+   inst.Instruction.NumDstRegs = 1;
+   tgsi_transform_dst_reg(&inst.Dst[0], TGSI_FILE_OUTPUT,
+                          0, TGSI_WRITEMASK_XYZW);
+   inst.Instruction.NumSrcRegs = 1;
+   tgsi_transform_src_reg(&inst.Src[0], TGSI_FILE_IMMEDIATE,
+                          vc->imm_index, TGSI_SWIZZLE_X,
+                          TGSI_SWIZZLE_Y, TGSI_SWIZZLE_Z, TGSI_SWIZZLE_W);
+   ctx->emit_instruction(ctx, &inst);
+}
+
+
+/**
+ * TGSI utility writes imm(0, 0, 0, 1) to vertex position
+ */
+struct tgsi_token *
+tgsi_write_vpos(const struct tgsi_token *tokens_in,
+                unsigned num_immediates)
+{
+   struct write_vpos_context transform;
+   const uint num_new_tokens = 1000; /* should be enough */
+   const uint new_len = tgsi_num_tokens(tokens_in) + num_new_tokens;
+   struct tgsi_token *new_tokens;
+
+   /* setup transformation context */
+   memset(&transform, 0, sizeof(transform));
+   transform.base.prolog = write_vpos_prolog;
+
+   transform.imm_index = num_immediates;
+
+   /* allocate new tokens buffer */
+   new_tokens = tgsi_alloc_tokens(new_len);
+   if (!new_tokens)
+      return NULL;
+
+   /* transform the shader */
+   tgsi_transform_shader(tokens_in, new_tokens, new_len, &transform.base);
+
+   return new_tokens;
+}
+
+
diff --git a/src/gallium/auxiliary/tgsi/tgsi_vpos.h b/src/gallium/auxiliary/tgsi/tgsi_vpos.h
new file mode 100644
index 00000000000..4c2ef81fdb9
--- /dev/null
+++ b/src/gallium/auxiliary/tgsi/tgsi_vpos.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2018 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef TGSI_WRITE_VPOS_H
+#define TGSI_WRITE_VPOS_H
+
+struct tgsi_token;
+
+struct tgsi_token *
+tgsi_write_vpos(const struct tgsi_token *tokens_in,
+                unsigned num_immediates);
+
+#endif /* TGSI_WRIE_VPOS_H */
diff --git a/src/gallium/auxiliary/util/u_simple_shaders.c b/src/gallium/auxiliary/util/u_simple_shaders.c
index ceb59507901..1908f6198a3 100644
--- a/src/gallium/auxiliary/util/u_simple_shaders.c
+++ b/src/gallium/auxiliary/util/u_simple_shaders.c
@@ -895,6 +895,7 @@ util_make_geometry_passthrough_shader(struct pipe_context *pipe,
    return ureg_create_shader_and_destroy(ureg, pipe);
 }
 
+
 /**
  * Blit from color to ZS or from ZS to color in a manner that is equivalent
  * to memcpy.
@@ -1056,3 +1057,110 @@ util_make_fs_pack_color_zs(struct pipe_context *pipe,
 
    return ureg_create_shader_and_destroy(ureg, pipe);
 }
+
+
+/**
+ * Create passthrough tessellation control shader.
+ * Passthrough tessellation control shader has output of vertex shader
+ * as input and input of tessellation eval shader as output.
+ */
+void *
+util_make_tess_ctrl_passthrough_shader(struct pipe_context *pipe,
+                                       uint num_vs_outputs,
+                                       uint num_tes_inputs,
+                                       const ubyte *vs_semantic_names,
+                                       const ubyte *vs_semantic_indexes,
+                                       const ubyte *tes_semantic_names,
+                                       const ubyte *tes_semantic_indexes,
+                                       const unsigned vertices_per_patch)
+{
+   unsigned i, j;
+   unsigned num_regs;
+
+   struct ureg_program *ureg;
+   struct ureg_dst temp, addr;
+   struct ureg_src invocationID;
+   struct ureg_dst dst[PIPE_MAX_SHADER_OUTPUTS];
+   struct ureg_src src[PIPE_MAX_SHADER_INPUTS];
+
+   ureg = ureg_create(PIPE_SHADER_TESS_CTRL);
+
+   if (!ureg)
+      return NULL;
+
+   ureg_property(ureg, TGSI_PROPERTY_TCS_VERTICES_OUT, vertices_per_patch);
+
+   num_regs = 0;
+
+   for (i = 0; i < num_tes_inputs; i++) {
+      switch (tes_semantic_names[i]) {
+      case TGSI_SEMANTIC_POSITION:
+      case TGSI_SEMANTIC_PSIZE:
+      case TGSI_SEMANTIC_COLOR:
+      case TGSI_SEMANTIC_BCOLOR:
+      case TGSI_SEMANTIC_CLIPDIST:
+      case TGSI_SEMANTIC_CLIPVERTEX:
+      case TGSI_SEMANTIC_TEXCOORD:
+      case TGSI_SEMANTIC_FOG:
+      case TGSI_SEMANTIC_GENERIC:
+         for (j = 0; j < num_vs_outputs; j++) {
+            if (tes_semantic_names[i] == vs_semantic_names[j] &&
+                tes_semantic_indexes[i] == vs_semantic_indexes[j]) {
+
+               dst[num_regs] = ureg_DECL_output(ureg,
+                                               tes_semantic_names[i],
+                                               tes_semantic_indexes[i]);
+               src[num_regs] = ureg_DECL_input(ureg, vs_semantic_names[j],
+                                               vs_semantic_indexes[j],
+                                               0, 1);
+
+               if (tes_semantic_names[i] == TGSI_SEMANTIC_GENERIC ||
+                   tes_semantic_names[i] == TGSI_SEMANTIC_POSITION) {
+                  src[num_regs] = ureg_src_dimension(src[num_regs], 0);
+                  dst[num_regs] = ureg_dst_dimension(dst[num_regs], 0);
+               }
+
+               num_regs++;
+               break;
+            }
+         }
+         break;
+      default:
+         break;
+      }
+   }
+
+   dst[num_regs] = ureg_DECL_output(ureg, TGSI_SEMANTIC_TESSOUTER,
+                                    num_regs);
+   src[num_regs] = ureg_DECL_constant(ureg, 0);
+   num_regs++;
+   dst[num_regs] = ureg_DECL_output(ureg, TGSI_SEMANTIC_TESSINNER,
+                                    num_regs);
+   src[num_regs] = ureg_DECL_constant(ureg, 1);
+   num_regs++;
+
+   if (vertices_per_patch > 1) {
+      invocationID = ureg_DECL_system_value(ureg,
+                        TGSI_SEMANTIC_INVOCATIONID, 0);
+      temp = ureg_DECL_local_temporary(ureg);
+      addr = ureg_DECL_address(ureg);
+      ureg_UARL(ureg, ureg_writemask(addr, TGSI_WRITEMASK_X),
+                ureg_scalar(invocationID, TGSI_SWIZZLE_X));
+   }
+
+   for (i = 0; i < num_regs; i++) {
+      if (dst[i].Dimension && vertices_per_patch > 1) {
+         struct ureg_src addr_x = ureg_scalar(ureg_src(addr), TGSI_SWIZZLE_X);
+         ureg_MOV(ureg, temp, ureg_src_dimension_indirect(src[i],
+                  addr_x, 0));
+         ureg_MOV(ureg, ureg_dst_dimension_indirect(dst[i],
+                  addr_x, 0), ureg_src(temp));
+      }
+      else
+         ureg_MOV(ureg, dst[i], src[i]);
+   }
+
+   ureg_END(ureg);
+
+   return ureg_create_shader_and_destroy(ureg, pipe);
+}
diff --git a/src/gallium/auxiliary/util/u_simple_shaders.h b/src/gallium/auxiliary/util/u_simple_shaders.h
index 501906d6fd3..9e024d05f72 100644
--- a/src/gallium/auxiliary/util/u_simple_shaders.h
+++ b/src/gallium/auxiliary/util/u_simple_shaders.h
@@ -159,6 +159,15 @@ util_make_fs_pack_color_zs(struct pipe_context *pipe,
                            enum pipe_format zs_format,
                            bool dst_is_color);
 
+extern void *
+util_make_tess_ctrl_passthrough_shader(struct pipe_context *pipe,
+                                       uint num_vs_outputs,
+                                       uint num_tes_inputs,
+                                       const ubyte *vs_semantic_names,
+                                       const ubyte *vs_semantic_indexes,
+                                       const ubyte *tes_semantic_names,
+                                       const ubyte *tes_semantic_indexes,
+                                       const unsigned vertices_per_patch);
 #ifdef __cplusplus
 }
 #endif



More information about the mesa-commit mailing list