filename | src/pvr2/pvr2.c |
changeset | 477:9a373f2ff009 |
prev | 441:0ff0093f3088 |
next | 502:c4ecae2b1b5e |
author | nkeynes |
date | Wed Oct 31 09:10:23 2007 +0000 (16 years ago) |
permissions | -rw-r--r-- |
last change | Add save/restore of render buffers in save states Gzip memory blocks in save states Move front-buffer management back to pvr2 Add screenshot preview when loading save states Various minor fixes and cleanups |
file | annotate | diff | log | raw |
1.1 --- a/src/pvr2/pvr2.c Sat Oct 13 03:59:32 2007 +00001.2 +++ b/src/pvr2/pvr2.c Wed Oct 31 09:10:23 2007 +00001.3 @@ -1,5 +1,5 @@1.4 /**1.5 - * $Id: pvr2.c,v 1.47 2007-10-13 03:59:32 nkeynes Exp $1.6 + * $Id: pvr2.c,v 1.48 2007-10-31 09:10:23 nkeynes Exp $1.7 *1.8 * PVR2 (Video) Core module implementation and MMIO registers.1.9 *1.10 @@ -17,6 +17,7 @@1.11 */1.12 #define MODULE pvr2_module1.14 +#include <assert.h>1.15 #include "dream.h"1.16 #include "eventq.h"1.17 #include "display.h"1.18 @@ -44,11 +45,12 @@1.19 static void pvr2_schedule_scanline_event( int eventid, int line, int minimum_lines, int line_time_ns );1.20 static render_buffer_t pvr2_get_render_buffer( frame_buffer_t frame );1.21 static render_buffer_t pvr2_next_render_buffer( );1.22 +static render_buffer_t pvr2_frame_buffer_to_render_buffer( frame_buffer_t frame );1.23 uint32_t pvr2_get_sync_status();1.25 void pvr2_display_frame( void );1.27 -static int output_colour_formats[] = { COLFMT_ARGB1555, COLFMT_RGB565, COLFMT_RGB888, COLFMT_ARGB8888 };1.28 +static int output_colour_formats[] = { COLFMT_BGRA1555, COLFMT_RGB565, COLFMT_BGR888, COLFMT_BGRA8888 };1.30 struct dreamcast_module pvr2_module = { "PVR2", pvr2_init, pvr2_reset, NULL,1.31 pvr2_run_slice, NULL,1.32 @@ -142,6 +144,7 @@1.34 static void pvr2_reset( void )1.35 {1.36 + int i;1.37 pvr2_state.line_count = 0;1.38 pvr2_state.line_remainder = 0;1.39 pvr2_state.cycles_run = 0;1.40 @@ -157,10 +160,113 @@1.42 pvr2_ta_init();1.43 texcache_flush();1.44 + if( display_driver ) {1.45 + display_driver->display_blank(0);1.46 + for( i=0; i<render_buffer_count; i++ ) {1.47 + display_driver->destroy_render_buffer(render_buffers[i]);1.48 + render_buffers[i] = NULL;1.49 + }1.50 + render_buffer_count = 0;1.51 + }1.52 }1.54 +void pvr2_save_render_buffer( FILE *f, render_buffer_t buffer )1.55 +{1.56 + struct frame_buffer fbuf;1.57 +1.58 + fbuf.width = buffer->width;1.59 + fbuf.height = buffer->height;1.60 + fbuf.rowstride = fbuf.width*3;1.61 + fbuf.colour_format = COLFMT_BGR888;1.62 + fbuf.inverted = buffer->inverted;1.63 + fbuf.data = g_malloc0( buffer->width * buffer->height * 3 );1.64 +1.65 + display_driver->read_render_buffer( fbuf.data, buffer, fbuf.rowstride, COLFMT_BGR888 );1.66 + write_png_to_stream( f, &fbuf );1.67 + g_free( fbuf.data );1.68 +1.69 + fwrite( &buffer->rowstride, sizeof(buffer->rowstride), 1, f );1.70 + fwrite( &buffer->colour_format, sizeof(buffer->colour_format), 1, f );1.71 + fwrite( &buffer->address, sizeof(buffer->address), 1, f );1.72 + fwrite( &buffer->scale, sizeof(buffer->scale), 1, f );1.73 + fwrite( &buffer->flushed, sizeof(buffer->flushed), 1, f );1.74 +1.75 +}1.76 +1.77 +render_buffer_t pvr2_load_render_buffer( FILE *f )1.78 +{1.79 + frame_buffer_t frame = read_png_from_stream( f );1.80 + if( frame == NULL ) {1.81 + return NULL;1.82 + }1.83 +1.84 + render_buffer_t buffer = pvr2_frame_buffer_to_render_buffer(frame);1.85 + assert( buffer != NULL );1.86 + fread( &buffer->rowstride, sizeof(buffer->rowstride), 1, f );1.87 + fread( &buffer->colour_format, sizeof(buffer->colour_format), 1, f );1.88 + fread( &buffer->address, sizeof(buffer->address), 1, f );1.89 + fread( &buffer->scale, sizeof(buffer->scale), 1, f );1.90 + fread( &buffer->flushed, sizeof(buffer->flushed), 1, f );1.91 + return buffer;1.92 +}1.93 +1.94 +1.95 +1.96 +1.97 +void pvr2_save_render_buffers( FILE *f )1.98 +{1.99 + int i;1.100 + fwrite( &render_buffer_count, sizeof(render_buffer_count), 1, f );1.101 + if( displayed_render_buffer != NULL ) {1.102 + i = 1;1.103 + fwrite( &i, sizeof(i), 1, f );1.104 + pvr2_save_render_buffer( f, displayed_render_buffer );1.105 + } else {1.106 + i = 0;1.107 + fwrite( &i, sizeof(i), 1, f );1.108 + }1.109 +1.110 + for( i=0; i<render_buffer_count; i++ ) {1.111 + if( render_buffers[i] != displayed_render_buffer && render_buffers[i] != NULL ) {1.112 + pvr2_save_render_buffer( f, render_buffers[i] );1.113 + }1.114 + }1.115 +}1.116 +1.117 +gboolean pvr2_load_render_buffers( FILE *f )1.118 +{1.119 + uint32_t count;1.120 + int i, has_frontbuffer;1.121 +1.122 + fread( &count, sizeof(count), 1, f );1.123 + if( count >= MAX_RENDER_BUFFERS ) {1.124 + return FALSE;1.125 + }1.126 + fread( &has_frontbuffer, sizeof(has_frontbuffer), 1, f );1.127 + for( i=0; i<render_buffer_count; i++ ) {1.128 + display_driver->destroy_render_buffer(render_buffers[i]);1.129 + render_buffers[i] = NULL;1.130 + }1.131 + render_buffer_count = 0;1.132 +1.133 + if( has_frontbuffer ) {1.134 + displayed_render_buffer = pvr2_load_render_buffer(f);1.135 + display_driver->display_render_buffer( displayed_render_buffer );1.136 + count--;1.137 + }1.138 +1.139 + for( i=0; i<count; i++ ) {1.140 + if( pvr2_load_render_buffer( f ) == NULL ) {1.141 + return FALSE;1.142 + }1.143 + }1.144 + return TRUE;1.145 +}1.146 +1.147 +1.148 static void pvr2_save_state( FILE *f )1.149 {1.150 + pvr2_save_render_buffers( f );1.151 fwrite( &pvr2_state, sizeof(pvr2_state), 1, f );1.152 pvr2_ta_save_state( f );1.153 pvr2_yuv_save_state( f );1.154 @@ -168,6 +274,8 @@1.156 static int pvr2_load_state( FILE *f )1.157 {1.158 + if( !pvr2_load_render_buffers(f) )1.159 + return 1;1.160 if( fread( &pvr2_state, sizeof(pvr2_state), 1, f ) != 1 )1.161 return 1;1.162 if( pvr2_ta_load_state(f) ) {1.163 @@ -220,6 +328,11 @@1.164 return pvr2_state.frame_count;1.165 }1.167 +render_buffer_t pvr2_get_front_buffer()1.168 +{1.169 + return displayed_render_buffer;1.170 +}1.171 +1.172 gboolean pvr2_save_next_scene( const gchar *filename )1.173 {1.174 if( pvr2_state.save_next_render_filename != NULL ) {1.175 @@ -291,14 +404,16 @@1.176 fbuf.address = MMIO_READ( PVR2, DISP_ADDR1 );1.177 }1.178 fbuf.address = (fbuf.address & 0x00FFFFFF) + PVR2_RAM_BASE;1.179 + fbuf.inverted = FALSE;1.180 + fbuf.data = video_base + (fbuf.address&0x00FFFFFF);1.182 render_buffer_t rbuf = pvr2_get_render_buffer( &fbuf );1.183 + if( rbuf == NULL ) {1.184 + rbuf = pvr2_frame_buffer_to_render_buffer( &fbuf );1.185 + }1.186 displayed_render_buffer = rbuf;1.187 if( rbuf != NULL ) {1.188 display_driver->display_render_buffer( rbuf );1.189 - } else {1.190 - fbuf.data = video_base + (fbuf.address&0x00FFFFFF);1.191 - display_driver->display_frame_buffer( &fbuf );1.192 }1.193 }1.194 }1.195 @@ -716,7 +831,8 @@1.196 }1.198 /**1.199 - * Determine the next render buffer to write into. The order of preference is:1.200 + * Allocate a render buffer with the requested parameters.1.201 + * The order of preference is:1.202 * 1. An existing buffer with the same address. (not flushed unless the new1.203 * size is smaller than the old one).1.204 * 2. An existing buffer with the same size chosen by LRU order. Old buffer1.205 @@ -726,23 +842,10 @@1.206 * Note: The current display field(s) will never be overwritten except as a last1.207 * resort.1.208 */1.209 -render_buffer_t pvr2_next_render_buffer()1.210 +render_buffer_t pvr2_alloc_render_buffer( sh4addr_t render_addr, int width, int height )1.211 {1.212 + int i;1.213 render_buffer_t result = NULL;1.214 - uint32_t render_addr = MMIO_READ( PVR2, RENDER_ADDR1 );1.215 - uint32_t render_mode = MMIO_READ( PVR2, RENDER_MODE );1.216 - uint32_t render_scale = MMIO_READ( PVR2, RENDER_SCALER );1.217 - uint32_t render_stride = MMIO_READ( PVR2, RENDER_SIZE ) << 3;1.218 -1.219 - if( render_addr & 0x01000000 ) { /* vram64 */1.220 - render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;1.221 - } else { /* vram32 */1.222 - render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;1.223 - }1.224 -1.225 - int width, height, i;1.226 - int colour_format = pvr2_render_colour_format[render_mode&0x07];1.227 - pvr2_render_getsize( &width, &height );1.229 /* Check existing buffers for an available buffer */1.230 for( i=0; i<render_buffer_count; i++ ) {1.231 @@ -752,6 +855,7 @@1.232 if( displayed_render_buffer == render_buffers[i] ) {1.233 /* Same address, but we can't use it because the1.234 * display has it. Mark it as unaddressed for later.1.235 + */1.236 render_buffers[i]->address = -1;1.237 } else {1.238 /* perfect */1.239 @@ -786,7 +890,9 @@1.240 render_buffers[i] != displayed_render_buffer ) {1.241 /* Never throw away the current "front buffer(s)" */1.242 result = render_buffers[i];1.243 - pvr2_render_buffer_copy_to_sh4( result );1.244 + if( !result->flushed ) {1.245 + pvr2_render_buffer_copy_to_sh4( result );1.246 + }1.247 if( result->width != width || result->height != height ) {1.248 display_driver->destroy_render_buffer(render_buffers[i]);1.249 result = display_driver->create_render_buffer(width,height);1.250 @@ -799,24 +905,68 @@1.251 result = display_driver->create_render_buffer(width,height);1.252 if( result != NULL ) {1.253 render_buffers[render_buffer_count++] = result;1.254 - } else {1.255 - // ERROR( "Failed to obtain a render buffer!" );1.256 - return NULL;1.257 }1.258 }1.259 }1.261 - /* Setup the buffer */1.262 - result->rowstride = render_stride;1.263 - result->colour_format = colour_format;1.264 - result->scale = render_scale;1.265 - result->size = width * height * colour_formats[colour_format].bpp;1.266 - result->address = render_addr;1.267 - result->flushed = FALSE;1.268 + if( result != NULL ) {1.269 + result->address = render_addr;1.270 + }1.271 return result;1.272 }1.274 /**1.275 + * Allocate a render buffer based on the current rendering settings1.276 + */1.277 +render_buffer_t pvr2_next_render_buffer()1.278 +{1.279 + render_buffer_t result = NULL;1.280 + uint32_t render_addr = MMIO_READ( PVR2, RENDER_ADDR1 );1.281 + uint32_t render_mode = MMIO_READ( PVR2, RENDER_MODE );1.282 + uint32_t render_scale = MMIO_READ( PVR2, RENDER_SCALER );1.283 + uint32_t render_stride = MMIO_READ( PVR2, RENDER_SIZE ) << 3;1.284 +1.285 + if( render_addr & 0x01000000 ) { /* vram64 */1.286 + render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE_INT;1.287 + } else { /* vram32 */1.288 + render_addr = (render_addr & 0x00FFFFFF) + PVR2_RAM_BASE;1.289 + }1.290 +1.291 + int width, height;1.292 + int colour_format = pvr2_render_colour_format[render_mode&0x07];1.293 + pvr2_render_getsize( &width, &height );1.294 +1.295 + result = pvr2_alloc_render_buffer( render_addr, width, height );1.296 + /* Setup the buffer */1.297 + if( result != NULL ) {1.298 + result->rowstride = render_stride;1.299 + result->colour_format = colour_format;1.300 + result->scale = render_scale;1.301 + result->size = width * height * colour_formats[colour_format].bpp;1.302 + result->flushed = FALSE;1.303 + result->inverted = TRUE; // render buffers are inverted normally1.304 + }1.305 + return result;1.306 +}1.307 +1.308 +static render_buffer_t pvr2_frame_buffer_to_render_buffer( frame_buffer_t frame )1.309 +{1.310 + render_buffer_t result = pvr2_alloc_render_buffer( frame->address, frame->width, frame->height );1.311 + if( result != NULL ) {1.312 + int bpp = colour_formats[frame->colour_format].bpp;1.313 + result->rowstride = frame->rowstride;1.314 + result->colour_format = frame->colour_format;1.315 + result->scale = 0x400;1.316 + result->size = frame->width * frame->height * bpp;1.317 + result->flushed = TRUE;1.318 + result->inverted = frame->inverted;1.319 + display_driver->load_frame_buffer( frame, result );1.320 + }1.321 + return result;1.322 +}1.323 +1.324 +1.325 +/**1.326 * Invalidate any caching on the supplied address. Specifically, if it falls1.327 * within any of the render buffers, flush the buffer back to PVR2 ram.1.328 */
.