gallium: implement RGBA pixel maps in the pixel transfer fragment program
authorBrian Paul <brian.paul@tungstengraphics.com>
Wed, 16 Apr 2008 22:52:12 +0000 (16:52 -0600)
committerBrian Paul <brian.paul@tungstengraphics.com>
Wed, 16 Apr 2008 22:53:44 +0000 (16:53 -0600)
src/mesa/state_tracker/st_atom_pixeltransfer.c
src/mesa/state_tracker/st_cb_drawpixels.c
src/mesa/state_tracker/st_context.h

index efb92b7..76356bb 100644 (file)
 #include "shader/prog_print.h"
 
 #include "st_context.h"
+#include "st_format.h"
 #include "st_program.h"
+#include "st_texture.h"
 
+#include "pipe/p_screen.h"
+#include "pipe/p_context.h"
+#include "pipe/p_inlines.h"
+#include "util/u_pack_color.h"
 
 
 struct state_key
@@ -51,6 +57,7 @@ struct state_key
    GLuint scaleAndBias:1;
    GLuint colorMatrix:1;
    GLuint colorMatrixPostScaleBias:1;
+   GLuint pixelMaps:1;
 
 #if 0
    GLfloat Maps[3][256][4];
@@ -101,6 +108,69 @@ make_state_key(GLcontext *ctx,  struct state_key *key)
        !TEST_EQ_4V(ctx->Pixel.PostColorMatrixBias, zero)) {
       key->colorMatrixPostScaleBias = 1;
    }
+
+   key->pixelMaps = ctx->Pixel.MapColorFlag;
+}
+
+
+static struct pipe_texture *
+create_color_map_texture(GLcontext *ctx)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct pipe_texture *pt;
+   enum pipe_format format;
+   const uint texSize = 256; /* simple, and usually perfect */
+
+   /* find an RGBA texture format */
+   format = st_choose_format(pipe, GL_RGBA, PIPE_TEXTURE);
+
+   /* create texture for color map/table */
+   pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, 0,
+                          texSize, texSize, 1, 0);
+   return pt;
+}
+
+
+/**
+ * Update the pixelmap texture with the contents of the R/G/B/A pixel maps.
+ */
+static void
+load_color_map_texture(GLcontext *ctx, struct pipe_texture *pt)
+{
+   struct pipe_context *pipe = ctx->st->pipe;
+   struct pipe_screen *screen = pipe->screen;
+   struct pipe_surface *surface;
+   const GLuint rSize = ctx->PixelMaps.RtoR.Size;
+   const GLuint gSize = ctx->PixelMaps.GtoG.Size;
+   const GLuint bSize = ctx->PixelMaps.BtoB.Size;
+   const GLuint aSize = ctx->PixelMaps.AtoA.Size;
+   const uint texSize = pt->width[0];
+   uint *dest;
+   uint i, j;
+
+   surface = screen->get_tex_surface(screen, pt, 0, 0, 0);
+   dest = (uint *) pipe_surface_map(surface);
+
+   /* Pack four 1D maps into a 2D texture:
+    * R map is placed horizontally, indexed by S, in channel 0
+    * G map is placed vertically, indexed by T, in channel 1
+    * B map is placed horizontally, indexed by S, in channel 2
+    * A map is placed vertically, indexed by T, in channel 3
+    */
+   for (i = 0; i < texSize; i++) {
+      for (j = 0; j < texSize; j++) {
+         int k = (i * texSize + j);
+         ubyte r = ctx->PixelMaps.RtoR.Map8[j * rSize / texSize];
+         ubyte g = ctx->PixelMaps.GtoG.Map8[i * gSize / texSize];
+         ubyte b = ctx->PixelMaps.BtoB.Map8[j * bSize / texSize];
+         ubyte a = ctx->PixelMaps.AtoA.Map8[i * aSize / texSize];
+         util_pack_color_ub(r, g, b, a, pt->format, dest + k);
+      }
+   }
+
+   pipe_surface_unmap(surface);
+   pipe_surface_reference(&surface, NULL);
+   pipe->texture_update(pipe, pt, 0, 0x1);
 }
 
 
