st/mesa: implement glBitmap shader transformation using tgsi_transform_shader
authorMarek Olšák <marek.olsak@amd.com>
Sun, 4 Oct 2015 00:38:55 +0000 (02:38 +0200)
committerMarek Olšák <marek.olsak@amd.com>
Fri, 9 Oct 2015 20:02:18 +0000 (22:02 +0200)
Reviewed-by: Dave Airlie <airlied@redhat.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Tested-by: Brian Paul <brianp@vmware.com>
src/mesa/Makefile.sources
src/mesa/state_tracker/st_cb_bitmap.c
src/mesa/state_tracker/st_cb_bitmap.h
src/mesa/state_tracker/st_cb_bitmap_shader.c [new file with mode: 0644]
src/mesa/state_tracker/st_glsl_to_tgsi.cpp
src/mesa/state_tracker/st_glsl_to_tgsi.h
src/mesa/state_tracker/st_program.c

index b40ee4d395b4ccb243d64cfdc4e7058aeac909f5..2dabea830753e620cae837e0bbf10419a734ce72 100644 (file)
@@ -415,6 +415,7 @@ STATETRACKER_FILES = \
        state_tracker/st_cache.h \
        state_tracker/st_cb_bitmap.c \
        state_tracker/st_cb_bitmap.h \
+       state_tracker/st_cb_bitmap_shader.c \
        state_tracker/st_cb_blit.c \
        state_tracker/st_cb_blit.h \
        state_tracker/st_cb_bufferobjects.c \
index 230eba8c4a5af07b56cbbd1b9af66459f51bd0f7..bb6dfe8564431e2c8d61504a2f25949e71aa1546 100644 (file)
@@ -107,151 +107,6 @@ struct bitmap_cache
 #define Z_EPSILON 1e-06
 
 
