diff options
Diffstat (limited to 'src/mesa')
| -rw-r--r-- | src/mesa/pipe/cell/spu/Makefile | 19 | ||||
| -rw-r--r-- | src/mesa/pipe/cell/spu/spu_main.c | 553 | ||||
| -rw-r--r-- | src/mesa/pipe/cell/spu/spu_main.h | 78 | ||||
| -rw-r--r-- | src/mesa/pipe/cell/spu/spu_tile.c | 115 | ||||
| -rw-r--r-- | src/mesa/pipe/cell/spu/spu_tile.h | 69 | ||||
| -rw-r--r-- | src/mesa/pipe/cell/spu/spu_tri.c | 892 | ||||
| -rw-r--r-- | src/mesa/pipe/cell/spu/spu_tri.h | 37 | 
7 files changed, 1751 insertions, 12 deletions
diff --git a/src/mesa/pipe/cell/spu/Makefile b/src/mesa/pipe/cell/spu/Makefile index bf97a49e78..b92a756cd5 100644 --- a/src/mesa/pipe/cell/spu/Makefile +++ b/src/mesa/pipe/cell/spu/Makefile @@ -16,15 +16,19 @@ PROG_SPU_EMBED_O = $(PROG)_spu-embed.o  SOURCES = \ -	main.c \ -	tile.c \ -	tri.c +	spu_main.c \ +	spu_tile.c \ +	spu_tri.c  SPU_OBJECTS = $(SOURCES:.c=.o) \  INCLUDE_DIRS = -I$(TOP)/src/mesa +.c.o: +	$(SPU_CC) $(SPU_CFLAGS) -c $< + +  # The .a file will be linked into the main/PPU executable  default: $(PROG_SPU_A) @@ -38,15 +42,6 @@ $(PROG_SPU): $(SPU_OBJECTS)  	$(SPU_CC) -o $(PROG_SPU) $(SPU_OBJECTS) $(SPU_LFLAGS) -main.o: main.c -	$(SPU_CC) $(SPU_CFLAGS) -c main.c - -tile.o: tile.c -	$(SPU_CC) $(SPU_CFLAGS) -c tile.c - -tri.o: tri.c -	$(SPU_CC) $(SPU_CFLAGS) -c tri.c -  clean:  	rm -f *~ *.o *.a *.d $(PROG_SPU) diff --git a/src/mesa/pipe/cell/spu/spu_main.c b/src/mesa/pipe/cell/spu/spu_main.c new file mode 100644 index 0000000000..df708e65d1 --- /dev/null +++ b/src/mesa/pipe/cell/spu/spu_main.c @@ -0,0 +1,553 @@ +/************************************************************************** + *  + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + *  + **************************************************************************/ + + +/* main() for Cell SPU code */ + + +#include <stdio.h> +#include <libmisc.h> +#include <spu_mfcio.h> + +#include "spu_main.h" +#include "spu_tri.h" +#include "spu_tile.h" +#include "pipe/cell/common.h" +#include "pipe/p_defines.h" + +/* +helpful headers: +/usr/lib/gcc/spu/4.1.1/include/spu_mfcio.h +/opt/ibm/cell-sdk/prototype/sysroot/usr/include/libmisc.h +*/ + +static boolean Debug = FALSE; + +volatile struct cell_init_info init; + +struct framebuffer fb; + + + +void +wait_on_mask(unsigned tagMask) +{ +   mfc_write_tag_mask( tagMask ); +   /* wait for completion of _any_ DMAs specified by tagMask */ +   mfc_read_tag_status_any(); +} + + +static void +wait_on_mask_all(unsigned tagMask) +{ +   mfc_write_tag_mask( tagMask ); +   /* wait for completion of _any_ DMAs specified by tagMask */ +   mfc_read_tag_status_all(); +} + + + +/** + * For tiles whose status is TILE_STATUS_CLEAR, write solid-filled + * tiles back to the main framebuffer. + */ +static void +really_clear_tiles(uint surfaceIndex) +{ +   const uint num_tiles = fb.width_tiles * fb.height_tiles; +   uint i, j; + +   if (surfaceIndex == 0) { +      for (i = 0; i < TILE_SIZE; i++) +         for (j = 0; j < TILE_SIZE; j++) +            ctile[i][j] = fb.color_clear_value; + +      for (i = init.id; i < num_tiles; i += init.num_spus) { +         uint tx = i % fb.width_tiles; +         uint ty = i / fb.width_tiles; +         if (tile_status[ty][tx] == TILE_STATUS_CLEAR) { +            put_tile(&fb, tx, ty, (uint *) ctile, TAG_SURFACE_CLEAR, 0); +         } +      } +   } +   else { +      for (i = 0; i < TILE_SIZE; i++) +         for (j = 0; j < TILE_SIZE; j++) +            ztile[i][j] = fb.depth_clear_value; + +      for (i = init.id; i < num_tiles; i += init.num_spus) { +         uint tx = i % fb.width_tiles; +         uint ty = i / fb.width_tiles; +         if (tile_status_z[ty][tx] == TILE_STATUS_CLEAR) +            put_tile(&fb, tx, ty, (uint *) ctile, TAG_SURFACE_CLEAR, 1); +      } +   } + +#if 0 +   wait_on_mask(1 << TAG_SURFACE_CLEAR); +#endif +} + + +static void +cmd_clear_surface(const struct cell_command_clear_surface *clear) +{ +   const uint num_tiles = fb.width_tiles * fb.height_tiles; +   uint i, j; + +   if (Debug) +      printf("SPU %u: CLEAR SURF %u to 0x%08x\n", init.id, +             clear->surface, clear->value); + +#define CLEAR_OPT 1 +#if CLEAR_OPT +   /* set all tile's status to CLEAR */ +   if (clear->surface == 0) { +      memset(tile_status, TILE_STATUS_CLEAR, sizeof(tile_status)); +      fb.color_clear_value = clear->value; +   } +   else { +      memset(tile_status_z, TILE_STATUS_CLEAR, sizeof(tile_status_z)); +      fb.depth_clear_value = clear->value; +   } +   return; +#endif + +   if (clear->surface == 0) { +      for (i = 0; i < TILE_SIZE; i++) +         for (j = 0; j < TILE_SIZE; j++) +            ctile[i][j] = clear->value; +   } +   else { +      for (i = 0; i < TILE_SIZE; i++) +         for (j = 0; j < TILE_SIZE; j++) +            ztile[i][j] = clear->value; +   } + +   /* +   printf("SPU: %s num=%d w=%d h=%d\n", +          __FUNCTION__, num_tiles, fb.width_tiles, fb.height_tiles); +   */ + +   for (i = init.id; i < num_tiles; i += init.num_spus) { +      uint tx = i % fb.width_tiles; +      uint ty = i / fb.width_tiles; +      if (clear->surface == 0) +         put_tile(&fb, tx, ty, (uint *) ctile, TAG_SURFACE_CLEAR, 0); +      else +         put_tile(&fb, tx, ty, (uint *) ztile, TAG_SURFACE_CLEAR, 1); +      /* XXX we don't want this here, but it fixes bad tile results */ +   } + +#if 0 +   wait_on_mask(1 << TAG_SURFACE_CLEAR); +#endif +} + + +/** + * Given a rendering command's bounding box (in pixels) compute the + * location of the corresponding screen tile bounding box. + */ +static INLINE void +tile_bounding_box(const struct cell_command_render *render, +                  uint *txmin, uint *tymin, +                  uint *box_num_tiles, uint *box_width_tiles) +{ +#if 1 +   /* Debug: full-window bounding box */ +   uint txmax = fb.width_tiles - 1; +   uint tymax = fb.height_tiles - 1; +   *txmin = 0; +   *tymin = 0; +   *box_num_tiles = fb.width_tiles * fb.height_tiles; +   *box_width_tiles = fb.width_tiles; +   (void) render; +   (void) txmax; +   (void) tymax; +#else +   uint txmax, tymax, box_height_tiles; + +   *txmin = (uint) render->xmin / TILE_SIZE; +   *tymin = (uint) render->ymin / TILE_SIZE; +   txmax = (uint) render->xmax / TILE_SIZE; +   tymax = (uint) render->ymax / TILE_SIZE; +   *box_width_tiles = txmax - *txmin + 1; +   box_height_tiles = tymax - *tymin + 1; +   *box_num_tiles = *box_width_tiles * box_height_tiles; +#endif +#if 0 +   printf("Render bounds: %g, %g  ...  %g, %g\n", +          render->xmin, render->ymin, render->xmax, render->ymax); +   printf("Render tiles:  %u, %u .. %u, %u\n", *txmin, *tymin, txmax, tymax); +#endif +} + + +static void +cmd_render(const struct cell_command_render *render) +{ +   /* we'll DMA into these buffers */ +   ubyte vertex_data[CELL_MAX_VBUF_SIZE] ALIGN16_ATTRIB; +   ushort indexes[CELL_MAX_VBUF_INDEXES] ALIGN16_ATTRIB; + +   uint i, j, vertex_size, vertex_bytes, index_bytes; + +   if (Debug) +      printf("SPU %u: RENDER prim %u, indices: %u, nr_vert: %u\n", +             init.id, +             render->prim_type, +             render->num_verts, +             render->num_indexes); + + +   ASSERT_ALIGN16(render->vertex_data); +   ASSERT_ALIGN16(render->index_data); + +   vertex_size = render->num_attribs * 4 * sizeof(float); + +   /* how much vertex data */ +   vertex_bytes = render->num_verts * vertex_size; +   index_bytes = render->num_indexes * sizeof(ushort); +   if (index_bytes < 8) +      index_bytes = 8; +   else +      index_bytes = (index_bytes + 15) & ~0xf; /* multiple of 16 */ + +   /* +   printf("VBUF: indices at %p,  vertices at %p  vertex_bytes %u  ind_bytes %u\n", +          render->index_data, render->vertex_data, vertex_bytes, index_bytes); +   */ + +   /* get vertex data from main memory */ +   mfc_get(vertex_data,  /* dest */ +           (unsigned int) render->vertex_data,  /* src */ +           vertex_bytes,  /* size */ +           TAG_VERTEX_BUFFER, +           0, /* tid */ +           0  /* rid */); + +   /* get index data from main memory */ +   mfc_get(indexes,  /* dest */ +           (unsigned int) render->index_data,  /* src */ +           index_bytes, +           TAG_INDEX_BUFFER, +           0, /* tid */ +           0  /* rid */); + +   wait_on_mask_all((1 << TAG_VERTEX_BUFFER) | +                    (1 << TAG_INDEX_BUFFER)); + +   /* find tiles which intersect the prim bounding box */ +   uint txmin, tymin, box_width_tiles, box_num_tiles; +#if 0 +   tile_bounding_box(render, &txmin, &tymin, +                     &box_num_tiles, &box_width_tiles); +#else +   txmin = 0; +   tymin = 0; +   box_num_tiles = fb.width_tiles * fb.height_tiles; +   box_width_tiles = fb.width_tiles; +#endif + +   /* make sure any pending clears have completed */ +   wait_on_mask(1 << TAG_SURFACE_CLEAR); + +   /* loop over tiles */ +   for (i = init.id; i < box_num_tiles; i += init.num_spus) { +      const uint tx = txmin + i % box_width_tiles; +      const uint ty = tymin + i / box_width_tiles; + +      ASSERT(tx < fb.width_tiles); +      ASSERT(ty < fb.height_tiles); + +      /* Start fetching color/z tiles.  We'll wait for completion when +       * we need read/write to them later in triangle rasterization. +       */ +      if (fb.depth_format == PIPE_FORMAT_Z16_UNORM) { +         if (tile_status_z[ty][tx] != TILE_STATUS_CLEAR) { +            get_tile(&fb, tx, ty, (uint *) ztile, TAG_READ_TILE_Z, 1); +         } +      } + +      if (tile_status[ty][tx] != TILE_STATUS_CLEAR) { +         get_tile(&fb, tx, ty, (uint *) ctile, TAG_READ_TILE_COLOR, 0); +      } + +      ASSERT(render->prim_type == PIPE_PRIM_TRIANGLES); + +      /* loop over tris */ +      for (j = 0; j < render->num_indexes; j += 3) { +         const float *v0, *v1, *v2; + +         v0 = (const float *) (vertex_data + indexes[j+0] * vertex_size); +         v1 = (const float *) (vertex_data + indexes[j+1] * vertex_size); +         v2 = (const float *) (vertex_data + indexes[j+2] * vertex_size); + +         tri_draw(v0, v1, v2, tx, ty); +      } + +      /* write color/z tiles back to main framebuffer, if dirtied */ +      if (tile_status[ty][tx] == TILE_STATUS_DIRTY) { +         put_tile(&fb, tx, ty, (uint *) ctile, TAG_WRITE_TILE_COLOR, 0); +         tile_status[ty][tx] = TILE_STATUS_DEFINED; +      } +      if (fb.depth_format == PIPE_FORMAT_Z16_UNORM) { +         if (tile_status_z[ty][tx] == TILE_STATUS_DIRTY) { +            put_tile(&fb, tx, ty, (uint *) ztile, TAG_WRITE_TILE_Z, 1); +            tile_status_z[ty][tx] = TILE_STATUS_DEFINED; +         } +      } + +      /* XXX move these... */ +      wait_on_mask(1 << TAG_WRITE_TILE_COLOR); +      if (fb.depth_format == PIPE_FORMAT_Z16_UNORM) { +         wait_on_mask(1 << TAG_WRITE_TILE_Z); +      } +   } +} + + +static void +cmd_framebuffer(const struct cell_command_framebuffer *cmd) +{ +   if (Debug) +      printf("SPU %u: FRAMEBUFFER: %d x %d at %p, cformat 0x%x  zformat 0x%x\n", +             init.id, +             cmd->width, +             cmd->height, +             cmd->color_start, +             cmd->color_format, +             cmd->depth_format); + +   fb.color_start = cmd->color_start; +   fb.depth_start = cmd->depth_start; +   fb.color_format = cmd->color_format; +   fb.depth_format = cmd->depth_format; +   fb.width = cmd->width; +   fb.height = cmd->height; +   fb.width_tiles = (fb.width + TILE_SIZE - 1) / TILE_SIZE; +   fb.height_tiles = (fb.height + TILE_SIZE - 1) / TILE_SIZE; +} + + +static void +cmd_finish(void) +{ +   if (Debug) +      printf("SPU %u: FINISH\n", init.id); +   really_clear_tiles(0); +   /* wait for all outstanding DMAs to finish */ +   mfc_write_tag_mask(~0); +   mfc_read_tag_status_all(); +   /* send mbox message to PPU */ +   spu_write_out_mbox(CELL_CMD_FINISH); +} + + +/** + * Execute a batch of commands + * The opcode param encodes the location of the buffer and its size. + */ +static void +cmd_batch(uint opcode) +{ +   const uint buf = (opcode >> 8) & 0xff; +   uint size = (opcode >> 16); +   uint buffer[CELL_BATCH_BUFFER_SIZE / 4] ALIGN16_ATTRIB; +   const uint usize = size / sizeof(uint); +   uint pos; + +   if (Debug) +      printf("SPU %u: BATCH buffer %u, len %u, from %p\n", +             init.id, buf, size, init.batch_buffers[buf]); + +   ASSERT((opcode & CELL_CMD_OPCODE_MASK) == CELL_CMD_BATCH); + +   ASSERT_ALIGN16(init.batch_buffers[buf]); + +   size = (size + 0xf) & ~0xf; + +   mfc_get(buffer,  /* dest */ +           (unsigned int) init.batch_buffers[buf],  /* src */ +           size, +           TAG_BATCH_BUFFER, +           0, /* tid */ +           0  /* rid */); +   wait_on_mask(1 << TAG_BATCH_BUFFER); + +   for (pos = 0; pos < usize; /* no incr */) { +      switch (buffer[pos]) { +      case CELL_CMD_FRAMEBUFFER: +         { +            struct cell_command_framebuffer *fb +               = (struct cell_command_framebuffer *) &buffer[pos]; +            cmd_framebuffer(fb); +            pos += sizeof(*fb) / 4; +         } +         break; +      case CELL_CMD_CLEAR_SURFACE: +         { +            struct cell_command_clear_surface *clr +               = (struct cell_command_clear_surface *) &buffer[pos]; +            cmd_clear_surface(clr); +            pos += sizeof(*clr) / 4; +         } +         break; +      case CELL_CMD_RENDER: +         { +            struct cell_command_render *render +               = (struct cell_command_render *) &buffer[pos]; +            cmd_render(render); +            pos += sizeof(*render) / 4; +         } +         break; +      case CELL_CMD_FINISH: +         cmd_finish(); +         pos += 1; +         break; +      default: +         printf("SPU %u: bad opcode: 0x%x\n", init.id, buffer[pos]); +         ASSERT(0); +         break; +      } +   } + +   if (Debug) +      printf("SPU %u: BATCH complete\n", init.id); +} + + +/** + * Temporary/simple main loop for SPEs: Get a command, execute it, repeat. + */ +static void +main_loop(void) +{ +   struct cell_command cmd; +   int exitFlag = 0; + +   if (Debug) +      printf("SPU %u: Enter main loop\n", init.id); + +   ASSERT((sizeof(struct cell_command) & 0xf) == 0); +   ASSERT_ALIGN16(&cmd); + +   while (!exitFlag) { +      unsigned opcode; +      int tag = 0; + +      if (Debug) +         printf("SPU %u: Wait for cmd...\n", init.id); + +      /* read/wait from mailbox */ +      opcode = (unsigned int) spu_read_in_mbox(); + +      if (Debug) +         printf("SPU %u: got cmd 0x%x\n", init.id, opcode); + +      /* command payload */ +      mfc_get(&cmd,  /* dest */ +              (unsigned int) init.cmd, /* src */ +              sizeof(struct cell_command), /* bytes */ +              tag, +              0, /* tid */ +              0  /* rid */); +      wait_on_mask( 1 << tag ); + +      switch (opcode & CELL_CMD_OPCODE_MASK) { +      case CELL_CMD_EXIT: +         if (Debug) +            printf("SPU %u: EXIT\n", init.id); +         exitFlag = 1; +         break; +      case CELL_CMD_FRAMEBUFFER: +         cmd_framebuffer(&cmd.fb); +         break; +      case CELL_CMD_CLEAR_SURFACE: +         cmd_clear_surface(&cmd.clear); +         break; +      case CELL_CMD_RENDER: +         cmd_render(&cmd.render); +         break; +      case CELL_CMD_BATCH: +         cmd_batch(opcode); +         break; +      case CELL_CMD_FINISH: +         cmd_finish(); +         break; +      default: +         printf("Bad opcode!\n"); +      } + +   } + +   if (Debug) +      printf("SPU %u: Exit main loop\n", init.id); +} + + + +static void +one_time_init(void) +{ +   memset(tile_status, TILE_STATUS_DEFINED, sizeof(tile_status)); +   memset(tile_status_z, TILE_STATUS_DEFINED, sizeof(tile_status_z)); +} + + +/** + * SPE entrypoint. + * Note: example programs declare params as 'unsigned long long' but + * that doesn't work. + */ +int +main(unsigned long speid, unsigned long argp) +{ +   int tag = 0; + +   (void) speid; + +   one_time_init(); + +   if (Debug) +      printf("SPU: main() speid=%lu\n", speid); + +   mfc_get(&init,  /* dest */ +           (unsigned int) argp, /* src */ +           sizeof(struct cell_init_info), /* bytes */ +           tag, +           0, /* tid */ +           0  /* rid */); +   wait_on_mask( 1 << tag ); + + +   main_loop(); + +   return 0; +} diff --git a/src/mesa/pipe/cell/spu/spu_main.h b/src/mesa/pipe/cell/spu/spu_main.h new file mode 100644 index 0000000000..9ef8cf0709 --- /dev/null +++ b/src/mesa/pipe/cell/spu/spu_main.h @@ -0,0 +1,78 @@ +/************************************************************************** + *  + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 SPU_MAIN_H +#define SPU_MAIN_H + + +#include "pipe/cell/common.h" + + +extern volatile struct cell_init_info init; + +struct framebuffer { +   void *color_start;              /**< addr of color surface in main memory */ +   void *depth_start;              /**< addr of depth surface in main memory */ +   enum pipe_format color_format; +   enum pipe_format depth_format; +   uint width, height;             /**< size in pixels */ +   uint width_tiles, height_tiles; /**< width and height in tiles */ + +   uint color_clear_value; +   uint depth_clear_value; +}; + +/* XXX Collect these globals in a struct: */ + +extern struct framebuffer fb; + + +/* DMA TAGS */ + +#define TAG_SURFACE_CLEAR     10 +#define TAG_VERTEX_BUFFER     11 +#define TAG_READ_TILE_COLOR   12 +#define TAG_READ_TILE_Z       13 +#define TAG_WRITE_TILE_COLOR  14 +#define TAG_WRITE_TILE_Z      15 +#define TAG_INDEX_BUFFER      16 +#define TAG_BATCH_BUFFER      17 + +/** The standard assert macro doesn't seem to work on SPUs */ +#define ASSERT(x) \ +   if (!(x)) { \ +      fprintf(stderr, "SPU %d: %s:%d: %s(): assertion %s failed.\n", \ +              init.id, __FILE__, __LINE__, __FUNCTION__, #x); \ +      exit(1); \ +   } + + +void +wait_on_mask(unsigned tag); + + +#endif /* SPU_MAIN_H */ diff --git a/src/mesa/pipe/cell/spu/spu_tile.c b/src/mesa/pipe/cell/spu/spu_tile.c new file mode 100644 index 0000000000..8fd9ab2905 --- /dev/null +++ b/src/mesa/pipe/cell/spu/spu_tile.c @@ -0,0 +1,115 @@ +/************************************************************************** + *  + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 "spu_tile.h" + + + +uint ctile[TILE_SIZE][TILE_SIZE] ALIGN16_ATTRIB; +ushort ztile[TILE_SIZE][TILE_SIZE] ALIGN16_ATTRIB; + +ubyte tile_status[MAX_HEIGHT/TILE_SIZE][MAX_WIDTH/TILE_SIZE] ALIGN16_ATTRIB; +ubyte tile_status_z[MAX_HEIGHT/TILE_SIZE][MAX_WIDTH/TILE_SIZE] ALIGN16_ATTRIB; + + + +void +get_tile(const struct framebuffer *fb, uint tx, uint ty, uint *tile, +         int tag, int zBuf) +{ +   const uint offset = ty * fb->width_tiles + tx; +   const uint bytesPerTile = TILE_SIZE * TILE_SIZE * (zBuf ? 2 : 4); +   const ubyte *src = zBuf ? fb->depth_start : fb->color_start; + +   src += offset * bytesPerTile; + +   ASSERT(tx < fb->width_tiles); +   ASSERT(ty < fb->height_tiles); +   ASSERT_ALIGN16(tile); +   /* +   printf("get_tile:  dest: %p  src: 0x%x  size: %d\n", +          tile, (unsigned int) src, bytesPerTile); +   */ +   mfc_get(tile,  /* dest in local memory */ +           (unsigned int) src, /* src in main memory */ +           bytesPerTile, +           tag, +           0, /* tid */ +           0  /* rid */); +} + + +void +put_tile(const struct framebuffer *fb, uint tx, uint ty, const uint *tile, +         int tag, int zBuf) +{ +   const uint offset = ty * fb->width_tiles + tx; +   const uint bytesPerTile = TILE_SIZE * TILE_SIZE * (zBuf ? 2 : 4); +   ubyte *dst = zBuf ? fb->depth_start : fb->color_start; + +   dst += offset * bytesPerTile; + +   ASSERT(tx < fb->width_tiles); +   ASSERT(ty < fb->height_tiles); +   ASSERT_ALIGN16(tile); +   /* +   printf("put_tile:  src: %p  dst: 0x%x  size: %d\n", +          tile, (unsigned int) dst, bytesPerTile); +   */ +   mfc_put((void *) tile,  /* src in local memory */ +           (unsigned int) dst,  /* dst in main memory */ +           bytesPerTile, +           tag, +           0, /* tid */ +           0  /* rid */); +} + + +void +clear_tile(uint tile[TILE_SIZE][TILE_SIZE], uint value) +{ +   uint i, j; +   for (i = 0; i < TILE_SIZE; i++) { +      for (j = 0; j < TILE_SIZE; j++) { +         tile[i][j] = value; +      } +   } +} + +void +clear_tile_z(ushort tile[TILE_SIZE][TILE_SIZE], uint value) +{ +   uint i, j; +   for (i = 0; i < TILE_SIZE; i++) { +      for (j = 0; j < TILE_SIZE; j++) { +         tile[i][j] = value; +      } +   } +} + diff --git a/src/mesa/pipe/cell/spu/spu_tile.h b/src/mesa/pipe/cell/spu/spu_tile.h new file mode 100644 index 0000000000..2ad469b584 --- /dev/null +++ b/src/mesa/pipe/cell/spu/spu_tile.h @@ -0,0 +1,69 @@ +/************************************************************************** + *  + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 SPU_TILE_H +#define SPU_TILE_H + + +#include <libmisc.h> +#include <spu_mfcio.h> +#include "spu_main.h" +#include "pipe/cell/common.h" + + +#define MAX_WIDTH 1024 +#define MAX_HEIGHT 1024 + + +extern uint ctile[TILE_SIZE][TILE_SIZE] ALIGN16_ATTRIB; +extern ushort ztile[TILE_SIZE][TILE_SIZE] ALIGN16_ATTRIB; + + +#define TILE_STATUS_CLEAR   1 +#define TILE_STATUS_DEFINED 2  /**< defined pixel data */ +#define TILE_STATUS_DIRTY   3  /**< modified, but not put back yet */ + +extern ubyte tile_status[MAX_HEIGHT/TILE_SIZE][MAX_WIDTH/TILE_SIZE] ALIGN16_ATTRIB; +extern ubyte tile_status_z[MAX_HEIGHT/TILE_SIZE][MAX_WIDTH/TILE_SIZE] ALIGN16_ATTRIB; + + +void +get_tile(const struct framebuffer *fb, uint tx, uint ty, uint *tile, +          int tag, int zBuf); + +void +put_tile(const struct framebuffer *fb, uint tx, uint ty, const uint *tile, +         int tag, int zBuf); + +void +clear_tile(uint tile[TILE_SIZE][TILE_SIZE], uint value); + +void +clear_tile_z(ushort tile[TILE_SIZE][TILE_SIZE], uint value); + + +#endif /* SPU_TILE_H */ diff --git a/src/mesa/pipe/cell/spu/spu_tri.c b/src/mesa/pipe/cell/spu/spu_tri.c new file mode 100644 index 0000000000..af24e42435 --- /dev/null +++ b/src/mesa/pipe/cell/spu/spu_tri.c @@ -0,0 +1,892 @@ +/************************************************************************** + *  + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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. + *  + **************************************************************************/ + +/** + * Triangle rendering within a tile. + */ + +#include "pipe/p_compiler.h" +#include "pipe/p_format.h" +#include "pipe/p_util.h" +#include "spu_main.h" +#include "spu_tile.h" +#include "spu_tri.h" + + + +/** + * Simplified types taken from other parts of Gallium + */ + +struct vertex_header { +   float data[2][4];  /* pos and color */ +}; + +struct prim_header { +   struct vertex_header *v[3]; +}; + + + + +#if 1 + +/* XXX fix this */ +#undef CEILF +#define CEILF(X) ((float) (int) ((X) + 0.99999)) + + +#define QUAD_TOP_LEFT     0 +#define QUAD_TOP_RIGHT    1 +#define QUAD_BOTTOM_LEFT  2 +#define QUAD_BOTTOM_RIGHT 3 +#define MASK_TOP_LEFT     (1 << QUAD_TOP_LEFT) +#define MASK_TOP_RIGHT    (1 << QUAD_TOP_RIGHT) +#define MASK_BOTTOM_LEFT  (1 << QUAD_BOTTOM_LEFT) +#define MASK_BOTTOM_RIGHT (1 << QUAD_BOTTOM_RIGHT) +#define MASK_ALL          0xf + +#define PIPE_MAX_SHADER_INPUTS 8 /* XXX temp */ + +#endif + + +#define DEBUG_VERTS 0 + +/** + * Triangle edge info + */ +struct edge { +   float dx;		/**< X(v1) - X(v0), used only during setup */ +   float dy;		/**< Y(v1) - Y(v0), used only during setup */ +   float dxdy;		/**< dx/dy */ +   float sx, sy;	/**< first sample point coord */ +   int lines;		/**< number of lines on this edge */ +}; + + +struct interp_coef +{ +   float a0[4]; +   float dadx[4]; +   float dady[4]; +}; + +/** + * Triangle setup info (derived from draw_stage). + * Also used for line drawing (taking some liberties). + */ +struct setup_stage { + +   /* Vertices are just an array of floats making up each attribute in +    * turn.  Currently fixed at 4 floats, but should change in time. +    * Codegen will help cope with this. +    */ +   const struct vertex_header *vmax; +   const struct vertex_header *vmid; +   const struct vertex_header *vmin; +   const struct vertex_header *vprovoke; + +   struct edge ebot; +   struct edge etop; +   struct edge emaj; + +   float oneoverarea; + +   uint tx, ty; + +   int cliprect_minx, cliprect_maxx, cliprect_miny, cliprect_maxy; + +#if 0 +   struct tgsi_interp_coef coef[PIPE_MAX_SHADER_INPUTS]; +#else +   struct interp_coef coef[PIPE_MAX_SHADER_INPUTS]; +#endif + +#if 0 +   struct quad_header quad;  +#endif + +   struct { +      int left[2];   /**< [0] = row0, [1] = row1 */ +      int right[2]; +      int y; +      unsigned y_flags; +      unsigned mask;     /**< mask of MASK_BOTTOM/TOP_LEFT/RIGHT bits */ +   } span; +}; + + +#if 0 +/** + * Basically a cast wrapper. + */ +static INLINE struct setup_stage *setup_stage( struct draw_stage *stage ) +{ +   return (struct setup_stage *)stage; +} +#endif + +#if 0 +/** + * Clip setup->quad against the scissor/surface bounds. + */ +static INLINE void +quad_clip(struct setup_stage *setup) +{ +   const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect; +   const int minx = (int) cliprect->minx; +   const int maxx = (int) cliprect->maxx; +   const int miny = (int) cliprect->miny; +   const int maxy = (int) cliprect->maxy; + +   if (setup->quad.x0 >= maxx || +       setup->quad.y0 >= maxy || +       setup->quad.x0 + 1 < minx || +       setup->quad.y0 + 1 < miny) { +      /* totally clipped */ +      setup->quad.mask = 0x0; +      return; +   } +   if (setup->quad.x0 < minx) +      setup->quad.mask &= (MASK_BOTTOM_RIGHT | MASK_TOP_RIGHT); +   if (setup->quad.y0 < miny) +      setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_BOTTOM_RIGHT); +   if (setup->quad.x0 == maxx - 1) +      setup->quad.mask &= (MASK_BOTTOM_LEFT | MASK_TOP_LEFT); +   if (setup->quad.y0 == maxy - 1) +      setup->quad.mask &= (MASK_TOP_LEFT | MASK_TOP_RIGHT); +} +#endif + +#if 0 +/** + * Emit a quad (pass to next stage) with clipping. + */ +static INLINE void +clip_emit_quad(struct setup_stage *setup) +{ +   quad_clip(setup); +   if (setup->quad.mask) { +      struct softpipe_context *sp = setup->softpipe; +      sp->quad.first->run(sp->quad.first, &setup->quad); +   } +} +#endif + +/** + * Evaluate attribute coefficients (plane equations) to compute + * attribute values for the four fragments in a quad. + * Eg: four colors will be compute. + */ +static INLINE void +eval_coeff( struct setup_stage *setup, uint slot, +            float x, float y, float result[4][4]) +{ +   uint i; +   const float *dadx = setup->coef[slot].dadx; +   const float *dady = setup->coef[slot].dady; + +   /* loop over XYZW comps */ +   for (i = 0; i < 4; i++) { +      result[QUAD_TOP_LEFT][i] = setup->coef[slot].a0[i] + x * dadx[i] + y * dady[i]; +      result[QUAD_TOP_RIGHT][i] = result[0][i] + dadx[i]; +      result[QUAD_BOTTOM_LEFT][i] = result[0][i] + dady[i]; +      result[QUAD_BOTTOM_RIGHT][i] = result[0][i] + dadx[i] + dady[i]; +   } +} + + +static INLINE void +eval_z( struct setup_stage *setup, +        float x, float y, float result[4]) +{ +   uint slot = 0; +   uint i = 2; +   const float *dadx = setup->coef[slot].dadx; +   const float *dady = setup->coef[slot].dady; + +   result[QUAD_TOP_LEFT] = setup->coef[slot].a0[i] + x * dadx[i] + y * dady[i]; +   result[QUAD_TOP_RIGHT] = result[0] + dadx[i]; +   result[QUAD_BOTTOM_LEFT] = result[0] + dady[i]; +   result[QUAD_BOTTOM_RIGHT] = result[0] + dadx[i] + dady[i]; +} + + +static INLINE uint +pack_color(const float color[4]) +{ +   uint r = (uint) (color[0] * 255.0); +   uint g = (uint) (color[1] * 255.0); +   uint b = (uint) (color[2] * 255.0); +   uint a = (uint) (color[3] * 255.0); +   switch (fb.color_format) { +   case PIPE_FORMAT_A8R8G8B8_UNORM: +      return (a << 24) | (r << 16) | (g << 8) | b; +   case PIPE_FORMAT_B8G8R8A8_UNORM: +      return (b << 24) | (g << 16) | (r << 8) | a; +   default: +      ASSERT(0); +      return 0; +   } +} + + +/** + * Emit a quad (pass to next stage).  No clipping is done. + */ +static INLINE void +emit_quad( struct setup_stage *setup, int x, int y, unsigned mask ) +{ +#if 0 +   struct softpipe_context *sp = setup->softpipe; +   setup->quad.x0 = x; +   setup->quad.y0 = y; +   setup->quad.mask = mask; +   sp->quad.first->run(sp->quad.first, &setup->quad); +#else +   /* Cell: "write" quad fragments to the tile by setting prim color */ +   int ix = x - setup->cliprect_minx; +   int iy = y - setup->cliprect_miny; +   float colors[4][4]; +   uint z; + +   eval_coeff(setup, 1, (float) x, (float) y, colors); + +   if (fb.depth_format == PIPE_FORMAT_Z16_UNORM) { +      float zvals[4]; +      eval_z(setup, (float) x, (float) y, zvals); + +      if (tile_status_z[setup->ty][setup->tx] == TILE_STATUS_CLEAR) { +         /* now, _really_ clear the tile */ +         clear_tile_z(ztile, fb.depth_clear_value); +      } +      else { +         /* make sure we've got the tile from main mem */ +         wait_on_mask(1 << TAG_READ_TILE_Z); +      } +      tile_status_z[setup->ty][setup->tx] = TILE_STATUS_DIRTY; + +      if (mask & MASK_TOP_LEFT) { +         z = (uint) (zvals[0] * 65535.0); +         if (z < ztile[iy][ix]) +            ztile[iy][ix] = z; +         else +            mask &= ~MASK_TOP_LEFT; +      } + +      if (mask & MASK_TOP_RIGHT) { +         z = (uint) (zvals[1] * 65535.0); +         if (z < ztile[iy][ix+1]) +            ztile[iy][ix+1] = z; +         else +            mask &= ~MASK_TOP_RIGHT; +      } + +      if (mask & MASK_BOTTOM_LEFT) { +         z = (uint) (zvals[2] * 65535.0); +         if (z < ztile[iy+1][ix]) +            ztile[iy+1][ix] = z; +         else +            mask &= ~MASK_BOTTOM_LEFT; +      } + +      if (mask & MASK_BOTTOM_RIGHT) { +         z = (uint) (zvals[3] * 65535.0); +         if (z < ztile[iy+1][ix+1]) +            ztile[iy+1][ix+1] = z; +         else +            mask &= ~MASK_BOTTOM_RIGHT; +      } +   } + +   if (mask) { +      if (tile_status[setup->ty][setup->tx] == TILE_STATUS_CLEAR) { +         /* now, _really_ clear the tile */ +         clear_tile(ctile, fb.color_clear_value); +      } +      else { +         /* make sure we've got the tile from main mem */ +         wait_on_mask(1 << TAG_READ_TILE_COLOR); +      } +      tile_status[setup->ty][setup->tx] = TILE_STATUS_DIRTY; + +      if (mask & MASK_TOP_LEFT) +         ctile[iy][ix] = pack_color(colors[QUAD_TOP_LEFT]); +      if (mask & MASK_TOP_RIGHT) +         ctile[iy][ix+1] = pack_color(colors[QUAD_TOP_RIGHT]); +      if (mask & MASK_BOTTOM_LEFT) +         ctile[iy+1][ix] = pack_color(colors[QUAD_BOTTOM_LEFT]); +      if (mask & MASK_BOTTOM_RIGHT) +         ctile[iy+1][ix+1] = pack_color(colors[QUAD_BOTTOM_RIGHT]); +   } +#endif +} + + +/** + * Given an X or Y coordinate, return the block/quad coordinate that it + * belongs to. + */ +static INLINE int block( int x ) +{ +   return x & ~1; +} + + +/** + * Compute mask which indicates which pixels in the 2x2 quad are actually inside + * the triangle's bounds. + * + * this is pretty nasty...  may need to rework flush_spans again to + * fix it, if possible. + */ +static unsigned calculate_mask( struct setup_stage *setup, int x ) +{ +   unsigned mask = 0x0; + +   if (x >= setup->span.left[0] && x < setup->span.right[0])  +      mask |= MASK_TOP_LEFT; + +   if (x >= setup->span.left[1] && x < setup->span.right[1])  +      mask |= MASK_BOTTOM_LEFT; +       +   if (x+1 >= setup->span.left[0] && x+1 < setup->span.right[0])  +      mask |= MASK_TOP_RIGHT; + +   if (x+1 >= setup->span.left[1] && x+1 < setup->span.right[1])  +      mask |= MASK_BOTTOM_RIGHT; + +   return mask; +} + + +/** + * Render a horizontal span of quads + */ +static void flush_spans( struct setup_stage *setup ) +{ +   int minleft, maxright; +   int x; + +   switch (setup->span.y_flags) { +   case 0x3: +      /* both odd and even lines written (both quad rows) */ +      minleft = MIN2(setup->span.left[0], setup->span.left[1]); +      maxright = MAX2(setup->span.right[0], setup->span.right[1]); +      break; + +   case 0x1: +      /* only even line written (quad top row) */ +      minleft = setup->span.left[0]; +      maxright = setup->span.right[0]; +      break; + +   case 0x2: +      /* only odd line written (quad bottom row) */ +      minleft = setup->span.left[1]; +      maxright = setup->span.right[1]; +      break; + +   default: +      return; +   } + +   /* XXX this loop could be moved into the above switch cases and +    * calculate_mask() could be simplified a bit... +    */ +   for (x = block(minleft); x <= block(maxright); x += 2) { +      emit_quad( setup, x, setup->span.y,  +                 calculate_mask( setup, x ) ); +   } + +   setup->span.y = 0; +   setup->span.y_flags = 0; +   setup->span.right[0] = 0; +   setup->span.right[1] = 0; +} + +#if DEBUG_VERTS +static void print_vertex(const struct setup_stage *setup, +                         const struct vertex_header *v) +{ +   int i; +   fprintf(stderr, "Vertex: (%p)\n", v); +   for (i = 0; i < setup->quad.nr_attrs; i++) { +      fprintf(stderr, "  %d: %f %f %f %f\n",  i,  +              v->data[i][0], v->data[i][1], v->data[i][2], v->data[i][3]); +   } +} +#endif + +static boolean setup_sort_vertices( struct setup_stage *setup, +				      const struct prim_header *prim ) +{ +   const struct vertex_header *v0 = prim->v[0]; +   const struct vertex_header *v1 = prim->v[1]; +   const struct vertex_header *v2 = prim->v[2]; + +#if DEBUG_VERTS +   fprintf(stderr, "Triangle:\n"); +   print_vertex(setup, v0); +   print_vertex(setup, v1); +   print_vertex(setup, v2); +#endif + +   setup->vprovoke = v2; + +   /* determine bottom to top order of vertices */ +   { +      float y0 = v0->data[0][1]; +      float y1 = v1->data[0][1]; +      float y2 = v2->data[0][1]; +      if (y0 <= y1) { +	 if (y1 <= y2) { +	    /* y0<=y1<=y2 */ +	    setup->vmin = v0;    +	    setup->vmid = v1;    +	    setup->vmax = v2; +	 } +	 else if (y2 <= y0) { +	    /* y2<=y0<=y1 */ +	    setup->vmin = v2;    +	    setup->vmid = v0;    +	    setup->vmax = v1;    +	 } +	 else { +	    /* y0<=y2<=y1 */ +	    setup->vmin = v0;    +	    setup->vmid = v2;    +	    setup->vmax = v1;   +	 } +      } +      else { +	 if (y0 <= y2) { +	    /* y1<=y0<=y2 */ +	    setup->vmin = v1;    +	    setup->vmid = v0;    +	    setup->vmax = v2;   +	 } +	 else if (y2 <= y1) { +	    /* y2<=y1<=y0 */ +	    setup->vmin = v2;    +	    setup->vmid = v1;    +	    setup->vmax = v0;   +	 } +	 else { +	    /* y1<=y2<=y0 */ +	    setup->vmin = v1;    +	    setup->vmid = v2;    +	    setup->vmax = v0; +	 } +      } +   } + +   /* Check if triangle is completely outside the tile bounds */ +   if (setup->vmin->data[0][1] > setup->cliprect_maxy) +      return FALSE; +   if (setup->vmax->data[0][1] < setup->cliprect_miny) +      return FALSE; +   if (setup->vmin->data[0][0] < setup->cliprect_minx && +       setup->vmid->data[0][0] < setup->cliprect_minx && +       setup->vmax->data[0][0] < setup->cliprect_minx) +      return FALSE; +   if (setup->vmin->data[0][0] > setup->cliprect_maxx && +       setup->vmid->data[0][0] > setup->cliprect_maxx && +       setup->vmax->data[0][0] > setup->cliprect_maxx) +      return FALSE; + +   setup->ebot.dx = setup->vmid->data[0][0] - setup->vmin->data[0][0]; +   setup->ebot.dy = setup->vmid->data[0][1] - setup->vmin->data[0][1]; +   setup->emaj.dx = setup->vmax->data[0][0] - setup->vmin->data[0][0]; +   setup->emaj.dy = setup->vmax->data[0][1] - setup->vmin->data[0][1]; +   setup->etop.dx = setup->vmax->data[0][0] - setup->vmid->data[0][0]; +   setup->etop.dy = setup->vmax->data[0][1] - setup->vmid->data[0][1]; + +   /* +    * Compute triangle's area.  Use 1/area to compute partial +    * derivatives of attributes later. +    * +    * The area will be the same as prim->det, but the sign may be +    * different depending on how the vertices get sorted above. +    * +    * To determine whether the primitive is front or back facing we +    * use the prim->det value because its sign is correct. +    */ +   { +      const float area = (setup->emaj.dx * setup->ebot.dy -  +			    setup->ebot.dx * setup->emaj.dy); + +      setup->oneoverarea = 1.0f / area; +      /* +      _mesa_printf("%s one-over-area %f  area %f  det %f\n", +                   __FUNCTION__, setup->oneoverarea, area, prim->det ); +      */ +   } + +#if 0 +   /* We need to know if this is a front or back-facing triangle for: +    *  - the GLSL gl_FrontFacing fragment attribute (bool) +    *  - two-sided stencil test +    */ +   setup->quad.facing = (prim->det > 0.0) ^ (setup->softpipe->rasterizer->front_winding == PIPE_WINDING_CW); +#endif + +   return TRUE; +} + + +#if 0 +/** + * Compute a0 for a constant-valued coefficient (GL_FLAT shading). + * The value value comes from vertex->data[slot][i]. + * The result will be put into setup->coef[slot].a0[i]. + * \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 ) +{ +   assert(slot < PIPE_MAX_SHADER_INPUTS); +   assert(i <= 3); + +   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]; +} +#endif + + +/** + * Compute a0, dadx and dady for a linearly interpolated coefficient, + * for a triangle. + */ +static void tri_linear_coeff( struct setup_stage *setup, +                              uint slot, uint firstComp, uint lastComp ) +{ +   uint i; +   for (i = firstComp; i < lastComp; i++) { +      float botda = setup->vmid->data[slot][i] - setup->vmin->data[slot][i]; +      float majda = setup->vmax->data[slot][i] - setup->vmin->data[slot][i]; +      float a = setup->ebot.dy * majda - botda * setup->emaj.dy; +      float b = setup->emaj.dx * botda - majda * setup->ebot.dx; +    +      ASSERT(slot < PIPE_MAX_SHADER_INPUTS); + +      setup->coef[slot].dadx[i] = a * setup->oneoverarea; +      setup->coef[slot].dady[i] = b * setup->oneoverarea; + +      /* calculate a0 as the value which would be sampled for the +       * fragment at (0,0), taking into account that we want to sample at +       * pixel centers, in other words (0.5, 0.5). +       * +       * this is neat but unfortunately not a good way to do things for +       * triangles with very large values of dadx or dady as it will +       * result in the subtraction and re-addition from a0 of a very +       * large number, which means we'll end up loosing a lot of the +       * fractional bits and precision from a0.  the way to fix this is +       * to define a0 as the sample at a pixel center somewhere near vmin +       * instead - i'll switch to this later. +       */ +      setup->coef[slot].a0[i] = (setup->vmin->data[slot][i] -  +                                 (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5f) +  +                                  setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5f))); +   } + +   /* +   _mesa_printf("attr[%d].%c: %f dx:%f dy:%f\n", +		slot, "xyzw"[i],  +		setup->coef[slot].a0[i], +		setup->coef[slot].dadx[i], +		setup->coef[slot].dady[i]); +   */ +} + + +#if 0 +/** + * Compute a0, dadx and dady for a perspective-corrected interpolant, + * for a triangle. + * We basically multiply the vertex value by 1/w before computing + * the plane coefficients (a0, dadx, dady). + * Later, when we compute the value at a particular fragment position we'll + * divide the interpolated value by the interpolated W at that fragment. + */ +static void tri_persp_coeff( struct setup_stage *setup, +                             unsigned slot, +                             unsigned i ) +{ +   /* premultiply by 1/w: +    */ +   float mina = setup->vmin->data[slot][i] * setup->vmin->data[0][3]; +   float mida = setup->vmid->data[slot][i] * setup->vmid->data[0][3]; +   float maxa = setup->vmax->data[slot][i] * setup->vmax->data[0][3]; + +   float botda = mida - mina; +   float majda = maxa - mina; +   float a = setup->ebot.dy * majda - botda * setup->emaj.dy; +   float b = setup->emaj.dx * botda - majda * setup->ebot.dx; +       +   /* +   printf("tri persp %d,%d: %f %f %f\n", slot, i, +          setup->vmin->data[slot][i], +          setup->vmid->data[slot][i], +          setup->vmax->data[slot][i] +          ); +   */ + +   assert(slot < PIPE_MAX_SHADER_INPUTS); +   assert(i <= 3); + +   setup->coef[slot].dadx[i] = a * setup->oneoverarea; +   setup->coef[slot].dady[i] = b * setup->oneoverarea; +   setup->coef[slot].a0[i] = (mina -  +			    (setup->coef[slot].dadx[i] * (setup->vmin->data[0][0] - 0.5f) +  +			     setup->coef[slot].dady[i] * (setup->vmin->data[0][1] - 0.5f))); +} +#endif + + +/** + * Compute the setup->coef[] array dadx, dady, a0 values. + * Must be called after setup->vmin,vmid,vmax,vprovoke are initialized. + */ +static void setup_tri_coefficients( struct setup_stage *setup ) +{ +#if 0 +   const enum interp_mode *interp = setup->softpipe->vertex_info.interp_mode; +   unsigned slot, j; + +   /* z and w are done by linear interpolation: +    */ +   tri_linear_coeff(setup, 0, 2); +   tri_linear_coeff(setup, 0, 3); + +   /* setup interpolation for all the remaining attributes: +    */ +   for (slot = 1; slot < setup->quad.nr_attrs; slot++) { +      switch (interp[slot]) { +      case INTERP_CONSTANT: +	 for (j = 0; j < NUM_CHANNELS; j++) +	    const_coeff(setup, slot, j); +	 break; +       +      case INTERP_LINEAR: +	 for (j = 0; j < NUM_CHANNELS; j++) +	    tri_linear_coeff(setup, slot, j); +	 break; + +      case INTERP_PERSPECTIVE: +	 for (j = 0; j < NUM_CHANNELS; j++) +	    tri_persp_coeff(setup, slot, j); +	 break; + +      default: +         /* invalid interp mode */ +         assert(0); +      } +   } +#else +   tri_linear_coeff(setup, 0, 2, 3);  /* slot 0, z */ +   tri_linear_coeff(setup, 1, 0, 4);  /* slot 1, color */ +#endif +} + + +static void setup_tri_edges( struct setup_stage *setup ) +{ +   float vmin_x = setup->vmin->data[0][0] + 0.5f; +   float vmid_x = setup->vmid->data[0][0] + 0.5f; + +   float vmin_y = setup->vmin->data[0][1] - 0.5f; +   float vmid_y = setup->vmid->data[0][1] - 0.5f; +   float vmax_y = setup->vmax->data[0][1] - 0.5f; + +   setup->emaj.sy = CEILF(vmin_y); +   setup->emaj.lines = (int) CEILF(vmax_y - setup->emaj.sy); +   setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy; +   setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy; + +   setup->etop.sy = CEILF(vmid_y); +   setup->etop.lines = (int) CEILF(vmax_y - setup->etop.sy); +   setup->etop.dxdy = setup->etop.dx / setup->etop.dy; +   setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy; + +   setup->ebot.sy = CEILF(vmin_y); +   setup->ebot.lines = (int) CEILF(vmid_y - setup->ebot.sy); +   setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy; +   setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy; +} + + +/** + * Render the upper or lower half of a triangle. + * Scissoring/cliprect is applied here too. + */ +static void subtriangle( struct setup_stage *setup, +			 struct edge *eleft, +			 struct edge *eright, +			 unsigned lines ) +{ +   const int minx = setup->cliprect_minx; +   const int maxx = setup->cliprect_maxx; +   const int miny = setup->cliprect_miny; +   const int maxy = setup->cliprect_maxy; +   int y, start_y, finish_y; +   int sy = (int)eleft->sy; + +   ASSERT((int)eleft->sy == (int) eright->sy); + +   /* clip top/bottom */ +   start_y = sy; +   finish_y = sy + lines; + +   if (start_y < miny) +      start_y = miny; + +   if (finish_y > maxy) +      finish_y = maxy; + +   start_y -= sy; +   finish_y -= sy; + +   /* +   _mesa_printf("%s %d %d\n", __FUNCTION__, start_y, finish_y);   +   */ + +   for (y = start_y; y < finish_y; y++) { + +      /* avoid accumulating adds as floats don't have the precision to +       * accurately iterate large triangle edges that way.  luckily we +       * can just multiply these days. +       * +       * this is all drowned out by the attribute interpolation anyway. +       */ +      int left = (int)(eleft->sx + y * eleft->dxdy); +      int right = (int)(eright->sx + y * eright->dxdy); + +      /* clip left/right */ +      if (left < minx) +         left = minx; +      if (right > maxx) +         right = maxx; + +      if (left < right) { +         int _y = sy + y; +         if (block(_y) != setup->span.y) { +            flush_spans(setup); +            setup->span.y = block(_y); +         } + +         setup->span.left[_y&1] = left; +         setup->span.right[_y&1] = right; +         setup->span.y_flags |= 1<<(_y&1); +      } +   } + + +   /* save the values so that emaj can be restarted: +    */ +   eleft->sx += lines * eleft->dxdy; +   eright->sx += lines * eright->dxdy; +   eleft->sy += lines; +   eright->sy += lines; +} + + +/** + * Do setup for triangle rasterization, then render the triangle. + */ +static void +setup_tri(struct setup_stage *setup, struct prim_header *prim) +{ +   if (!setup_sort_vertices( setup, prim )) { +      return; /* totally clipped */ +   } + +   setup_tri_coefficients( setup ); +   setup_tri_edges( setup ); + +#if 0 +   setup->quad.prim = PRIM_TRI; +#endif + +   setup->span.y = 0; +   setup->span.y_flags = 0; +   setup->span.right[0] = 0; +   setup->span.right[1] = 0; +   /*   setup->span.z_mode = tri_z_mode( setup->ctx ); */ + +   /*   init_constant_attribs( setup ); */ +       +   if (setup->oneoverarea < 0.0) { +      /* emaj on left: +       */ +      subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines ); +      subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines ); +   } +   else { +      /* emaj on right: +       */ +      subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines ); +      subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines ); +   } + +   flush_spans( setup ); +} + + + +/** + * Draw triangle into tile at (tx, ty) (tile coords) + * The tile data should have already been fetched. + */ +void +tri_draw(const float *v0, const float *v1, const float *v2, uint tx, uint ty) +{ +   struct prim_header tri; +   struct setup_stage setup; + +   tri.v[0] = (struct vertex_header *) v0; +   tri.v[1] = (struct vertex_header *) v1; +   tri.v[2] = (struct vertex_header *) v2; + +   setup.tx = tx; +   setup.ty = ty; + +   /* set clipping bounds to tile bounds */ +   setup.cliprect_minx = tx * TILE_SIZE; +   setup.cliprect_miny = ty * TILE_SIZE; +   setup.cliprect_maxx = (tx + 1) * TILE_SIZE; +   setup.cliprect_maxy = (ty + 1) * TILE_SIZE; + +   setup_tri(&setup, &tri); +} diff --git a/src/mesa/pipe/cell/spu/spu_tri.h b/src/mesa/pipe/cell/spu/spu_tri.h new file mode 100644 index 0000000000..86c42b6339 --- /dev/null +++ b/src/mesa/pipe/cell/spu/spu_tri.h @@ -0,0 +1,37 @@ +/************************************************************************** + *  + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * 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 TUNGSTEN GRAPHICS 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 SPU_TRI_H +#define SPU_TRI_H + + +extern void +tri_draw(const float *v0, const float *v1, const float *v2, uint tx, uint ty); + + +#endif /* SPU_TRI_H */  | 
