Search
lxdream.org :: lxdream/src/pvr2/glrender.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/glrender.c
changeset 653:3202ff01d48e
next655:31a4b664d489
author nkeynes
date Fri Mar 28 12:32:25 2008 +0000 (12 years ago)
permissions -rw-r--r--
last change Merge lxdream-render branch (643:670) to trunk
file annotate diff log raw
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/pvr2/glrender.c Fri Mar 28 12:32:25 2008 +0000
1.3 @@ -0,0 +1,305 @@
1.4 +/**
1.5 + * $Id$
1.6 + *
1.7 + * Standard OpenGL rendering engine.
1.8 + *
1.9 + * Copyright (c) 2005 Nathan Keynes.
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.15 + *
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.20 + */
1.21 +
1.22 +#include <assert.h>
1.23 +#include "display.h"
1.24 +#include "pvr2/pvr2.h"
1.25 +#include "pvr2/scene.h"
1.26 +
1.27 +int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
1.28 + GL_GREATER, GL_NOTEQUAL, GL_GEQUAL,
1.29 + GL_ALWAYS };
1.30 +int pvr2_poly_srcblend[8] = {
1.31 + GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
1.32 + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
1.33 + GL_ONE_MINUS_DST_ALPHA };
1.34 +int pvr2_poly_dstblend[8] = {
1.35 + GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
1.36 + GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
1.37 + GL_ONE_MINUS_DST_ALPHA };
1.38 +int pvr2_poly_texblend[4] = {
1.39 + GL_REPLACE,
1.40 + GL_MODULATE,
1.41 + GL_DECAL,
1.42 + GL_MODULATE
1.43 +};
1.44 +int pvr2_render_colour_format[8] = {
1.45 + COLFMT_BGRA1555, COLFMT_RGB565, COLFMT_BGRA4444, COLFMT_BGRA1555,
1.46 + COLFMT_BGR888, COLFMT_BGRA8888, COLFMT_BGRA8888, COLFMT_BGRA4444 };
1.47 +
1.48 +
1.49 +/**
1.50 + * Clip the tile bounds to the clipping plane.
1.51 + * @return TRUE if the tile was not clipped completely.
1.52 + */
1.53 +static gboolean clip_tile_bounds( uint32_t *tile, float *clip )
1.54 +{
1.55 + if( tile[0] < clip[0] ) tile[0] = clip[0];
1.56 + if( tile[1] > clip[1] ) tile[1] = clip[1];
1.57 + if( tile[2] < clip[2] ) tile[2] = clip[2];
1.58 + if( tile[3] > clip[3] ) tile[3] = clip[3];
1.59 + return tile[0] < tile[1] && tile[2] < tile[3];
1.60 +}
1.61 +
1.62 +void pvr2_scene_load_textures()
1.63 +{
1.64 + int i;
1.65 + for( i=0; i < pvr2_scene.poly_count; i++ ) {
1.66 + struct polygon_struct *poly = &pvr2_scene.poly_array[i];
1.67 + if( POLY1_TEXTURED(poly->context[0]) ) {
1.68 + poly->tex_id = texcache_get_texture( poly->context[2],
1.69 + POLY2_TEX_WIDTH(poly->context[1]),
1.70 + POLY2_TEX_HEIGHT(poly->context[1]) );
1.71 + if( poly->mod_vertex_index != -1 ) {
1.72 + poly->mod_tex_id = texcache_get_texture( poly->context[4],
1.73 + POLY2_TEX_WIDTH(poly->context[3]),
1.74 + POLY2_TEX_HEIGHT(poly->context[3]) );
1.75 + }
1.76 + } else {
1.77 + poly->tex_id = -1;
1.78 + poly->mod_tex_id = -1;
1.79 + }
1.80 + }
1.81 +}
1.82 +
1.83 +
1.84 +
1.85 +/**
1.86 + * Once-off call to setup the OpenGL context.
1.87 + */
1.88 +void pvr2_setup_gl_context()
1.89 +{
1.90 + texcache_gl_init(); // Allocate texture IDs
1.91 + glCullFace( GL_BACK );
1.92 + glEnable( GL_BLEND );
1.93 + glEnable( GL_DEPTH_TEST );
1.94 + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
1.95 + glMatrixMode(GL_MODELVIEW);
1.96 + glLoadIdentity();
1.97 +
1.98 + glEnableClientState( GL_COLOR_ARRAY );
1.99 + glEnableClientState( GL_VERTEX_ARRAY );
1.100 + glEnableClientState( GL_TEXTURE_COORD_ARRAY );
1.101 + glEnableClientState( GL_SECONDARY_COLOR_ARRAY );
1.102 +
1.103 + glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1.104 + glClearDepth(0);
1.105 + glClearStencil(0);
1.106 +}
1.107 +
1.108 +/**
1.109 + * Setup the GL context for the supplied polygon context.
1.110 + * @param context pointer to 3 or 5 words of polygon context
1.111 + * @param modified boolean flag indicating that the modified
1.112 + * version should be used, rather than the normal version.
1.113 + */
1.114 +void render_set_context( uint32_t *context, int render_mode )
1.115 +{
1.116 + uint32_t poly1 = context[0], poly2, texture;
1.117 + if( render_mode == RENDER_FULLMOD ) {
1.118 + poly2 = context[3];
1.119 + texture = context[4];
1.120 + } else {
1.121 + poly2 = context[1];
1.122 + texture = context[2];
1.123 + }
1.124 +
1.125 + glDepthFunc( POLY1_DEPTH_MODE(poly1) );
1.126 + glDepthMask( POLY1_DEPTH_WRITE(poly1) ? GL_TRUE : GL_FALSE );
1.127 +
1.128 + switch( POLY1_CULL_MODE(poly1) ) {
1.129 + case CULL_NONE:
1.130 + case CULL_SMALL:
1.131 + glDisable( GL_CULL_FACE );
1.132 + break;
1.133 + case CULL_CCW:
1.134 + glEnable( GL_CULL_FACE );
1.135 + glFrontFace( GL_CW );
1.136 + break;
1.137 + case CULL_CW:
1.138 + glEnable( GL_CULL_FACE );
1.139 + glFrontFace( GL_CCW );
1.140 + break;
1.141 + }
1.142 +
1.143 + if( POLY1_SPECULAR(poly1) ) {
1.144 + glEnable(GL_COLOR_SUM);
1.145 + } else {
1.146 + glDisable(GL_COLOR_SUM);
1.147 + }
1.148 +
1.149 +
1.150 + if( POLY1_TEXTURED(poly1) ) {
1.151 + int width = POLY2_TEX_WIDTH(poly2);
1.152 + int height = POLY2_TEX_HEIGHT(poly2);
1.153 + glEnable(GL_TEXTURE_2D);
1.154 + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, pvr2_poly_texblend[POLY2_TEX_BLEND(poly2)] );
1.155 + if( POLY2_TEX_CLAMP_U(poly2) ) {
1.156 + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
1.157 + } else {
1.158 + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
1.159 + }
1.160 + if( POLY2_TEX_CLAMP_V(poly2) ) {
1.161 + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
1.162 + } else {
1.163 + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
1.164 + }
1.165 + } else {
1.166 + glDisable( GL_TEXTURE_2D );
1.167 + }
1.168 +
1.169 + glShadeModel( POLY1_SHADE_MODEL(poly1) );
1.170 +
1.171 + int srcblend = POLY2_SRC_BLEND(poly2);
1.172 + int destblend = POLY2_DEST_BLEND(poly2);
1.173 + glBlendFunc( srcblend, destblend );
1.174 +
1.175 + if( POLY2_SRC_BLEND_TARGET(poly2) || POLY2_DEST_BLEND_TARGET(poly2) ) {
1.176 + ERROR( "Accumulation buffer not supported" );
1.177 + }
1.178 +
1.179 +}
1.180 +
1.181 +
1.182 +static void gl_render_poly( struct polygon_struct *poly )
1.183 +{
1.184 + if( poly->tex_id != -1 ) {
1.185 + glBindTexture(GL_TEXTURE_2D, poly->tex_id);
1.186 + }
1.187 + render_set_context( poly->context, RENDER_NORMAL );
1.188 + glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index, poly->vertex_count );
1.189 +}
1.190 +
1.191 +void gl_render_tilelist( pvraddr_t tile_entry )
1.192 +{
1.193 + uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
1.194 + int strip_count;
1.195 + struct polygon_struct *poly;
1.196 +
1.197 + while(1) {
1.198 + uint32_t entry = *tile_list++;
1.199 + switch( entry >> 28 ) {
1.200 + case 0x0F:
1.201 + return; // End-of-list
1.202 + case 0x0E:
1.203 + tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
1.204 + break;
1.205 + case 0x08: case 0x09: case 0x0A: case 0x0B:
1.206 + strip_count = ((entry >> 25) & 0x0F)+1;
1.207 + poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
1.208 + while( strip_count > 0 ) {
1.209 + assert( poly != NULL );
1.210 + gl_render_poly( poly );
1.211 + poly = poly->next;
1.212 + strip_count--;
1.213 + }
1.214 + break;
1.215 + default:
1.216 + if( entry & 0x7E000000 ) {
1.217 + poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
1.218 + gl_render_poly( poly );
1.219 + }
1.220 + }
1.221 + }
1.222 +}
1.223 +
1.224 +
1.225 +/**
1.226 + * Render the currently defined scene in pvr2_scene
1.227 + */
1.228 +void pvr2_scene_render( render_buffer_t buffer )
1.229 +{
1.230 + /* Scene setup */
1.231 + struct timeval start_tv, tex_tv, end_tv;
1.232 +
1.233 + gettimeofday(&start_tv, NULL);
1.234 + display_driver->set_render_target(buffer);
1.235 + pvr2_check_palette_changed();
1.236 + pvr2_scene_load_textures();
1.237 +
1.238 + gettimeofday( &tex_tv, NULL );
1.239 + uint32_t ms = (tex_tv.tv_sec - start_tv.tv_sec) * 1000 +
1.240 + (tex_tv.tv_usec - start_tv.tv_usec)/1000;
1.241 + DEBUG( "Scene setup in %dms", ms );
1.242 +
1.243 + /* Setup view projection matrix */
1.244 + glMatrixMode(GL_PROJECTION);
1.245 + glLoadIdentity();
1.246 + float nearz = pvr2_scene.bounds[4];
1.247 + float farz = pvr2_scene.bounds[5];
1.248 + if( nearz == farz ) {
1.249 + farz*= 2.0;
1.250 + }
1.251 + glOrtho( 0, pvr2_scene.buffer_width, pvr2_scene.buffer_height, 0,
1.252 + -farz, -nearz );
1.253 + float alphaRef = ((float)(MMIO_READ(PVR2, RENDER_ALPHA_REF)&0xFF)+1)/256.0;
1.254 + glAlphaFunc( GL_GEQUAL, alphaRef );
1.255 +
1.256 + /* Clear the buffer (FIXME: May not want always want to do this) */
1.257 + glDisable( GL_SCISSOR_TEST );
1.258 + glDepthMask( GL_TRUE );
1.259 + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
1.260 +
1.261 + /* Setup vertex array pointers */
1.262 + glInterleavedArrays(GL_T2F_C4UB_V3F, sizeof(struct vertex_struct), pvr2_scene.vertex_array);
1.263 + glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].offset_rgba );
1.264 +
1.265 + uint32_t bgplane_mode = MMIO_READ(PVR2, RENDER_BGPLANE);
1.266 + uint32_t *bgplane = pvr2_scene.pvr2_pbuf + (((bgplane_mode & 0x00FFFFFF)) >> 3) ;
1.267 + render_backplane( bgplane, pvr2_scene.buffer_width, pvr2_scene.buffer_height, bgplane_mode );
1.268 +
1.269 + glEnable( GL_SCISSOR_TEST );
1.270 +
1.271 + /* Process the segment list */
1.272 + struct tile_segment *segment = pvr2_scene.segment_list;
1.273 + do {
1.274 + int tilex = SEGMENT_X(segment->control);
1.275 + int tiley = SEGMENT_Y(segment->control);
1.276 +
1.277 + int tile_bounds[4] = { tilex << 5, (tilex+1)<<5, tiley<<5, (tiley+1)<<5 };
1.278 + if( !clip_tile_bounds(tile_bounds, pvr2_scene.bounds) ) {
1.279 + continue; // fully clipped, skip tile
1.280 + }
1.281 +
1.282 + /* Clip to the visible part of the tile */
1.283 + glScissor( tile_bounds[0], pvr2_scene.buffer_height-tile_bounds[3],
1.284 + tile_bounds[1]-tile_bounds[0], tile_bounds[3] - tile_bounds[2] );
1.285 + if( IS_TILE_PTR(segment->opaque_ptr) ) {
1.286 + gl_render_tilelist(segment->opaque_ptr);
1.287 + }
1.288 + if( IS_TILE_PTR(segment->trans_ptr) ) {
1.289 + if( pvr2_scene.sort_mode == SORT_NEVER ||
1.290 + (pvr2_scene.sort_mode == SORT_TILEFLAG && (segment->control&SEGMENT_SORT_TRANS))) {
1.291 + gl_render_tilelist(segment->trans_ptr);
1.292 + } else {
1.293 + render_autosort_tile(segment->trans_ptr, RENDER_NORMAL );
1.294 + }
1.295 + }
1.296 + if( IS_TILE_PTR(segment->punchout_ptr) ) {
1.297 + glEnable(GL_ALPHA_TEST );
1.298 + render_autosort_tile(segment->punchout_ptr, RENDER_NORMAL );
1.299 + glDisable(GL_ALPHA_TEST );
1.300 + }
1.301 + } while( !IS_LAST_SEGMENT(segment++) );
1.302 + glDisable( GL_SCISSOR_TEST );
1.303 +
1.304 + gettimeofday( &end_tv, NULL );
1.305 + ms = (end_tv.tv_sec - tex_tv.tv_sec) * 1000 +
1.306 + (end_tv.tv_usec - tex_tv.tv_usec)/1000;
1.307 + DEBUG( "Scene render in %dms", ms );
1.308 +}
.