-/**
- * Make fragment program for glBitmap:
- *   Sample the texture and kill the fragment if the bit is 0.
- * This program will be combined with the user's fragment program.
- */
-static struct st_fragment_program *
-make_bitmap_fragment_program(struct gl_context *ctx, GLuint samplerIndex)
-{
-   struct st_context *st = st_context(ctx);
-   struct st_fragment_program *stfp;
-   struct gl_program *p;
-   GLuint ic = 0;
-
-   p = ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
-   if (!p)
-      return NULL;
-
-   p->NumInstructions = 3;
-
-   p->Instructions = _mesa_alloc_instructions(p->NumInstructions);
-   if (!p->Instructions) {
-      ctx->Driver.DeleteProgram(ctx, p);
-      return NULL;
-   }
-   _mesa_init_instructions(p->Instructions, p->NumInstructions);
-
-   /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
-   p->Instructions[ic].Opcode = OPCODE_TEX;
-   p->Instructions[ic].DstReg.File = PROGRAM_TEMPORARY;
-   p->Instructions[ic].DstReg.Index = 0;
-   p->Instructions[ic].SrcReg[0].File = PROGRAM_INPUT;
-   p->Instructions[ic].SrcReg[0].Index = VARYING_SLOT_TEX0;
-   p->Instructions[ic].TexSrcUnit = samplerIndex;
-   p->Instructions[ic].TexSrcTarget = TEXTURE_2D_INDEX;
-   ic++;
-
-   /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
-   p->Instructions[ic].Opcode = OPCODE_KIL;
-   p->Instructions[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
-
-   if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM)
-      p->Instructions[ic].SrcReg[0].Swizzle = SWIZZLE_XXXX;
-
-   p->Instructions[ic].SrcReg[0].Index = 0;
-   p->Instructions[ic].SrcReg[0].Negate = NEGATE_XYZW;
-   ic++;
-
-   /* END; */
-   p->Instructions[ic++].Opcode = OPCODE_END;
-
-   assert(ic == p->NumInstructions);
-
-   p->InputsRead = VARYING_BIT_TEX0;
-   p->OutputsWritten = 0x0;
-   p->SamplersUsed = (1 << samplerIndex);
-
-   stfp = (struct st_fragment_program *) p;
-   stfp->Base.UsesKill = GL_TRUE;
-
-   return stfp;
-}
-
-
-static struct gl_program *
-make_bitmap_fragment_program_glsl(struct st_context *st,
-                                  struct st_fragment_program *orig,
-                                  GLuint samplerIndex)
-{
-   struct gl_context *ctx = st->ctx;
-   struct st_fragment_program *fp = (struct st_fragment_program *)
-      ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
-
-   if (!fp)
-      return NULL;
-   
-   get_bitmap_visitor(fp, orig->glsl_to_tgsi, samplerIndex);
-   return &fp->Base.Base;
-}
-
-
-static int
-find_free_bit(uint bitfield)
-{
-   int i;
-   for (i = 0; i < 32; i++) {
-      if ((bitfield & (1 << i)) == 0) {
-         return i;
-      }
-   }
-   return -1;
-}
-
-
-/**
- * Combine basic bitmap fragment program with the user-defined program.
- * \param st  current context
- * \param fpIn  the incoming fragment program
- * \param fpOut  the new fragment program which does fragment culling
- * \param bitmap_sampler  sampler number for the bitmap texture
- */
-void
-st_make_bitmap_fragment_program(struct st_context *st,
-                                struct gl_fragment_program *fpIn,
-                                struct gl_fragment_program **fpOut,
-                                GLuint *bitmap_sampler)
-{
-   struct st_fragment_program *bitmap_prog;
-   struct st_fragment_program *stfpIn = (struct st_fragment_program *) fpIn;
-   struct gl_program *newProg;
-   uint sampler;
-
-   /*
-    * Generate new program which is the user-defined program prefixed
-    * with the bitmap sampler/kill instructions.
-    */
-   sampler = find_free_bit(fpIn->Base.SamplersUsed);
-   
-   if (stfpIn->glsl_to_tgsi)
-      newProg = make_bitmap_fragment_program_glsl(st, stfpIn, sampler);
-   else {
-      bitmap_prog = make_bitmap_fragment_program(st->ctx, sampler);
-
-      newProg = _mesa_combine_programs(st->ctx,
-                                       &bitmap_prog->Base.Base,
-                                       &fpIn->Base);
-      /* done with this after combining */
-      st_reference_fragprog(st, &bitmap_prog, NULL);
-   }
-
-#if 0
-   {
-      printf("Combined bitmap program:\n");
-      _mesa_print_program(newProg);
-      printf("InputsRead: 0x%x\n", newProg->InputsRead);
-      printf("OutputsWritten: 0x%x\n", newProg->OutputsWritten);
-      _mesa_print_parameter_list(newProg->Parameters);
-   }
-#endif
-
-   /* return results */
-   *fpOut = (struct gl_fragment_program *) newProg;
-   *bitmap_sampler = sampler;
-}
-
-
 /**
  * Copy user-provide bitmap bits into texture buffer, expanding
  * bits into texels.
index b4254ca1eeb41dacd3be56357d204a8482fa2886..dc7e5cb5c9ead75492e38c0fe5d3423b696d6344 100644 (file)
@@ -31,6 +31,7 @@
 
 
 #include "main/compiler.h"
+#include <stdbool.h>
 
 struct dd_function_table;
 struct st_context;
@@ -46,14 +47,12 @@ st_init_bitmap(struct st_context *st);
 extern void
 st_destroy_bitmap(struct st_context *st);
 
-extern void
-st_make_bitmap_fragment_program(struct st_context *st,
-                                struct gl_fragment_program *fpIn,
-                                struct gl_fragment_program **fpOut,
-                                GLuint *bitmap_sampler);
-
 extern void
 st_flush_bitmap_cache(struct st_context *st);
 
+extern const struct tgsi_token *
+st_get_bitmap_shader(const struct tgsi_token *tokens,
+                     unsigned sampler_index,
+                     bool use_texcoord, bool swizzle_xxxx);
 
 #endif /* ST_CB_BITMAP_H */
