Cell: basic texture mapping
authorBrian <brian.paul@tungstengraphics.com>
Tue, 29 Jan 2008 00:23:44 +0000 (17:23 -0700)
committerBen Skeggs <skeggsb@gmail.com>
Fri, 15 Feb 2008 02:50:24 +0000 (13:50 +1100)
Texture images are tiled in PPU code.  SPUs use a texture cache for getting
texels from textures.
This is very rough code, but demos/texcyl.c works.

src/mesa/pipe/cell/common.h
src/mesa/pipe/cell/ppu/cell_context.h
src/mesa/pipe/cell/ppu/cell_state_emit.c
src/mesa/pipe/cell/ppu/cell_state_sampler.c
src/mesa/pipe/cell/ppu/cell_texture.c
src/mesa/pipe/cell/ppu/cell_texture.h
src/mesa/pipe/cell/spu/Makefile
src/mesa/pipe/cell/spu/spu_main.c
src/mesa/pipe/cell/spu/spu_main.h
src/mesa/pipe/cell/spu/spu_tri.c

index 5e32b20..f0d48ff 100644 (file)
@@ -79,7 +79,8 @@
 #define CELL_CMD_STATE_FRAMEBUFFER   10
 #define CELL_CMD_STATE_DEPTH_STENCIL 11
 #define CELL_CMD_STATE_SAMPLER       12
-#define CELL_CMD_STATE_VERTEX_INFO   13
+#define CELL_CMD_STATE_TEXTURE       13
+#define CELL_CMD_STATE_VERTEX_INFO   14
 
 
 #define CELL_NUM_BUFFERS 4
@@ -134,6 +135,13 @@ struct cell_command_release_verts
 };
 
 
+struct cell_command_texture
+{
+   void *start;         /**< Address in main memory */
+   uint width, height;
+};
+
+
 /** XXX unions don't seem to work */
 struct cell_command
 {
index de65fb5..7d234f3 100644 (file)
@@ -76,7 +76,7 @@ struct cell_context
    struct pipe_framebuffer_state framebuffer;
    struct pipe_poly_stipple poly_stipple;
    struct pipe_scissor_state scissor;
-   struct pipe_texture *texture[PIPE_MAX_SAMPLERS];
+   struct cell_texture *texture[PIPE_MAX_SAMPLERS];
    struct pipe_viewport_state viewport;
    struct pipe_vertex_buffer vertex_buffer[PIPE_ATTRIB_MAX];
    struct pipe_vertex_element vertex_element[PIPE_ATTRIB_MAX];
@@ -84,6 +84,9 @@ struct cell_context
    ubyte *cbuf_map[PIPE_MAX_COLOR_BUFS];
    ubyte *zsbuf_map;
 
+   struct pipe_surface *tex_surf;
+   uint *tex_map;
+
    uint dirty;
 
    /** The primitive drawing context */
index 6776ec8..391ff45 100644 (file)
@@ -30,7 +30,7 @@
 #include "cell_state.h"
 #include "cell_state_emit.h"
 #include "cell_batch.h"
-
+#include "cell_texture.h"
 
 
 static void
@@ -72,6 +72,16 @@ cell_emit_state(struct cell_context *cell)
                      cell->sampler[0], sizeof(struct pipe_sampler_state));
    }
 
