spu_render.c

Go to the documentation of this file.
00001 /**************************************************************************
00002  * 
00003  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
00004  * All Rights Reserved.
00005  * 
00006  * Permission is hereby granted, free of charge, to any person obtaining a
00007  * copy of this software and associated documentation files (the
00008  * "Software"), to deal in the Software without restriction, including
00009  * without limitation the rights to use, copy, modify, merge, publish,
00010  * distribute, sub license, and/or sell copies of the Software, and to
00011  * permit persons to whom the Software is furnished to do so, subject to
00012  * the following conditions:
00013  * 
00014  * The above copyright notice and this permission notice (including the
00015  * next paragraph) shall be included in all copies or substantial portions
00016  * of the Software.
00017  * 
00018  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00019  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00020  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
00021  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
00022  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
00023  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
00024  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00025  * 
00026  **************************************************************************/
00027 
00028 
00029 #include <stdio.h>
00030 #include <libmisc.h>
00031 #include <spu_mfcio.h>
00032 
00033 #include "spu_main.h"
00034 #include "spu_render.h"
00035 #include "spu_tri.h"
00036 #include "spu_tile.h"
00037 #include "cell/common.h"
00038 #include "util/u_memory.h"
00039 
00040 
00045 static INLINE void
00046 tile_bounding_box(const struct cell_command_render *render,
00047                   uint *txmin, uint *tymin,
00048                   uint *box_num_tiles, uint *box_width_tiles)
00049 {
00050 #if 0
00051    /* Debug: full-window bounding box */
00052    uint txmax = spu.fb.width_tiles - 1;
00053    uint tymax = spu.fb.height_tiles - 1;
00054    *txmin = 0;
00055    *tymin = 0;
00056    *box_num_tiles = spu.fb.width_tiles * spu.fb.height_tiles;
00057    *box_width_tiles = spu.fb.width_tiles;
00058    (void) render;
00059    (void) txmax;
00060    (void) tymax;
00061 #else
00062    uint txmax, tymax, box_height_tiles;
00063 
00064    *txmin = (uint) render->xmin / TILE_SIZE;
00065    *tymin = (uint) render->ymin / TILE_SIZE;
00066    txmax = (uint) render->xmax / TILE_SIZE;
00067    tymax = (uint) render->ymax / TILE_SIZE;
00068    if (txmax >= spu.fb.width_tiles)
00069       txmax = spu.fb.width_tiles-1;
00070    if (tymax >= spu.fb.height_tiles)
00071       tymax = spu.fb.height_tiles-1;
00072    *box_width_tiles = txmax - *txmin + 1;
00073    box_height_tiles = tymax - *tymin + 1;
00074    *box_num_tiles = *box_width_tiles * box_height_tiles;
00075 #endif
00076 #if 0
00077    printf("SPU %u: bounds: %g, %g  ...  %g, %g\n", spu.init.id,
00078           render->xmin, render->ymin, render->xmax, render->ymax);
00079    printf("SPU %u: tiles:  %u, %u .. %u, %u\n",
00080            spu.init.id, *txmin, *tymin, txmax, tymax);
00081    ASSERT(render->xmin <= render->xmax);
00082    ASSERT(render->ymin <= render->ymax);
00083 #endif
00084 }
00085 
00086 
00088 static INLINE boolean
00089 my_tile(uint tx, uint ty)
00090 {
00091    return (spu.fb.width_tiles * ty + tx) % spu.init.num_spus == spu.init.id;
00092 }
00093 
00094 
00098 static INLINE void
00099 get_cz_tiles(uint tx, uint ty)
00100 {
00101    if (spu.read_depth) {
00102       if (spu.cur_ztile_status != TILE_STATUS_CLEAR) {
00103          //printf("SPU %u: getting Z tile %u, %u\n", spu.init.id, tx, ty);
00104          get_tile(tx, ty, &spu.ztile, TAG_READ_TILE_Z, 1);
00105          spu.cur_ztile_status = TILE_STATUS_GETTING;
00106       }
00107    }
00108 
00109    if (spu.cur_ctile_status != TILE_STATUS_CLEAR) {
00110       //printf("SPU %u: getting C tile %u, %u\n", spu.init.id, tx, ty);
00111       get_tile(tx, ty, &spu.ctile, TAG_READ_TILE_COLOR, 0);
00112       spu.cur_ctile_status = TILE_STATUS_GETTING;
00113    }
00114 }
00115 
00116 
00120 static INLINE void
00121 put_cz_tiles(uint tx, uint ty)
00122 {
00123    if (spu.cur_ztile_status == TILE_STATUS_DIRTY) {
00124       /* tile was modified and needs to be written back */
00125       //printf("SPU %u: put dirty Z tile %u, %u\n", spu.init.id, tx, ty);
00126       put_tile(tx, ty, &spu.ztile, TAG_WRITE_TILE_Z, 1);
00127       spu.cur_ztile_status = TILE_STATUS_DEFINED;
00128    }
00129    else if (spu.cur_ztile_status == TILE_STATUS_GETTING) {
00130       /* tile was never used */
00131       spu.cur_ztile_status = TILE_STATUS_DEFINED;
00132       //printf("SPU %u: put getting Z tile %u, %u\n", spu.init.id, tx, ty);
00133    }
00134 
00135    if (spu.cur_ctile_status == TILE_STATUS_DIRTY) {
00136       /* tile was modified and needs to be written back */
00137       //printf("SPU %u: put dirty C tile %u, %u\n", spu.init.id, tx, ty);
00138       put_tile(tx, ty, &spu.ctile, TAG_WRITE_TILE_COLOR, 0);
00139       spu.cur_ctile_status = TILE_STATUS_DEFINED;
00140    }
00141    else if (spu.cur_ctile_status == TILE_STATUS_GETTING) {
00142       /* tile was never used */
00143       spu.cur_ctile_status = TILE_STATUS_DEFINED;
00144       //printf("SPU %u: put getting C tile %u, %u\n", spu.init.id, tx, ty);
00145    }
00146 }
00147 
00148 
00152 static INLINE void
00153 wait_put_cz_tiles(void)
00154 {
00155    wait_on_mask(1 << TAG_WRITE_TILE_COLOR);
00156    if (spu.read_depth) {
00157       wait_on_mask(1 << TAG_WRITE_TILE_Z);
00158    }
00159 }
00160 
00161 
00167 void
00168 cmd_render(const struct cell_command_render *render, uint *pos_incr)
00169 {
00170    /* we'll DMA into these buffers */
00171    ubyte vertex_data[CELL_BUFFER_SIZE] ALIGN16_ATTRIB;
00172    const uint vertex_size = render->vertex_size; /* in bytes */
00173    /*const*/ uint total_vertex_bytes = render->num_verts * vertex_size;
00174    uint index_bytes;
00175    const ubyte *vertices;
00176    const ushort *indexes;
00177    uint i, j;
00178 
00179 
00180    if (Debug) {
00181       printf("SPU %u: RENDER prim %u, num_vert=%u  num_ind=%u  "
00182              "inline_vert=%u\n",
00183              spu.init.id,
00184              render->prim_type,
00185              render->num_verts,
00186              render->num_indexes,
00187              render->inline_verts);
00188 
00189       /*
00190       printf("       bound: %g, %g .. %g, %g\n",
00191              render->xmin, render->ymin, render->xmax, render->ymax);
00192       */
00193    }
00194 
00195    ASSERT(sizeof(*render) % 4 == 0);
00196    ASSERT(total_vertex_bytes % 16 == 0);
00197    ASSERT(render->prim_type == PIPE_PRIM_TRIANGLES);
00198    ASSERT(render->num_indexes % 3 == 0);
00199 
00200 
00201    /* indexes are right after the render command in the batch buffer */
00202    indexes = (const ushort *) (render + 1);
00203    index_bytes = ROUNDUP8(render->num_indexes * 2);
00204    *pos_incr = index_bytes / 8 + sizeof(*render) / 8;
00205 
00206 
00207    if (render->inline_verts) {
00208       /* Vertices are after indexes in batch buffer at next 16-byte addr */
00209       vertices = (const ubyte *) render + (*pos_incr * 8);
00210       vertices = (const ubyte *) align_pointer((void *) vertices, 16);
00211       ASSERT_ALIGN16(vertices);
00212       *pos_incr = ((vertices + total_vertex_bytes) - (ubyte *) render) / 8;
00213    }
00214    else {
00215       /* Begin DMA fetch of vertex buffer */
00216       ubyte *src = spu.init.buffers[render->vertex_buf];
00217       ubyte *dest = vertex_data;
00218 
00219       /* skip vertex data we won't use */
00220 #if 01
00221       src += render->min_index * vertex_size;
00222       dest += render->min_index * vertex_size;
00223       total_vertex_bytes -= render->min_index * vertex_size;
00224 #endif
00225       ASSERT(total_vertex_bytes % 16 == 0);
00226       ASSERT_ALIGN16(dest);
00227       ASSERT_ALIGN16(src);
00228 
00229       mfc_get(dest,   /* in vertex_data[] array */
00230               (unsigned int) src,  /* src in main memory */
00231               total_vertex_bytes,  /* size */
00232               TAG_VERTEX_BUFFER,
00233               0, /* tid */
00234               0  /* rid */);
00235 
00236       vertices = vertex_data;
00237 
00238       wait_on_mask(1 << TAG_VERTEX_BUFFER);
00239    }
00240 
00241 
00245    uint txmin, tymin, box_width_tiles, box_num_tiles;
00246    tile_bounding_box(render, &txmin, &tymin,
00247                      &box_num_tiles, &box_width_tiles);
00248 
00249 
00250    /* make sure any pending clears have completed */
00251    wait_on_mask(1 << TAG_SURFACE_CLEAR); /* XXX temporary */
00252 
00253 
00257    for (i = 0; i < box_num_tiles; i++) {
00258       const uint tx = txmin + i % box_width_tiles;
00259       const uint ty = tymin + i / box_width_tiles;
00260 
00261       ASSERT(tx < spu.fb.width_tiles);
00262       ASSERT(ty < spu.fb.height_tiles);
00263 
00264       if (!my_tile(tx, ty))
00265          continue;
00266 
00267       spu.cur_ctile_status = spu.ctile_status[ty][tx];
00268       spu.cur_ztile_status = spu.ztile_status[ty][tx];
00269 
00270       get_cz_tiles(tx, ty);
00271 
00272       uint drawn = 0;
00273 
00274       /* loop over tris */
00275       for (j = 0; j < render->num_indexes; j += 3) {
00276          const float *v0, *v1, *v2;
00277 
00278          v0 = (const float *) (vertices + indexes[j+0] * vertex_size);
00279          v1 = (const float *) (vertices + indexes[j+1] * vertex_size);
00280          v2 = (const float *) (vertices + indexes[j+2] * vertex_size);
00281 
00282          drawn += tri_draw(v0, v1, v2, tx, ty);
00283       }
00284 
00285       //printf("SPU %u: drew %u of %u\n", spu.init.id, drawn, render->num_indexes/3);
00286 
00287       /* write color/z tiles back to main framebuffer, if dirtied */
00288       put_cz_tiles(tx, ty);
00289 
00290       wait_put_cz_tiles(); /* XXX seems unnecessary... */
00291 
00292       spu.ctile_status[ty][tx] = spu.cur_ctile_status;
00293       spu.ztile_status[ty][tx] = spu.cur_ztile_status;
00294    }
00295 
00296    if (Debug)
00297       printf("SPU %u: RENDER done\n",
00298              spu.init.id);
00299 }
00300 
00301 

Generated on Tue Sep 29 06:25:16 2009 for Gallium3D by  doxygen 1.5.4