diff --git a/src/mesa/state_tracker/st_cb_bitmap_shader.c b/src/mesa/state_tracker/st_cb_bitmap_shader.c
new file mode 100644 (file)
index 0000000..cddea36
--- /dev/null
@@ -0,0 +1,174 @@
+/**************************************************************************
+ *
+ * Copyright (C) 2015 Advanced Micro Devices, Inc.
+ * Copyright 2007 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 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 "st_cb_bitmap.h"
+#include "tgsi/tgsi_transform.h"
+#include "tgsi/tgsi_scan.h"
+#include "tgsi/tgsi_dump.h"
+#include "util/u_debug.h"
+
+struct tgsi_bitmap_transform {
+   struct tgsi_transform_context base;
+   struct tgsi_shader_info info;
+   unsigned sampler_index;
+   bool use_texcoord;
+   bool swizzle_xxxx;
+   bool first_instruction_emitted;
+};
+
+static inline struct tgsi_bitmap_transform *
+tgsi_bitmap_transform(struct tgsi_transform_context *tctx)
+{
+   return (struct tgsi_bitmap_transform *)tctx;
+}
+
+static void
+transform_instr(struct tgsi_transform_context *tctx,
+               struct tgsi_full_instruction *current_inst)
+{
+   struct tgsi_bitmap_transform *ctx = tgsi_bitmap_transform(tctx);
+   struct tgsi_full_declaration decl;
+   struct tgsi_full_instruction inst;
+   unsigned i, semantic;
+   int texcoord_index = -1;
+
+   if (ctx->first_instruction_emitted) {
+      tctx->emit_instruction(tctx, current_inst);
+      return;
+   }
+
+   ctx->first_instruction_emitted = true;
+
+   /* Add TEMP[0] if it's missing. */
+   if (ctx->info.file_max[TGSI_FILE_TEMPORARY] == -1) {
+      decl = tgsi_default_full_declaration();
+      decl.Declaration.File = TGSI_FILE_TEMPORARY;
+      tctx->emit_declaration(tctx, &decl);
+   }
+
+   /* Add TEXCOORD[0] if it's missing. */
+   semantic = ctx->use_texcoord ? TGSI_SEMANTIC_TEXCOORD :
+                                  TGSI_SEMANTIC_GENERIC;
+   for (i = 0; i < ctx->info.num_inputs; i++) {
+      if (ctx->info.input_semantic_name[i] == semantic &&
+          ctx->info.input_semantic_index[i] == 0) {
+         texcoord_index = i;
+         break;
+      }
+   }
+
+   if (texcoord_index == -1) {
+      decl = tgsi_default_full_declaration();
+      decl.Declaration.File = TGSI_FILE_INPUT;
+      decl.Declaration.Semantic = 1;
+      decl.Semantic.Name = semantic;
+      decl.Declaration.Interpolate = 1;
+      decl.Interp.Interpolate = TGSI_INTERPOLATE_PERSPECTIVE;
+      decl.Range.First = decl.Range.Last = ctx->info.num_inputs;
+      texcoord_index = ctx->info.num_inputs;
+      tctx->emit_declaration(tctx, &decl);
+   }
+
+   /* Declare the sampler. */
+   decl = tgsi_default_full_declaration();
+   decl.Declaration.File = TGSI_FILE_SAMPLER;
+   decl.Range.First = decl.Range.Last = ctx->sampler_index;
+   tctx->emit_declaration(tctx, &decl);
+
+   /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
+   inst = tgsi_default_full_instruction();
+   inst.Instruction.Opcode = TGSI_OPCODE_TEX;
+   inst.Instruction.Texture = 1;
+   inst.Texture.Texture = TGSI_TEXTURE_2D;
+
+   inst.Instruction.NumDstRegs = 1;
+   inst.Dst[0].Register.File  = TGSI_FILE_TEMPORARY;
+   inst.Dst[0].Register.Index = 0;
+   inst.Dst[0].Register.WriteMask = TGSI_WRITEMASK_XYZW;
+
+   inst.Instruction.NumSrcRegs = 2;
+   inst.Src[0].Register.File  = TGSI_FILE_INPUT;
+   inst.Src[0].Register.Index = texcoord_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_W;
+   inst.Src[1].Register.File  = TGSI_FILE_SAMPLER;
+   inst.Src[1].Register.Index = ctx->sampler_index;
+
+   tctx->emit_instruction(tctx, &inst);
+
+   /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
+   inst = tgsi_default_full_instruction();
+   inst.Instruction.Opcode = TGSI_OPCODE_KILL_IF;
+   inst.Instruction.NumDstRegs = 0;
+   inst.Instruction.NumSrcRegs = 1;
+
+   inst.Src[0].Register.File  = TGSI_FILE_TEMPORARY;
+   inst.Src[0].Register.Index = 0;
+   inst.Src[0].Register.Negate = 1;
+   inst.Src[0].Register.SwizzleX = TGSI_SWIZZLE_X;
+   if (ctx->swizzle_xxxx) {
+      inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_X;
+      inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_X;
+      inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_X;
+   } else {
+      inst.Src[0].Register.SwizzleY = TGSI_SWIZZLE_Y;
+      inst.Src[0].Register.SwizzleZ = TGSI_SWIZZLE_Z;
+      inst.Src[0].Register.SwizzleW = TGSI_SWIZZLE_W;
+   }
+   tctx->emit_instruction(tctx, &inst);
+
+   /* And emit the instruction we got. */
+   tctx->emit_instruction(tctx, current_inst);
+}
+
+const struct tgsi_token *
+st_get_bitmap_shader(const struct tgsi_token *tokens,
+                     unsigned sampler_index,
+                     bool use_texcoord, bool swizzle_xxxx)
+{
+   struct tgsi_bitmap_transform ctx;
+   struct tgsi_token *newtoks;
+   int newlen;
+
+   memset(&ctx, 0, sizeof(ctx));
+   ctx.base.transform_instruction = transform_instr;
+   ctx.sampler_index = sampler_index;
+   ctx.use_texcoord = use_texcoord;
+   ctx.swizzle_xxxx = swizzle_xxxx;
+   tgsi_scan_shader(tokens, &ctx.info);
+
+   newlen = tgsi_num_tokens(tokens) + 20;
+   newtoks = tgsi_alloc_tokens(newlen);
+   if (!newtoks)
+      return NULL;
+
+   tgsi_transform_shader(tokens, newtoks, newlen, &ctx.base);
+   return newtoks;
+}
index 1488ea07c1d8176aeef5a526eb8e27c6b8879ab8..a54ee17173af25ca34418c2732d3347dcc72a047 100644 (file)
@@ -4466,84 +4466,6 @@ get_pixel_transfer_visitor(struct st_fragment_program *fp,
    fp->glsl_to_tgsi = v;
 }
 
