filename | src/pvr2/rendsort.c |
changeset | 331:a6048d3a9a79 |
prev | 319:5392aed6a982 |
next | 429:e581b90c3fb3 |
author | nkeynes |
date | Mon Jan 29 11:24:44 2007 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Get render size from the tile segment array Set near clip to just 0 rather than scanning the scene Fixup modulate RGB to force fragment alpha to 1.0 Add some debugging fprintfs |
file | annotate | diff | log | raw |
nkeynes@222 | 1 | /** |
nkeynes@331 | 2 | * $Id: rendsort.c,v 1.5 2007-01-26 01:37:39 nkeynes Exp $ |
nkeynes@222 | 3 | * |
nkeynes@222 | 4 | * PVR2 renderer routines for depth sorted polygons |
nkeynes@222 | 5 | * |
nkeynes@222 | 6 | * Copyright (c) 2005 Nathan Keynes. |
nkeynes@222 | 7 | * |
nkeynes@222 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@222 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@222 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@222 | 11 | * (at your option) any later version. |
nkeynes@222 | 12 | * |
nkeynes@222 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@222 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@222 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@222 | 16 | * GNU General Public License for more details. |
nkeynes@222 | 17 | */ |
nkeynes@222 | 18 | #include <sys/time.h> |
nkeynes@222 | 19 | #include "pvr2/pvr2.h" |
nkeynes@222 | 20 | #include "asic.h" |
nkeynes@222 | 21 | |
nkeynes@222 | 22 | extern char *video_base; |
nkeynes@318 | 23 | extern gboolean pvr2_force_fragment_alpha; |
nkeynes@222 | 24 | |
nkeynes@222 | 25 | #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) ) |
nkeynes@222 | 26 | #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) ) |
nkeynes@222 | 27 | |
nkeynes@222 | 28 | struct render_triangle { |
nkeynes@222 | 29 | uint32_t *polygon; |
nkeynes@319 | 30 | int vertex_length; /* Number of 32-bit words in vertex, or 0 for an unpacked vertex */ |
nkeynes@222 | 31 | float minx,miny,minz; |
nkeynes@222 | 32 | float maxx,maxy,maxz; |
nkeynes@222 | 33 | float *vertexes[3]; |
nkeynes@222 | 34 | }; |
nkeynes@222 | 35 | |
nkeynes@318 | 36 | #define SENTINEL 0xDEADBEEF |
nkeynes@318 | 37 | |
nkeynes@222 | 38 | /** |
nkeynes@222 | 39 | * Count the number of triangles in the list starting at the given |
nkeynes@222 | 40 | * pvr memory address. |
nkeynes@222 | 41 | */ |
nkeynes@222 | 42 | int render_count_triangles( pvraddr_t tile_entry ) { |
nkeynes@222 | 43 | uint32_t *tile_list = (uint32_t *)(video_base+tile_entry); |
nkeynes@222 | 44 | int count = 0; |
nkeynes@222 | 45 | while(1) { |
nkeynes@222 | 46 | uint32_t entry = *tile_list++; |
nkeynes@222 | 47 | if( entry >> 28 == 0x0F ) { |
nkeynes@222 | 48 | break; |
nkeynes@222 | 49 | } else if( entry >> 28 == 0x0E ) { |
nkeynes@222 | 50 | tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF)); |
nkeynes@222 | 51 | } else if( entry >> 29 == 0x04 ) { /* Triangle array */ |
nkeynes@222 | 52 | count += ((entry >> 25) & 0x0F)+1; |
nkeynes@222 | 53 | } else if( entry >> 29 == 0x05 ) { /* Quad array */ |
nkeynes@222 | 54 | count += ((((entry >> 25) & 0x0F)+1)<<1); |
nkeynes@222 | 55 | } else { /* Polygon */ |
nkeynes@222 | 56 | int i; |
nkeynes@222 | 57 | for( i=0; i<6; i++ ) { |
nkeynes@222 | 58 | if( entry & (0x40000000>>i) ) { |
nkeynes@222 | 59 | count++; |
nkeynes@222 | 60 | } |
nkeynes@222 | 61 | } |
nkeynes@222 | 62 | } |
nkeynes@222 | 63 | } |
nkeynes@222 | 64 | return count; |
nkeynes@222 | 65 | } |
nkeynes@222 | 66 | |
nkeynes@222 | 67 | static void compute_triangle_boxes( struct render_triangle *triangle, int num_triangles ) |
nkeynes@222 | 68 | { |
nkeynes@222 | 69 | int i; |
nkeynes@222 | 70 | for( i=0; i<num_triangles; i++ ) { |
nkeynes@222 | 71 | triangle[i].minx = MIN3(triangle[i].vertexes[0][0],triangle[i].vertexes[1][0],triangle[i].vertexes[2][0]); |
nkeynes@222 | 72 | triangle[i].maxx = MAX3(triangle[i].vertexes[0][0],triangle[i].vertexes[1][0],triangle[i].vertexes[2][0]); |
nkeynes@222 | 73 | triangle[i].miny = MIN3(triangle[i].vertexes[0][1],triangle[i].vertexes[1][1],triangle[i].vertexes[2][1]); |
nkeynes@222 | 74 | triangle[i].maxy = MAX3(triangle[i].vertexes[0][1],triangle[i].vertexes[1][1],triangle[i].vertexes[2][1]); |
nkeynes@331 | 75 | float az = 1/triangle[i].vertexes[0][2]; |
nkeynes@331 | 76 | float bz = 1/triangle[i].vertexes[1][2]; |
nkeynes@331 | 77 | float cz = 1/triangle[i].vertexes[2][2]; |
nkeynes@331 | 78 | triangle[i].minz = MIN3(az,bz,cz); |
nkeynes@331 | 79 | triangle[i].maxz = MAX3(az,bz,cz); |
nkeynes@222 | 80 | } |
nkeynes@222 | 81 | } |
nkeynes@222 | 82 | |
nkeynes@222 | 83 | void render_extract_triangles( pvraddr_t tile_entry, gboolean cheap_modifier_mode, |
nkeynes@319 | 84 | struct render_triangle *triangles, int num_triangles, |
nkeynes@319 | 85 | struct vertex_unpacked *vertex_space, int render_mode ) |
nkeynes@222 | 86 | { |
nkeynes@222 | 87 | uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE); |
nkeynes@222 | 88 | uint32_t *tile_list = (uint32_t *)(video_base+tile_entry); |
nkeynes@222 | 89 | int count = 0; |
nkeynes@222 | 90 | while(1) { |
nkeynes@222 | 91 | uint32_t entry = *tile_list++; |
nkeynes@222 | 92 | if( entry >> 28 == 0x0F ) { |
nkeynes@222 | 93 | break; |
nkeynes@222 | 94 | } else if( entry >> 28 == 0x0E ) { |
nkeynes@222 | 95 | tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF)); |
nkeynes@222 | 96 | } else { |
nkeynes@222 | 97 | uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2)); |
nkeynes@222 | 98 | int is_modified = entry & 0x01000000; |
nkeynes@222 | 99 | int vertex_length = (entry >> 21) & 0x07; |
nkeynes@222 | 100 | int context_length = 3; |
nkeynes@222 | 101 | if( is_modified && !cheap_modifier_mode ) { |
nkeynes@222 | 102 | context_length = 5; |
nkeynes@222 | 103 | vertex_length *= 2 ; |
nkeynes@222 | 104 | } |
nkeynes@222 | 105 | vertex_length += 3; |
nkeynes@222 | 106 | |
nkeynes@222 | 107 | if( (entry & 0xE0000000) == 0x80000000 ) { |
nkeynes@222 | 108 | /* Triangle(s) */ |
nkeynes@222 | 109 | int strip_count = ((entry >> 25) & 0x0F)+1; |
nkeynes@222 | 110 | int polygon_length = 3 * vertex_length + context_length; |
nkeynes@222 | 111 | int i; |
nkeynes@222 | 112 | for( i=0; i<strip_count; i++ ) { |
nkeynes@222 | 113 | float *vertex = (float *)(polygon+context_length); |
nkeynes@222 | 114 | triangles[count].polygon = polygon; |
nkeynes@222 | 115 | triangles[count].vertex_length = vertex_length; |
nkeynes@222 | 116 | triangles[count].vertexes[0] = vertex; |
nkeynes@222 | 117 | vertex+=vertex_length; |
nkeynes@222 | 118 | triangles[count].vertexes[1] = vertex; |
nkeynes@222 | 119 | vertex+=vertex_length; |
nkeynes@222 | 120 | triangles[count].vertexes[2] = vertex; |
nkeynes@222 | 121 | polygon += polygon_length; |
nkeynes@222 | 122 | count++; |
nkeynes@222 | 123 | } |
nkeynes@222 | 124 | } else if( (entry & 0xE0000000) == 0xA0000000 ) { |
nkeynes@319 | 125 | /* Quad(s) */ |
nkeynes@276 | 126 | int strip_count = ((entry >> 25) & 0x0F)+1; |
nkeynes@222 | 127 | int polygon_length = 4 * vertex_length + context_length; |
nkeynes@319 | 128 | |
nkeynes@222 | 129 | int i; |
nkeynes@222 | 130 | for( i=0; i<strip_count; i++ ) { |
nkeynes@319 | 131 | render_unpack_quad( vertex_space, *polygon, (polygon+context_length), |
nkeynes@319 | 132 | vertex_length, render_mode ); |
nkeynes@222 | 133 | triangles[count].polygon = polygon; |
nkeynes@319 | 134 | triangles[count].vertex_length = 0; |
nkeynes@319 | 135 | triangles[count].vertexes[0] = (float *)vertex_space; |
nkeynes@319 | 136 | triangles[count].vertexes[1] = (float *)(vertex_space + 1); |
nkeynes@319 | 137 | triangles[count].vertexes[2] = (float *)(vertex_space + 3); |
nkeynes@222 | 138 | count++; |
nkeynes@222 | 139 | /* Preserve face direction */ |
nkeynes@222 | 140 | triangles[count].polygon = polygon; |
nkeynes@319 | 141 | triangles[count].vertex_length = 0; |
nkeynes@319 | 142 | triangles[count].vertexes[0] = (float *)(vertex_space + 1); |
nkeynes@319 | 143 | triangles[count].vertexes[1] = (float *)(vertex_space + 2); |
nkeynes@319 | 144 | triangles[count].vertexes[2] = (float *)(vertex_space + 3); |
nkeynes@222 | 145 | count++; |
nkeynes@319 | 146 | vertex_space += 4; |
nkeynes@222 | 147 | polygon += polygon_length; |
nkeynes@222 | 148 | } |
nkeynes@222 | 149 | } else { |
nkeynes@222 | 150 | /* Polygon */ |
nkeynes@222 | 151 | int i, first=-1, last = -1; |
nkeynes@222 | 152 | float *vertex = (float *)polygon+context_length; |
nkeynes@222 | 153 | for( i=0; i<6; i++ ) { |
nkeynes@222 | 154 | if( entry & (0x40000000>>i) ) { |
nkeynes@222 | 155 | triangles[count].polygon = polygon; |
nkeynes@222 | 156 | triangles[count].vertex_length = vertex_length; |
nkeynes@222 | 157 | if( i&1 ) { |
nkeynes@222 | 158 | triangles[count].vertexes[0] = vertex + vertex_length; |
nkeynes@222 | 159 | triangles[count].vertexes[1] = vertex; |
nkeynes@222 | 160 | triangles[count].vertexes[2] = vertex + (vertex_length<<1); |
nkeynes@222 | 161 | } else { |
nkeynes@222 | 162 | triangles[count].vertexes[0] = vertex; |
nkeynes@222 | 163 | triangles[count].vertexes[1] = vertex + vertex_length; |
nkeynes@222 | 164 | triangles[count].vertexes[2] = vertex + (vertex_length<<1); |
nkeynes@222 | 165 | } |
nkeynes@222 | 166 | count++; |
nkeynes@222 | 167 | } |
nkeynes@222 | 168 | vertex += vertex_length; |
nkeynes@222 | 169 | } |
nkeynes@222 | 170 | } |
nkeynes@222 | 171 | } |
nkeynes@222 | 172 | } |
nkeynes@318 | 173 | if( count != num_triangles ) { |
nkeynes@318 | 174 | ERROR( "Extracted triangles do not match expected count!" ); |
nkeynes@318 | 175 | } |
nkeynes@222 | 176 | } |
nkeynes@222 | 177 | |
nkeynes@222 | 178 | void render_triangles( struct render_triangle *triangles, int num_triangles, |
nkeynes@222 | 179 | int render_mode ) |
nkeynes@222 | 180 | { |
nkeynes@318 | 181 | int i,j, k, m = 0; |
nkeynes@222 | 182 | for( i=0; i<num_triangles; i++ ) { |
nkeynes@222 | 183 | render_set_context( triangles[i].polygon, render_mode ); |
nkeynes@331 | 184 | glEnable(GL_DEPTH_TEST); |
nkeynes@331 | 185 | glDepthFunc(GL_GEQUAL); |
nkeynes@319 | 186 | if( triangles[i].vertex_length == 0 ) { |
nkeynes@319 | 187 | render_unpacked_vertex_array( *triangles[i].polygon, (struct vertex_unpacked **)triangles[i].vertexes, 3 ); |
nkeynes@319 | 188 | } else { |
nkeynes@319 | 189 | render_vertex_array( *triangles[i].polygon, (uint32_t **)triangles[i].vertexes, 3, |
nkeynes@319 | 190 | triangles[i].vertex_length, render_mode ); |
nkeynes@222 | 191 | } |
nkeynes@222 | 192 | } |
nkeynes@222 | 193 | |
nkeynes@222 | 194 | |
nkeynes@222 | 195 | } |
nkeynes@222 | 196 | |
nkeynes@222 | 197 | int compare_triangles( void *a, void *b ) |
nkeynes@222 | 198 | { |
nkeynes@222 | 199 | struct render_triangle *tri1 = a; |
nkeynes@222 | 200 | struct render_triangle *tri2 = b; |
nkeynes@331 | 201 | if( tri1->minz < tri2->minz ) { |
nkeynes@331 | 202 | return 1; // No these _aren't_ back to front... |
nkeynes@331 | 203 | } else if( tri1->minz > tri2->minz ) { |
nkeynes@222 | 204 | return -1; |
nkeynes@222 | 205 | } else { |
nkeynes@222 | 206 | return 0; |
nkeynes@222 | 207 | } |
nkeynes@222 | 208 | } |
nkeynes@222 | 209 | |
nkeynes@222 | 210 | void sort_triangles( struct render_triangle *triangles, int num_triangles ) |
nkeynes@222 | 211 | { |
nkeynes@222 | 212 | qsort( triangles, num_triangles, sizeof(struct render_triangle), compare_triangles ); |
nkeynes@222 | 213 | } |
nkeynes@222 | 214 | |
nkeynes@222 | 215 | void render_autosort_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) |
nkeynes@222 | 216 | { |
nkeynes@222 | 217 | int num_triangles = render_count_triangles(tile_entry); |
nkeynes@222 | 218 | if( num_triangles == 0 ) { |
nkeynes@222 | 219 | return; /* nothing to do */ |
nkeynes@222 | 220 | } else if( num_triangles == 1 ) { /* Triangle can hardly overlap with itself */ |
nkeynes@222 | 221 | render_tile( tile_entry, render_mode, cheap_modifier_mode ); |
nkeynes@222 | 222 | } else { /* Ooh boy here we go... */ |
nkeynes@318 | 223 | struct render_triangle triangles[num_triangles+1]; |
nkeynes@319 | 224 | struct vertex_unpacked vertex_space[num_triangles << 1]; |
nkeynes@319 | 225 | // Reserve space for num_triangles / 2 * 4 vertexes (maximum possible number of |
nkeynes@319 | 226 | // quad vertices) |
nkeynes@318 | 227 | triangles[num_triangles].polygon = (void *)SENTINEL; |
nkeynes@319 | 228 | render_extract_triangles(tile_entry, cheap_modifier_mode, triangles, num_triangles, vertex_space, render_mode); |
nkeynes@222 | 229 | compute_triangle_boxes(triangles, num_triangles); |
nkeynes@222 | 230 | sort_triangles( triangles, num_triangles ); |
nkeynes@222 | 231 | render_triangles(triangles, num_triangles, render_mode); |
nkeynes@318 | 232 | if( triangles[num_triangles].polygon != (void *)SENTINEL ) { |
nkeynes@318 | 233 | fprintf( stderr, "Triangle overflow in render_autosort_tile!" ); |
nkeynes@318 | 234 | } |
nkeynes@222 | 235 | } |
nkeynes@222 | 236 | } |
.