Search
lxdream.org :: lxdream/src/pvr2/pvr2.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2.c
changeset 477:9a373f2ff009
prev441:0ff0093f3088
next502:c4ecae2b1b5e
author nkeynes
date Wed Oct 31 09:10:23 2007 +0000 (12 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 +0000
1.2 +++ b/src/pvr2/pvr2.c Wed Oct 31 09:10:23 2007 +0000
1.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_module
1.13
1.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.24
1.25 void pvr2_display_frame( void );
1.26
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.29
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.33
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.41
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.53
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.155
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.166
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.181
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.197
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 new
1.203 * size is smaller than the old one).
1.204 * 2. An existing buffer with the same size chosen by LRU order. Old buffer
1.205 @@ -726,23 +842,10 @@
1.206 * Note: The current display field(s) will never be overwritten except as a last
1.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.228
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 the
1.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.260
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.273
1.274 /**
1.275 + * Allocate a render buffer based on the current rendering settings
1.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 normally
1.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 falls
1.327 * within any of the render buffers, flush the buffer back to PVR2 ram.
1.328 */
.