-/**
- * Make fragment program for glBitmap:
- *   Sample the texture and kill the fragment if the bit is 0.
- * This program will be combined with the user's fragment program.
- *
- * Based on make_bitmap_fragment_program in st_cb_bitmap.c.
- */
-extern "C" void
-get_bitmap_visitor(struct st_fragment_program *fp,
-                   glsl_to_tgsi_visitor *original, int samplerIndex)
-{
-   glsl_to_tgsi_visitor *v = new glsl_to_tgsi_visitor();
-   struct st_context *st = st_context(original->ctx);
-   struct gl_program *prog = &fp->Base.Base;
-   st_src_reg coord, src0;
-   st_dst_reg dst0;
-   glsl_to_tgsi_instruction *inst;
-
-   /* Copy attributes of the glsl_to_tgsi_visitor in the original shader. */
-   v->ctx = original->ctx;
-   v->prog = prog;
-   v->shader_program = NULL;
-   v->shader = NULL;
-   v->glsl_version = original->glsl_version;
-   v->native_integers = original->native_integers;
-   v->options = original->options;
-   v->next_temp = original->next_temp;
-   v->num_address_regs = original->num_address_regs;
-   v->samplers_used = prog->SamplersUsed = original->samplers_used;
-   v->indirect_addr_consts = original->indirect_addr_consts;
-   memcpy(&v->immediates, &original->immediates, sizeof(v->immediates));
-   v->num_immediates = original->num_immediates;
-
-   /* TEX tmp0, fragment.texcoord[0], texture[0], 2D; */
-   coord = st_src_reg(PROGRAM_INPUT, VARYING_SLOT_TEX0, glsl_type::vec2_type);
-   src0 = v->get_temp(glsl_type::vec4_type);
-   dst0 = st_dst_reg(src0);
-   inst = v->emit_asm(NULL, TGSI_OPCODE_TEX, dst0, coord);
-   inst->sampler.index = samplerIndex;
-   inst->sampler_array_size = 1;
-   inst->tex_target = TEXTURE_2D_INDEX;
-
-   prog->InputsRead |= VARYING_BIT_TEX0;
-   prog->SamplersUsed |= (1 << samplerIndex); /* mark sampler as used */
-   v->samplers_used |= (1 << samplerIndex);
-
-   /* KIL if -tmp0 < 0 # texel=0 -> keep / texel=0 -> discard */
-   src0.negate = NEGATE_XYZW;
-   if (st->bitmap.tex_format == PIPE_FORMAT_L8_UNORM)
-      src0.swizzle = SWIZZLE_XXXX;
-   inst = v->emit_asm(NULL, TGSI_OPCODE_KILL_IF, undef_dst, src0);
-
-   /* Now copy the instructions from the original glsl_to_tgsi_visitor into the
-    * new visitor. */
-   foreach_in_list(glsl_to_tgsi_instruction, inst, &original->instructions) {
-      glsl_to_tgsi_instruction *newinst;
-      st_src_reg src_regs[4];
-
-      if (inst->dst[0].file == PROGRAM_OUTPUT)
-         prog->OutputsWritten |= BITFIELD64_BIT(inst->dst[0].index);
-
-      for (int i = 0; i < 4; i++) {
-         src_regs[i] = inst->src[i];
-         if (src_regs[i].file == PROGRAM_INPUT)
-            prog->InputsRead |= BITFIELD64_BIT(src_regs[i].index);
-      }
-
-      newinst = v->emit_asm(NULL, inst->op, inst->dst[0], src_regs[0], src_regs[1], src_regs[2], src_regs[3]);
-      newinst->tex_target = inst->tex_target;
-      newinst->sampler_array_size = inst->sampler_array_size;
-   }
-
-   /* Make modifications to fragment program info. */
-   prog->Parameters = _mesa_clone_parameter_list(original->prog->Parameters);
-   count_resources(v, prog);
-   fp->glsl_to_tgsi = v;
-}
-
 /* ------------------------- TGSI conversion stuff -------------------------- */
 struct label {
    unsigned branch_target;
index c29fc768e49bb4ca8a7386edc936b31be4ca541f..dcdfbebcbdc612dc9ecd4ae8c61fe957f90ea870 100644 (file)
@@ -58,9 +58,6 @@ void free_glsl_to_tgsi_visitor(struct glsl_to_tgsi_visitor *v);
 void get_pixel_transfer_visitor(struct st_fragment_program *fp,
                                 struct glsl_to_tgsi_visitor *original,
                                 int scale_and_bias, int pixel_maps);
-void get_bitmap_visitor(struct st_fragment_program *fp,
-                        struct glsl_to_tgsi_visitor *original,
-                        int samplerIndex);
 
 GLboolean st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);
 