@@ -113,6 +183,7 @@ make_state_key(GLcontext *ctx,  struct state_key *key)
 static struct gl_fragment_program *
 get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
 {
+   struct st_context *st = ctx->st;
    struct prog_instruction inst[MAX_INST];
    struct gl_program_parameter_list *params;
    struct gl_fragment_program *fp;
@@ -126,7 +197,10 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
 
    params = _mesa_new_parameter_list();
 
-   /* TEX colorTemp, fragment.texcoord[0], texture[0], 2D; */
+   /*
+    * Get initial pixel color from the texture.
+    * TEX colorTemp, fragment.texcoord[0], texture[0], 2D;
+    */
    _mesa_init_instructions(inst + ic, 1);
    inst[ic].Opcode = OPCODE_TEX;
    inst[ic].DstReg.File = PROGRAM_TEMPORARY;
@@ -140,7 +214,6 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
    fp->Base.OutputsWritten = (1 << FRAG_RESULT_COLR);
    fp->Base.SamplersUsed = 0x1;  /* sampler 0 (bit 0) is used */
 
-   /* MAD colorTemp, colorTemp, scale, bias; */
    if (key->scaleAndBias) {
       static const gl_state_index scale_state[STATE_LENGTH] =
          { STATE_INTERNAL, STATE_PT_SCALE, 0, 0, 0 };
@@ -161,6 +234,7 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
       scale_p = _mesa_add_state_reference(params, scale_state);
       bias_p = _mesa_add_state_reference(params, bias_state);
 
+      /* MAD colorTemp, colorTemp, scale, bias; */
       _mesa_init_instructions(inst + ic, 1);
       inst[ic].Opcode = OPCODE_MAD;
       inst[ic].DstReg.File = PROGRAM_TEMPORARY;
@@ -174,6 +248,56 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
       ic++;
    }
 
+   if (key->pixelMaps) {
+      const GLuint temp = 1;
+
+      /* create the colormap/texture now if not already done */
+      if (!st->pixel_xfer.pixelmap_texture) {
+         st->pixel_xfer.pixelmap_texture = create_color_map_texture(ctx);
+      }
+
+      /* with a little effort, we can do four pixel map look-ups with
+       * two TEX instructions:
+       */
+
+      /* TEX temp.rg, colorTemp.rgba, texture[1], 2D; */
+      _mesa_init_instructions(inst + ic, 1);
+      inst[ic].Opcode = OPCODE_TEX;
+      inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+      inst[ic].DstReg.Index = temp;
+      inst[ic].DstReg.WriteMask = WRITEMASK_XY; /* write R,G */
+      inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+      inst[ic].SrcReg[0].Index = colorTemp;
+      inst[ic].TexSrcUnit = 1;
+      inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
+      ic++;
+
+      /* TEX temp.ba, colorTemp.baba, texture[1], 2D; */
+      _mesa_init_instructions(inst + ic, 1);
+      inst[ic].Opcode = OPCODE_TEX;
+      inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+      inst[ic].DstReg.Index = temp;
+      inst[ic].DstReg.WriteMask = WRITEMASK_ZW; /* write B,A */
+      inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+      inst[ic].SrcReg[0].Index = colorTemp;
+      inst[ic].SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W,
+                                                 SWIZZLE_Z, SWIZZLE_W);
+      inst[ic].TexSrcUnit = 1;
+      inst[ic].TexSrcTarget = TEXTURE_2D_INDEX;
+      ic++;
+
+      /* MOV colorTemp, temp; */
+      _mesa_init_instructions(inst + ic, 1);
+      inst[ic].Opcode = OPCODE_MOV;
+      inst[ic].DstReg.File = PROGRAM_TEMPORARY;
+      inst[ic].DstReg.Index = colorTemp;
+      inst[ic].SrcReg[0].File = PROGRAM_TEMPORARY;
+      inst[ic].SrcReg[0].Index = temp;
+      ic++;
+
+      fp->Base.SamplersUsed |= (1 << 1);  /* sampler 1 is used */
+   }
+
    if (key->colorMatrix) {
       static const gl_state_index row0_state[STATE_LENGTH] =
          { STATE_COLOR_MATRIX, 0, 0, 0, 0 };
@@ -190,8 +314,6 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
       GLint row3_p = _mesa_add_state_reference(params, row3_state);
       const GLuint temp = 1;
 
-      /* XXX reimplement in terms of MUL/MAD (see t_vp_build.c) */
-
       /* DP4 temp.x, colorTemp, matrow0; */
       _mesa_init_instructions(inst + ic, 1);
       inst[ic].Opcode = OPCODE_DP4;
@@ -316,6 +438,7 @@ get_pixel_transfer_program(GLcontext *ctx, const struct state_key *key)
 static void
 update_pixel_transfer(struct st_context *st)
 {
+   GLcontext *ctx = st->ctx;
    struct state_key key;
    struct gl_fragment_program *fp;
 
@@ -329,6 +452,11 @@ update_pixel_transfer(struct st_context *st)
                                  &key, sizeof(key), &fp->Base);
    }
 
+   if (ctx->Pixel.MapColorFlag) {
+      load_color_map_texture(ctx, st->pixel_xfer.pixelmap_texture);
+   }
+   st->pixel_xfer.pixelmap_enabled = ctx->Pixel.MapColorFlag;
+
    st->pixel_xfer.program = (struct st_fragment_program *) fp;
 }
 
index 5f8c90c..67f468c 100644 (file)
@@ -562,6 +562,9 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
       sampler.normalized_coords = 1;
 
       cso_single_sampler(cso, 0, &sampler);
+      if (st->pixel_xfer.pixelmap_enabled) {
+         cso_single_sampler(cso, 1, &sampler);
+      }
       cso_single_sampler_done(cso);
    }
 
@@ -582,7 +585,15 @@ draw_textured_quad(GLcontext *ctx, GLint x, GLint y, GLfloat z,
    }
 
    /* texture state: */
-   pipe->set_sampler_textures(pipe, 1, &pt);
+   if (st->pixel_xfer.pixelmap_enabled) {
+      struct pipe_texture *textures[2];
+      textures[0] = pt;
+      textures[1] = st->pixel_xfer.pixelmap_texture;
+      pipe->set_sampler_textures(pipe, 2, textures);
+   }
+   else {
+      pipe->set_sampler_textures(pipe, 1, &pt);
+   }
 
    /* Compute window coords (y=0=bottom) with pixel zoom.
     * Recall that these coords are transformed by the current
index d89e54c..ae1ba41 100644 (file)
@@ -138,6 +138,8 @@ struct st_context
       GLuint user_prog_sn;  /**< user fragment program serial no. */
       struct st_fragment_program *combined_prog;
       GLuint combined_prog_sn;
+      struct pipe_texture *pixelmap_texture;
+      boolean pixelmap_enabled;  /**< use the pixelmap texture? */
    } pixel_xfer;
 
    /** for glBitmap */