+   if (cell->dirty & CELL_NEW_TEXTURE) {
+      struct cell_command_texture texture;
+      texture.start = cell->texture[0]->tiled_data;
+      texture.width = cell->texture[0]->base.width[0];
+      texture.height = cell->texture[0]->base.height[0];
+
+      emit_state_cmd(cell, CELL_CMD_STATE_TEXTURE,
+                     &texture, sizeof(struct cell_command_texture));
+   }
+
    if (cell->dirty & CELL_NEW_VERTEX_INFO) {
       emit_state_cmd(cell, CELL_CMD_STATE_VERTEX_INFO,
                      &cell->vertex_info, sizeof(struct vertex_info));
index ae1eeb4..317f760 100644 (file)
  */
 
 #include "pipe/p_util.h"
+#include "pipe/draw/draw_context.h"
 #include "cell_context.h"
 #include "cell_state.h"
-#if 0
 #include "cell_texture.h"
-#include "cell_tile_cache.h"
-#endif
 
 
 void *
@@ -53,6 +51,8 @@ cell_bind_sampler_state(struct pipe_context *pipe,
 {
    struct cell_context *cell = cell_context(pipe);
 
+   draw_flush(cell->draw);
+
    assert(unit < PIPE_MAX_SAMPLERS);
    cell->sampler[unit] = (struct pipe_sampler_state *)sampler;
 
@@ -76,7 +76,11 @@ cell_set_sampler_texture(struct pipe_context *pipe,
 {
    struct cell_context *cell = cell_context(pipe);
 
+   draw_flush(cell->draw);
+
    cell->texture[sampler] = texture;
 
+   cell_update_texture_mapping(cell);
+
    cell->dirty |= CELL_NEW_TEXTURE;
 }
index 0a8190d..acbe4c7 100644 (file)
@@ -163,3 +163,90 @@ cell_get_tex_surface(struct pipe_context *pipe,
    }
    return ps;
 }
+
+
+
+static void
+tile_copy_data(uint w, uint h, uint tile_size, uint *dst, const uint *src)
+{
+   const uint tile_size2 = tile_size * tile_size;
+   const uint h_t = h / tile_size, w_t = w / tile_size;
+
+   uint it, jt;  /* tile counters */
+   uint i, j;    /* intra-tile counters */
+
+   for (it = 0; it < h_t; it++) {
+      for (jt = 0; jt < w_t; jt++) {
+         /* fill in tile (i, j) */
+         uint *tdst = dst + (it * w_t + jt) * tile_size2;
+         for (i = 0; i < tile_size; i++) {
+            for (j = 0; j < tile_size; j++) {
+               const uint srci = it * tile_size + i;
+               const uint srcj = jt * tile_size + j;
+               *tdst++ = src[srci * h + srcj];
+            }
+         }
+      }
+   }
+}
+
+
+
+/**
+ * Convert linear texture image data to tiled format for SPU usage.
+ */
+static void
+cell_tile_texture(struct cell_context *cell,
+                  struct cell_texture *texture)
+{
+   uint face = 0, level = 0, zslice = 0;
+   struct pipe_surface *surf;
+   const uint w = texture->base.width[0], h = texture->base.height[0];
+   const uint *src;
+
+   /* temporary restrictions: */
+   assert(w >= TILE_SIZE);
+   assert(h >= TILE_SIZE);
+   assert(w % TILE_SIZE == 0);
+   assert(h % TILE_SIZE == 0);
+
+   surf = cell_get_tex_surface(&cell->pipe, &texture->base, face, level, zslice);
+   ASSERT(surf);
+
+   src = (const uint *) pipe_surface_map(surf);
+
+   if (texture->tiled_data) {
+      align_free(texture->tiled_data);
+   }
+   texture->tiled_data = align_malloc(w * h * 4, 16);
+
+   tile_copy_data(w, h, TILE_SIZE, texture->tiled_data, src);
+
+   pipe_surface_unmap(surf);
+
+   pipe_surface_reference(&surf, NULL);
+}
+
+
+
+void
+cell_update_texture_mapping(struct cell_context *cell)
+{
+   uint face = 0, level = 0, zslice = 0;
+
+   cell_tile_texture(cell, cell->texture[0]);
+#if 0
+   if (cell->tex_surf && cell->tex_map) {
+      pipe_surface_unmap(cell->tex_surf);
+      cell->tex_map = NULL;
+   }
+
+   /* XXX free old surface */
+
+   cell->tex_surf = cell_get_tex_surface(&cell->pipe,
+                                         &cell->texture[0]->base,
+                                         face, level, zslice);
+
+   cell->tex_map = pipe_surface_map(cell->tex_surf);
+#endif
+}
index ef5808c..bd434c8 100644 (file)
@@ -46,6 +46,8 @@ struct cell_texture
     */
    struct pipe_buffer *buffer;
    unsigned long buffer_size;
+
+   void *tiled_data;  /* XXX this may be temporary */ /*ALIGN16*/
 };
 
 
@@ -70,4 +72,8 @@ cell_get_tex_surface(struct pipe_context *pipe,
                      unsigned face, unsigned level, unsigned zslice);
 
 
+extern void
+cell_update_texture_mapping(struct cell_context *cell);
+
+
 #endif /* CELL_TEXTURE */
index 417ae1b..011fdce 100644 (file)
@@ -17,6 +17,7 @@ PROG_SPU_EMBED_O = $(PROG)_spu-embed.o
 
 SOURCES = \
        spu_main.c \
+       spu_texture.c \
        spu_tile.c \
        spu_tri.c
 
index c2b05ed..5a5b17d 100644 (file)
@@ -34,6 +34,7 @@
 #include <spu_mfcio.h>
 
 #include "spu_main.h"
+#include "spu_texture.h"
 #include "spu_tri.h"
 #include "spu_tile.h"
 #include "pipe/cell/common.h"
@@ -447,6 +448,17 @@ cmd_state_sampler(const struct pipe_sampler_state *state)
 
 
 static void
+cmd_state_texture(const struct cell_command_texture *texture)
+{
+   if (Debug)
+      printf("SPU %u: TEXTURE at %p  size %u x %u\n",
+             spu.init.id, texture->start, texture->width, texture->height);
+
+   memcpy(&spu.texture, texture, sizeof(*texture));
+}
+
+
+static void
 cmd_state_vertex_info(const struct vertex_info *vinfo)
 {
    if (Debug) {
@@ -561,6 +573,10 @@ cmd_batch(uint opcode)
          cmd_state_sampler((struct pipe_sampler_state *) &buffer[pos+1]);
          pos += (1 + sizeof(struct pipe_sampler_state) / 4);
          break;
+      case CELL_CMD_STATE_TEXTURE:
+         cmd_state_texture((struct cell_command_texture *) &buffer[pos+1]);
+         pos += (1 + sizeof(struct cell_command_texture) / 4);
+         break;
       case CELL_CMD_STATE_VERTEX_INFO:
          cmd_state_vertex_info((struct vertex_info *) &buffer[pos+1]);
          pos += (1 + sizeof(struct vertex_info) / 4);
@@ -656,6 +672,7 @@ one_time_init(void)
 {
    memset(tile_status, TILE_STATUS_DEFINED, sizeof(tile_status));
    memset(tile_status_z, TILE_STATUS_DEFINED, sizeof(tile_status_z));
+   invalidate_tex_cache();
 }
 
 
index 5bc5d9f..480c54e 100644 (file)
@@ -60,6 +60,7 @@ struct spu_global
    struct pipe_depth_stencil_alpha_state depth_stencil;
    struct pipe_blend_state blend;
    struct pipe_sampler_state sampler[PIPE_MAX_SAMPLERS];
+   struct cell_command_texture texture;
 
    struct vertex_info vertex_info;
 
@@ -84,6 +85,8 @@ extern struct spu_global spu;
 #define TAG_INDEX_BUFFER      16
 #define TAG_BATCH_BUFFER      17
 #define TAG_MISC              18
+#define TAG_TEXTURE_TILE      19
+
 
 
 extern void
index 3d0d106..aad28f1 100644 (file)
@@ -33,6 +33,7 @@
 #include "pipe/p_format.h"
 #include "pipe/p_util.h"
 #include "spu_main.h"
+#include "spu_texture.h"
 #include "spu_tile.h"
 #include "spu_tri.h"
 
@@ -362,9 +363,24 @@ emit_quad( struct setup_stage *setup, int x, int y, unsigned mask )
    /* Cell: "write" quad fragments to the tile by setting prim color */
    const int ix = x - setup->cliprect_minx;
    const int iy = y - setup->cliprect_miny;
-   float colors[4][4];
-
-   eval_coeff(setup, 1, (float) x, (float) y, colors);
+   uint colors[4];  /* indexed by QUAD_x */
+
+   if (spu.texture.start) {
+      float texcoords[4][4];
+      uint i;
+      eval_coeff(setup, 2, (float) x, (float) y, texcoords);
+      for (i = 0; i < 4; i++) {
+         colors[i] = sample_texture(texcoords[i]);
+      }
+   }
+   else {
+      float fcolors[4][4];
+      eval_coeff(setup, 1, (float) x, (float) y, fcolors);
+      colors[QUAD_TOP_LEFT] = pack_color(fcolors[QUAD_TOP_LEFT]);
+      colors[QUAD_TOP_RIGHT] = pack_color(fcolors[QUAD_TOP_RIGHT]);
+      colors[QUAD_BOTTOM_LEFT] = pack_color(fcolors[QUAD_BOTTOM_LEFT]);
+      colors[QUAD_BOTTOM_RIGHT] = pack_color(fcolors[QUAD_BOTTOM_RIGHT]);
+   }
 
    if (spu.depth_stencil.depth.enabled) {
       mask &= do_depth_test(setup, x, y, mask);
@@ -382,13 +398,13 @@ emit_quad( struct setup_stage *setup, int x, int y, unsigned mask )
       tile_status[setup->ty][setup->tx] = TILE_STATUS_DIRTY;
 
       if (mask & MASK_TOP_LEFT)
-         ctile.t32[iy][ix] = pack_color(colors[QUAD_TOP_LEFT]);
+         ctile.t32[iy][ix] = colors[QUAD_TOP_LEFT];
       if (mask & MASK_TOP_RIGHT)
-         ctile.t32[iy][ix+1] = pack_color(colors[QUAD_TOP_RIGHT]);
+         ctile.t32[iy][ix+1] = colors[QUAD_TOP_RIGHT];
       if (mask & MASK_BOTTOM_LEFT)
-         ctile.t32[iy+1][ix] = pack_color(colors[QUAD_BOTTOM_LEFT]);
+         ctile.t32[iy+1][ix] = colors[QUAD_BOTTOM_LEFT];
       if (mask & MASK_BOTTOM_RIGHT)
-         ctile.t32[iy+1][ix+1] = pack_color(colors[QUAD_BOTTOM_RIGHT]);
+         ctile.t32[iy+1][ix+1] = colors[QUAD_BOTTOM_RIGHT];
    }
 #endif
 }
@@ -606,7 +622,6 @@ static boolean setup_sort_vertices( struct setup_stage *setup,
 }
 
 
-#if 0
 /**
  * Compute a0 for a constant-valued coefficient (GL_FLAT shading).
  * The value value comes from vertex->data[slot][i].
@@ -614,21 +629,20 @@ static boolean setup_sort_vertices( struct setup_stage *setup,
  * \param slot  which attribute slot 
  * \param i  which component of the slot (0..3)
  */
-static void const_coeff( struct setup_stage *setup,
-                        unsigned slot,
-                        unsigned i )
+static void const_coeff(struct setup_stage *setup, uint slot)
 {
-   assert(slot < PIPE_MAX_SHADER_INPUTS);
-   assert(i <= 3);
+   uint i;
+   ASSERT(slot < PIPE_MAX_SHADER_INPUTS);
 
-   setup->coef[slot].dadx[i] = 0;
-   setup->coef[slot].dady[i] = 0;
+   for (i = 0; i < 4; i++) {
+      setup->coef[slot].dadx[i] = 0;
+      setup->coef[slot].dady[i] = 0;
 
-   /* need provoking vertex info!
-    */
-   setup->coef[slot].a0[i] = setup->vprovoke->data[slot][i];
+      /* need provoking vertex info!
+       */
+      setup->coef[slot].a0[i] = setup->vprovoke->data[slot][i];
+   }
 }
-#endif
 
 
 /**
@@ -735,15 +749,17 @@ static void setup_tri_coefficients( struct setup_stage *setup )
       case INTERP_NONE:
          break;
       case INTERP_POS:
-         tri_linear_coeff(setup, i, 2, 3);  /* slot 0, z */
+         tri_linear_coeff(setup, i, 2, 3);
          /* XXX interp W if PERSPECTIVE... */
          break;
       case INTERP_CONSTANT:
-         /* fall-through */
+         const_coeff(setup, i);
+         break;
       case INTERP_LINEAR:
-         tri_linear_coeff(setup, i, 0, 4);  /* slot 1, color */
+         tri_linear_coeff(setup, i, 0, 4);
          break;
       case INTERP_PERSPECTIVE:
+         tri_linear_coeff(setup, i, 0, 4); /* XXX temporary */
          break;
       default:
          ASSERT(0);