index 7a6720cee7c4e2ea69bbb454a1b0f7dbc3ef5e14..fba661b5405bcabab80034487292bb5c304fa3a2 100644 (file)
@@ -567,18 +567,7 @@ st_translate_fragment_program(struct st_context *st,
    assert(!(key->bitmap && key->drawpixels));
    memset(inputSlotToAttr, ~0, sizeof(inputSlotToAttr));
 
-   if (key->bitmap) {
-      /* glBitmap drawing */
-      struct gl_fragment_program *fp; /* we free this temp program below */
-
-      st_make_bitmap_fragment_program(st, &stfp->Base,
-                                      &fp, &variant->bitmap_sampler);
-
-      variant->parameters = _mesa_clone_parameter_list(fp->Base.Parameters);
-      stfp = st_fragment_program(fp);
-      deleteFP = GL_TRUE;
-   }
-   else if (key->drawpixels) {
+   if (key->drawpixels) {
       /* glDrawPixels drawing */
       struct gl_fragment_program *fp; /* we free this temp program below */
 
@@ -892,6 +881,27 @@ st_translate_fragment_program(struct st_context *st,
          fprintf(stderr, "mesa: cannot emulate deprecated features\n");
    }
 
+   /* glBitmap */
+   if (key->bitmap) {
+      const struct tgsi_token *tokens;
+
+      variant->bitmap_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1;
+
+      tokens = st_get_bitmap_shader(variant->tgsi.tokens,
+                                    variant->bitmap_sampler,
+                                    st->needs_texcoord_semantic,
+                                    st->bitmap.tex_format ==
+                                    PIPE_FORMAT_L8_UNORM);
+
+      if (tokens) {
+         tgsi_free_tokens(variant->tgsi.tokens);
+         variant->tgsi.tokens = tokens;
+         variant->parameters =
+            _mesa_clone_parameter_list(stfp->Base.Base.Parameters);
+      } else
+         fprintf(stderr, "mesa: cannot create a shader for glBitmap\n");
+   }
+
    if (ST_DEBUG & DEBUG_TGSI) {
       tgsi_dump(variant->tgsi.tokens, 0/*TGSI_DUMP_VERBOSE*/);
       debug_printf("\n");