util: Move os_misc to util
[mesa.git] / src / gallium / auxiliary / util / u_pstipple.c
index 640305f9ec45eaf1b903d51d20b32811c2bed68d..77b0458dc0301fa7b80fe9d086b6773c10e35fbd 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  * 
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2008 VMware, Inc.
  * Copyright 2010 VMware, Inc.
  * All Rights Reserved.
  *
@@ -19,7 +19,7 @@
  * 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 TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE 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.
 #include "tgsi/tgsi_scan.h"
 
 /** Approx number of new tokens for instructions in pstip_transform_inst() */
-#define NUM_NEW_TOKENS 50
+#define NUM_NEW_TOKENS 53
 
 
-static void
+void
 util_pstipple_update_stipple_texture(struct pipe_context *pipe,
                                      struct pipe_resource *tex,
                                      const uint32_t pattern[32])
 {
-   static const uint bit31 = 1 << 31;
+   static const uint bit31 = 1u << 31;
    struct pipe_transfer *transfer;
    ubyte *data;
    int i, j;
@@ -118,7 +118,7 @@ util_pstipple_create_stipple_texture(struct pipe_context *pipe,
 
    tex = screen->resource_create(screen, &templat);
 
-   if (tex)
+   if (tex && pattern)
       util_pstipple_update_stipple_texture(pipe, tex, pattern);
 
    return tex;
@@ -177,13 +177,14 @@ struct pstip_transform_context {
    struct tgsi_shader_info info;
    uint tempsUsed;  /**< bitmask */
    int wincoordInput;
+   unsigned wincoordFile;
    int maxInput;
    uint samplersUsed;  /**< bitfield of samplers used */
    int freeSampler;  /** an available sampler for the pstipple */
-   int texTemp;  /**< temp registers */
    int numImmed;
-   boolean firstInstruction;
    uint coordOrigin;
+   unsigned fixedUnit;
+   bool hasFixedUnit;
 };
 
 
@@ -203,10 +204,10 @@ pstip_transform_decl(struct tgsi_transform_context *ctx,
    if (decl->Declaration.File == TGSI_FILE_SAMPLER) {
       uint i;
       for (i = decl->Range.First; i <= decl->Range.Last; i++) {
-         pctx->samplersUsed |= 1 << i;
+         pctx->samplersUsed |= 1u << i;
       }
    }
-   else if (decl->Declaration.File == TGSI_FILE_INPUT) {
+   else if (decl->Declaration.File == pctx->wincoordFile) {
       pctx->maxInput = MAX2(pctx->maxInput, (int) decl->Range.Last);
       if (decl->Semantic.Name == TGSI_SEMANTIC_POSITION)
          pctx->wincoordInput = (int) decl->Range.First;
@@ -229,6 +230,7 @@ pstip_transform_immed(struct tgsi_transform_context *ctx,
    struct pstip_transform_context *pctx =
       (struct pstip_transform_context *) ctx;
    pctx->numImmed++;
+   ctx->emit_immediate(ctx, immed);
 }
 
 
@@ -243,7 +245,7 @@ free_bit(uint bitfield)
 
 
 /**
- * TGSI instruction transform callback.
+ * TGSI transform prolog
  * Before the first instruction, insert our new code to sample the
  * stipple texture (using the fragment coord register) then kill the
  * fragment if the stipple texture bit is off.
@@ -256,166 +258,131 @@ free_bit(uint bitfield)
  *   [...original code...]
  */
 static void
-pstip_transform_inst(struct tgsi_transform_context *ctx,
-                     struct tgsi_full_instruction *inst)
+pstip_transform_prolog(struct tgsi_transform_context *ctx)
 {
    struct pstip_transform_context *pctx =
       (struct pstip_transform_context *) ctx;
+   int wincoordInput;
+   int texTemp;
+   int sampIdx;
+
+   STATIC_ASSERT(sizeof(pctx->samplersUsed) * 8 >= PIPE_MAX_SAMPLERS);
+
+   /* find free texture sampler */
+   pctx->freeSampler = free_bit(pctx->samplersUsed);
+   if (pctx->freeSampler < 0 || pctx->freeSampler >= PIPE_MAX_SAMPLERS)
+      pctx->freeSampler = PIPE_MAX_SAMPLERS - 1;
 
-   if (pctx->firstInstruction) {
-      /* emit our new declarations before the first instruction */
+   if (pctx->wincoordInput < 0)
+      wincoordInput = pctx->maxInput + 1;
+   else
+      wincoordInput = pctx->wincoordInput;
 
+   if (pctx->wincoordInput < 0) {
       struct tgsi_full_declaration decl;
-      struct tgsi_full_instruction newInst;
-      uint i;
-      int wincoordInput;
-
-      /* find free texture sampler */
-      pctx->freeSampler = free_bit(pctx->samplersUsed);
-      if (pctx->freeSampler >= PIPE_MAX_SAMPLERS)
-         pctx->freeSampler = PIPE_MAX_SAMPLERS - 1;
-
-      if (pctx->wincoordInput < 0)
-         wincoordInput = pctx->maxInput + 1;
-      else
-         wincoordInput = pctx->wincoordInput;
-
-      /* find one free temp register */
-      for (i = 0; i < 32; i++) {
-         if ((pctx->tempsUsed & (1 << i)) == 0) {
-            /* found a free temp */
-            if (pctx->texTemp < 0)
-               pctx->texTemp  = i;
-            else
-               break;
-         }
-      }
-      assert(pctx->texTemp >= 0);
 
-      if (pctx->wincoordInput < 0) {
-         /* declare new position input reg */
-         decl = tgsi_default_full_declaration();
-         decl.Declaration.File = TGSI_FILE_INPUT;
+      decl = tgsi_default_full_declaration();
+      /* declare new position input reg */
+      decl.Declaration.File = pctx->wincoordFile;
+      decl.Declaration.Semantic = 1;
+      decl.Semantic.Name = TGSI_SEMANTIC_POSITION;
+      decl.Range.First =
+      decl.Range.Last = wincoordInput;
+
+      if (pctx->wincoordFile == TGSI_FILE_INPUT) {
          decl.Declaration.Interpolate = 1;
-         decl.Declaration.Semantic = 1;
-         decl.Semantic.Name = TGSI_SEMANTIC_POSITION;
-         decl.Semantic.Index = 0;
-         decl.Range.First = 
-            decl.Range.Last = wincoordInput;
          decl.Interp.Interpolate = TGSI_INTERPOLATE_LINEAR;
-         ctx->emit_declaration(ctx, &decl);
       }
 
-      /* declare new sampler */
-      decl = tgsi_default_full_declaration();
-      decl.Declaration.File = TGSI_FILE_SAMPLER;
-      decl.Range.First = 
-      decl.Range.Last = pctx->freeSampler;
       ctx->emit_declaration(ctx, &decl);
+   }
 
-      /* declare new temp regs */
-      decl = tgsi_default_full_declaration();
-      decl.Declaration.File = TGSI_FILE_TEMPORARY;
-      decl.Range.First = 
-      decl.Range.Last = pctx->texTemp;
-      ctx->emit_declaration(ctx, &decl);
+   sampIdx = pctx->hasFixedUnit ? (int)pctx->fixedUnit : pctx->freeSampler;
 
-      /* emit immediate = {1/32, 1/32, 1, 1}
-       * The index/position of this immediate will be pctx->numImmed
-       */
-      {
-         static const float value[4] = { 1.0/32, 1.0/32, 1.0, 1.0 };
-         struct tgsi_full_immediate immed;
-         uint size = 4;
-         immed = tgsi_default_full_immediate();
-         immed.Immediate.NrTokens = 1 + size; /* one for the token itself */
-         immed.u[0].Float = value[0];
-         immed.u[1].Float = value[1];
-         immed.u[2].Float = value[2];
-         immed.u[3].Float = value[3];
-         ctx->emit_immediate(ctx, &immed);
-      }
+   /* declare new sampler */
+   tgsi_transform_sampler_decl(ctx, sampIdx);
 
-      pctx->firstInstruction = FALSE;
-
-
-      /* 
-       * Insert new MUL/TEX/KILL_IF instructions at start of program
-       * Take gl_FragCoord, divide by 32 (stipple size), sample the
-       * texture and kill fragment if needed.
-       *
-       * We'd like to use non-normalized texcoords to index into a RECT
-       * texture, but we can only use REPEAT wrap mode with normalized
-       * texcoords.  Darn.
-       */
-
-      /* XXX invert wincoord if origin isn't lower-left... */
-
-      /* MUL texTemp, INPUT[wincoord], 1/32; */
-      newInst = tgsi_default_full_instruction();
-      newInst.Instruction.Opcode = TGSI_OPCODE_MUL;
-      newInst.Instruction.NumDstRegs = 1;
-      newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
-      newInst.Dst[0].Register.Index = pctx->texTemp;
-      newInst.Instruction.NumSrcRegs = 2;
-      newInst.Src[0].Register.File = TGSI_FILE_INPUT;
-      newInst.Src[0].Register.Index = wincoordInput;
-      newInst.Src[1].Register.File = TGSI_FILE_IMMEDIATE;
-      newInst.Src[1].Register.Index = pctx->numImmed;
-      ctx->emit_instruction(ctx, &newInst);
-
-      /* TEX texTemp, texTemp, sampler; */
-      newInst = tgsi_default_full_instruction();
-      newInst.Instruction.Opcode = TGSI_OPCODE_TEX;
-      newInst.Instruction.NumDstRegs = 1;
-      newInst.Dst[0].Register.File = TGSI_FILE_TEMPORARY;
-      newInst.Dst[0].Register.Index = pctx->texTemp;
-      newInst.Instruction.NumSrcRegs = 2;
-      newInst.Instruction.Texture = TRUE;
-      newInst.Texture.Texture = TGSI_TEXTURE_2D;
-      newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
-      newInst.Src[0].Register.Index = pctx->texTemp;
-      newInst.Src[1].Register.File = TGSI_FILE_SAMPLER;
-      newInst.Src[1].Register.Index = pctx->freeSampler;
-      ctx->emit_instruction(ctx, &newInst);
-
-      /* KILL_IF -texTemp;   # if -texTemp < 0, kill fragment */
-      newInst = tgsi_default_full_instruction();
-      newInst.Instruction.Opcode = TGSI_OPCODE_KILL_IF;
-      newInst.Instruction.NumDstRegs = 0;
-      newInst.Instruction.NumSrcRegs = 1;
-      newInst.Src[0].Register.File = TGSI_FILE_TEMPORARY;
-      newInst.Src[0].Register.Index = pctx->texTemp;
-      newInst.Src[0].Register.Negate = 1;
-      ctx->emit_instruction(ctx, &newInst);
+   /* if the src shader has SVIEW decl's for each SAMP decl, we
+    * need to continue the trend and ensure there is a matching
+    * SVIEW for the new SAMP we just created
+    */
+   if (pctx->info.file_max[TGSI_FILE_SAMPLER_VIEW] != -1) {
+      tgsi_transform_sampler_view_decl(ctx,
+                                       sampIdx,
+                                       TGSI_TEXTURE_2D,
+                                       TGSI_RETURN_TYPE_FLOAT);
+   }
+
+   /* Declare temp[0] reg if not already declared.
+    * We can always use temp[0] since this code is before
+    * the rest of the shader.
+    */
+   texTemp = 0;
+   if ((pctx->tempsUsed & (1 << texTemp)) == 0) {
+      tgsi_transform_temp_decl(ctx, texTemp);
    }
 
-   /* emit this instruction */
-   ctx->emit_instruction(ctx, inst);
+   /* emit immediate = {1/32, 1/32, 1, 1}
+    * The index/position of this immediate will be pctx->numImmed
+    */
+   tgsi_transform_immediate_decl(ctx, 1.0/32.0, 1.0/32.0, 1.0, 1.0);
+
+   /* 
+    * Insert new MUL/TEX/KILL_IF instructions at start of program
+    * Take gl_FragCoord, divide by 32 (stipple size), sample the
+    * texture and kill fragment if needed.
+    *
+    * We'd like to use non-normalized texcoords to index into a RECT
+    * texture, but we can only use REPEAT wrap mode with normalized
+    * texcoords.  Darn.
+    */
+
+   /* XXX invert wincoord if origin isn't lower-left... */
+
+   /* MUL texTemp, INPUT[wincoord], 1/32; */
+   tgsi_transform_op2_inst(ctx, TGSI_OPCODE_MUL,
+                           TGSI_FILE_TEMPORARY, texTemp,
+                           TGSI_WRITEMASK_XYZW,
+                           pctx->wincoordFile, wincoordInput,
+                           TGSI_FILE_IMMEDIATE, pctx->numImmed, false);
+
+   /* TEX texTemp, texTemp, sampler, 2D; */
+   tgsi_transform_tex_inst(ctx,
+                           TGSI_FILE_TEMPORARY, texTemp,
+                           TGSI_FILE_TEMPORARY, texTemp,
+                           TGSI_TEXTURE_2D, sampIdx);
+
+   /* KILL_IF -texTemp;   # if -texTemp < 0, kill fragment */
+   tgsi_transform_kill_inst(ctx,
+                            TGSI_FILE_TEMPORARY, texTemp,
+                            TGSI_SWIZZLE_W, TRUE);
 }
 
 
 /**
  * Given a fragment shader, return a new fragment shader which
  * samples a stipple texture and executes KILL.
+ *
+ * \param samplerUnitOut  returns the index of the sampler unit which
+ *                        will be used to sample the stipple texture;
+ *                        if NULL, the fixed unit is used
+ * \param fixedUnit       fixed texture unit used for the stipple texture
+ * \param wincoordFile    TGSI_FILE_INPUT or TGSI_FILE_SYSTEM_VALUE,
+ *                        depending on which one is supported by the driver
+ *                        for TGSI_SEMANTIC_POSITION in the fragment shader
  */
-struct pipe_shader_state *
-util_pstipple_create_fragment_shader(struct pipe_context *pipe,
-                                     struct pipe_shader_state *fs,
-                                     unsigned *samplerUnitOut)
+struct tgsi_token *
+util_pstipple_create_fragment_shader(const struct tgsi_token *tokens,
+                                     unsigned *samplerUnitOut,
+                                     unsigned fixedUnit,
+                                     unsigned wincoordFile)
 {
-   struct pipe_shader_state *new_fs;
    struct pstip_transform_context transform;
-   const uint newLen = tgsi_num_tokens(fs->tokens) + NUM_NEW_TOKENS;
-   unsigned i;
-
-   new_fs = MALLOC(sizeof(*new_fs));
-   if (!new_fs)
-      return NULL;
+   const uint newLen = tgsi_num_tokens(tokens) + NUM_NEW_TOKENS;
+   struct tgsi_token *new_tokens;
 
-   new_fs->tokens = tgsi_alloc_tokens(newLen);
-   if (!new_fs->tokens) {
-      FREE(new_fs);
+   new_tokens = tgsi_alloc_tokens(newLen);
+   if (!new_tokens) {
       return NULL;
    }
 
@@ -423,34 +390,31 @@ util_pstipple_create_fragment_shader(struct pipe_context *pipe,
     */
    memset(&transform, 0, sizeof(transform));
    transform.wincoordInput = -1;
+   transform.wincoordFile = wincoordFile;
    transform.maxInput = -1;
-   transform.texTemp = -1;
-   transform.firstInstruction = TRUE;
    transform.coordOrigin = TGSI_FS_COORD_ORIGIN_UPPER_LEFT;
-   transform.base.transform_instruction = pstip_transform_inst;
+   transform.hasFixedUnit = !samplerUnitOut;
+   transform.fixedUnit = fixedUnit;
+   transform.base.prolog = pstip_transform_prolog;
    transform.base.transform_declaration = pstip_transform_decl;
    transform.base.transform_immediate = pstip_transform_immed;
 
-   tgsi_scan_shader(fs->tokens, &transform.info);
+   tgsi_scan_shader(tokens, &transform.info);
 
-   /* find fragment coordinate origin property */
-   for (i = 0; i < transform.info.num_properties; i++) {
-      if (transform.info.properties[i].name == TGSI_PROPERTY_FS_COORD_ORIGIN)
-         transform.coordOrigin = transform.info.properties[i].data[0];
-   }
+   transform.coordOrigin =
+      transform.info.properties[TGSI_PROPERTY_FS_COORD_ORIGIN];
 
-   tgsi_transform_shader(fs->tokens,
-                         (struct tgsi_token *) new_fs->tokens,
-                         newLen, &transform.base);
+   tgsi_transform_shader(tokens, new_tokens, newLen, &transform.base);
 
 #if 0 /* DEBUG */
    tgsi_dump(fs->tokens, 0);
    tgsi_dump(new_fs->tokens, 0);
 #endif
 
-   assert(transform.freeSampler < PIPE_MAX_SAMPLERS);
-   *samplerUnitOut = transform.freeSampler;
+   if (samplerUnitOut) {
+      assert(transform.freeSampler < PIPE_MAX_SAMPLERS);
+      *samplerUnitOut = transform.freeSampler;
+   }
 
-   return new_fs;
+   return new_tokens;
 }
-