Search
lxdream.org :: lxdream/src/pvr2/rendsort.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendsort.c
changeset 893:8eae02de411a
prev876:78cd32021472
next934:3acd3b3ee6d1
author nkeynes
date Thu Dec 11 21:33:08 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Only call finish_rendering() for texture renders - workaround bug in apple/intel drivers
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * PVR2 renderer routines for depth sorted polygons
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    18 #include <sys/time.h>
    19 #include <string.h>
    20 #include <assert.h>
    21 #include "pvr2/pvr2.h"
    22 #include "pvr2/scene.h"
    23 #include "asic.h"
    25 #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
    26 #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
    27 #define EPSILON 0.0001
    29 struct sort_triangle {
    30     struct polygon_struct *poly;
    31     int triangle_num; // triangle number in the poly, from 0
    32     /* plane equation */
    33     float mx, my, mz, d;
    34     float bounds[6]; /* x1,x2,y1,y2,z1,z2 */
    35 };
    37 #define SENTINEL 0xDEADBEEF
    39 /**
    40  * Count the number of triangles in the list starting at the given 
    41  * pvr memory address.
    42  */
    43 static int sort_count_triangles( pvraddr_t tile_entry ) {
    44     uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
    45     int count = 0;
    46     while(1) {
    47         uint32_t entry = *tile_list++;
    48         if( entry >> 28 == 0x0F ) {
    49             break;
    50         } else if( entry >> 28 == 0x0E ) {
    51             tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
    52         } else if( entry >> 29 == 0x04 ) { /* Triangle array */
    53             count += ((entry >> 25) & 0x0F)+1;
    54         } else if( entry >> 29 == 0x05 ) { /* Quad array */
    55             count += ((((entry >> 25) & 0x0F)+1)<<1);
    56         } else { /* Polygon */
    57             int i;
    58             for( i=0; i<6; i++ ) {
    59                 if( entry & (0x40000000>>i) ) {
    60                     count++;
    61                 }
    62             }
    63         }
    64     }
    65     return count;
    66 }
    68 static void sort_add_triangle( struct sort_triangle *triangle, struct polygon_struct *poly, int index )
    69 {
    70     struct vertex_struct *vertexes = &pvr2_scene.vertex_array[poly->vertex_index+index];
    71     triangle->poly = poly;
    72     triangle->triangle_num = index;
    74     /* Compute triangle bounding-box */
    75     triangle->bounds[0] = MIN3(vertexes[0].x,vertexes[1].x,vertexes[2].x);
    76     triangle->bounds[1] = MAX3(vertexes[0].x,vertexes[1].x,vertexes[2].x);
    77     triangle->bounds[2] = MIN3(vertexes[0].y,vertexes[1].y,vertexes[2].y);
    78     triangle->bounds[3] = MAX3(vertexes[0].y,vertexes[1].y,vertexes[2].y);
    79     triangle->bounds[4] = MIN3(vertexes[0].z,vertexes[1].z,vertexes[2].z);
    80     triangle->bounds[5] = MAX3(vertexes[0].z,vertexes[1].z,vertexes[2].z);
    82     /* Compute plane equation */
    83     float sx = vertexes[1].x - vertexes[0].x;
    84     float sy = vertexes[1].y - vertexes[0].y;
    85     float sz = vertexes[1].z - vertexes[0].z;
    86     float tx = vertexes[2].x - vertexes[0].x;
    87     float ty = vertexes[2].y - vertexes[0].y;
    88     float tz = vertexes[2].z - vertexes[0].z;
    89     triangle->mx = sy*tz - sz*ty;
    90     triangle->my = sz*tx - sx*tz;
    91     triangle->mz = sx*ty - sy*tx;
    92     triangle->d = -vertexes[0].x*triangle->mx - 
    93                   vertexes[0].y*triangle->my - 
    94                   vertexes[0].z*triangle->mz;
    95 }
    97 /**
    98  * Extract a triangle list from the tile (basically indexes into the polygon list, plus
    99  * computing maxz while we go through it
   100  */
   101 int sort_extract_triangles( pvraddr_t tile_entry, struct sort_triangle *triangles )
   102 {
   103     uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
   104     int strip_count;
   105     struct polygon_struct *poly;
   106     int count = 0, i;
   108     while(1) {
   109         uint32_t entry = *tile_list++;
   110         switch( entry >> 28 ) {
   111         case 0x0F:
   112             return count; // End-of-list
   113         case 0x0E:
   114             tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
   115             break;
   116         case 0x08: case 0x09: case 0x0A: case 0x0B:
   117             strip_count = ((entry >> 25) & 0x0F)+1;
   118             poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
   119             while( strip_count > 0 ) {
   120                 assert( poly != NULL );
   121                 for( i=0; i<poly->vertex_count-2; i++ ) {
   122                     sort_add_triangle( &triangles[count], poly, i );
   123                     count++;
   124                 }
   125                 poly = poly->next;
   126                 strip_count--;
   127             }
   128             break;
   129         default:
   130             if( entry & 0x7E000000 ) {
   131                 poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
   132                 for( i=0; i<6; i++ ) {
   133                     if( entry & (0x40000000>>i) ) {
   134                         sort_add_triangle( &triangles[count], poly, i );
   135                         count++;
   136                     }
   137                 }
   138             }
   139         }
   140     }       
   142 }
   144 void sort_render_triangles( struct sort_triangle **triangles, int num_triangles )
   145 {
   146     int i;
   147     for( i=0; i<num_triangles; i++ ) {
   148         struct polygon_struct *poly = triangles[i]->poly;
   149         if( poly->tex_id != -1 ) {
   150             glBindTexture(GL_TEXTURE_2D, poly->tex_id);
   151         }
   152         render_set_context( poly->context, GL_GEQUAL );
   153         glDepthMask(GL_FALSE);
   154         /* Fix cull direction */
   155         if( triangles[i]->triangle_num & 1 ) {
   156             glCullFace(GL_FRONT);
   157         } else {
   158             glCullFace(GL_BACK);
   159         }
   161         glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index + triangles[i]->triangle_num, 3 );
   162     }
   163 }
   165 static int sort_triangle_compare( const void *a, const void *b ) 
   166 {
   167     const struct sort_triangle *tri1 = a;
   168     const struct sort_triangle *tri2 = b;
   169     if( tri1->bounds[5] <= tri2->bounds[4] ) 
   170         return 1; /* tri1 is entirely under tri2 */
   171     else if( tri2->bounds[5] <= tri1->bounds[4] )
   172         return -1;  /* tri2 is entirely under tri1 */
   173     else if( tri1->bounds[1] <= tri2->bounds[0] ||
   174              tri2->bounds[1] <= tri1->bounds[0] ||
   175              tri1->bounds[3] <= tri2->bounds[2] ||
   176              tri2->bounds[3] <= tri1->bounds[2] )
   177         return 0; /* tri1 and tri2 don't actually overlap at all */
   178     else { 
   179         struct vertex_struct *tri1v = &pvr2_scene.vertex_array[tri1->poly->vertex_index + tri1->triangle_num];
   180         struct vertex_struct *tri2v = &pvr2_scene.vertex_array[tri2->poly->vertex_index + tri2->triangle_num];
   181         float v[3];
   182         int i;
   183         for( i=0; i<3; i++ ) {
   184             v[i] = tri1->mx * tri2v[i].x + tri1->my * tri2v[i].y + tri1->mz * tri2v[i].z + tri1->d;
   185             if( v[i] > -EPSILON && v[i] < EPSILON ) v[i] = 0;
   186         }
   187         if( v[0] == 0 && v[1] == 0 && v[2] == 0 ) {
   188             return 0; /* coplanar */
   189         }
   190         if( (v[0] >=0 && v[1] >= 0 && v[2] >= 0) ||
   191             (v[0] <= 0 && v[1] <= 0 && v[2] <= 0) ) {
   192             /* Tri is on one side of the plane. Pick an arbitrary point to determine which side */
   193             float t1z = -(tri1->mx * tri2v[0].x + tri1->my * tri2v[0].y + tri1->d) / tri1->mz;
   194             return tri2v[0].z - t1z;
   195         }
   197         /* If the above test failed, then tri2 intersects tri1's plane. This
   198          * doesn't necessarily mean the triangles intersect (although they may).
   199          * For now just return 0, and come back to this later as it's a fairly
   200          * uncommon case in practice. 
   201          */
   202         return 0;
   203     }
   204 }
   206 /**
   207  * This is pretty much a standard merge sort (Unfortunately can't depend on
   208  * the system to provide one. Note we can't use quicksort here - the sort
   209  * must be stable to preserve the order of coplanar triangles.
   210  */
   211 static void sort_triangles( struct sort_triangle **triangles, int num_triangles, struct sort_triangle **out )
   212 {
   213     if( num_triangles > 2 ) {
   214         int l = num_triangles>>1, r=num_triangles-l, i=0,j=0;
   215         struct sort_triangle *left[l];
   216         struct sort_triangle *right[r];
   217         sort_triangles( triangles, l, left );
   218         sort_triangles( triangles+l, r, right );
   220         /* Merge */
   221         while(1) {
   222             if( sort_triangle_compare(left[i], right[j]) <= 0 ) {
   223                 *out++ = left[i++];
   224                 if( i == l ) {
   225                     memcpy( out, &right[j], (r-j)*sizeof(struct sort_triangle *) );        
   226                     break;
   227                 }
   228             } else {
   229                 *out++ = right[j++];
   230                 if( j == r ) {
   231                     memcpy( out, &left[i], (l-i)*sizeof(struct sort_triangle *) );
   232                     break;
   233                 }
   234             }
   235         }
   236     } else if( num_triangles == 2 ) {
   237         if( sort_triangle_compare(triangles[0], triangles[1]) <= 0 ) {
   238             out[0] = triangles[0];
   239             out[1] = triangles[1];
   240         } else {
   241             struct sort_triangle *tmp = triangles[0];
   242             out[0] = triangles[1];
   243             out[1] = tmp;
   244         }
   245     } else {
   246         out[0] = triangles[0];
   247     }
   248 } 
   250 void render_autosort_tile( pvraddr_t tile_entry, int render_mode ) 
   251 {
   252     int num_triangles = sort_count_triangles(tile_entry);
   253     if( num_triangles == 0 ) {
   254         return; /* nothing to do */
   255     } else if( num_triangles == 1 ) { /* Triangle can hardly overlap with itself */
   256         gl_render_tilelist(tile_entry, GL_GEQUAL);
   257     } else { /* Ooh boy here we go... */
   258         int i;
   259         struct sort_triangle triangles[num_triangles+1];
   260         struct sort_triangle *triangle_order[num_triangles+1];
   261         triangles[num_triangles].poly = (void *)SENTINEL;
   262         for( i=0; i<num_triangles; i++ ) {
   263             triangle_order[i] = &triangles[i];
   264         }
   265         int extracted_triangles = sort_extract_triangles(tile_entry, triangles);
   266         assert( extracted_triangles == num_triangles );
   267         sort_triangles( triangle_order, num_triangles, triangle_order );
   268         sort_render_triangles(triangle_order, num_triangles);
   269         glCullFace(GL_BACK);
   270         assert( triangles[num_triangles].poly == (void *)SENTINEL );
   271     }
   272 }
.