filename | src/pvr2/pvr2mem.c |
changeset | 477:9a373f2ff009 |
prev | 429:e581b90c3fb3 |
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 |
view | annotate | diff | log | raw |
1 /**
2 * $Id: pvr2mem.c,v 1.11 2007-10-31 09:10:23 nkeynes Exp $
3 *
4 * PVR2 (Video) VRAM handling routines (mainly for the 64-bit region)
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 "pvr2.h"
19 #include "asic.h"
20 #include <stdio.h>
21 #include <errno.h>
23 extern unsigned char *video_base;
25 void pvr2_dma_write( sh4addr_t destaddr, unsigned char *src, uint32_t count )
26 {
27 int region;
29 switch( destaddr & 0x13800000 ) {
30 case 0x10000000:
31 case 0x12000000:
32 pvr2_ta_write( src, count );
33 break;
34 case 0x11000000:
35 case 0x11800000:
36 region = MMIO_READ( ASIC, PVRDMARGN1 );
37 if( region == 0 ) {
38 pvr2_vram64_write( destaddr, src, count );
39 } else {
40 char *dest = mem_get_region(destaddr);
41 memcpy( dest, src, count );
42 }
43 break;
44 case 0x10800000:
45 case 0x12800000:
46 pvr2_yuv_write( src, count );
47 break;
48 case 0x13000000:
49 case 0x13800000:
50 region = MMIO_READ( ASIC, PVRDMARGN2 );
51 if( region == 0 ) {
52 pvr2_vram64_write( destaddr, src, count );
53 } else {
54 char *dest = mem_get_region(destaddr);
55 memcpy( dest, src, count );
56 }
57 }
58 }
60 void pvr2_vram64_write( sh4addr_t destaddr, unsigned char *src, uint32_t length )
61 {
62 int bank_flag = (destaddr & 0x04) >> 2;
63 uint32_t *banks[2];
64 uint32_t *dwsrc;
65 int i;
67 destaddr = destaddr & 0x7FFFFF;
68 if( destaddr + length > 0x800000 ) {
69 length = 0x800000 - destaddr;
70 }
72 for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) {
73 texcache_invalidate_page( i );
74 }
76 banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
77 banks[1] = banks[0] + 0x100000;
78 if( bank_flag )
79 banks[0]++;
81 /* Handle non-aligned start of source */
82 if( destaddr & 0x03 ) {
83 unsigned char *dest = ((unsigned char *)banks[bank_flag]) + (destaddr & 0x03);
84 for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
85 *dest++ = *src++;
86 }
87 bank_flag = !bank_flag;
88 }
90 dwsrc = (uint32_t *)src;
91 while( length >= 4 ) {
92 *banks[bank_flag]++ = *dwsrc++;
93 bank_flag = !bank_flag;
94 length -= 4;
95 }
97 /* Handle non-aligned end of source */
98 if( length ) {
99 src = (unsigned char *)dwsrc;
100 unsigned char *dest = (unsigned char *)banks[bank_flag];
101 while( length-- > 0 ) {
102 *dest++ = *src++;
103 }
104 }
105 }
107 /**
108 * Write an image to 64-bit vram, with a line-stride different from the line-size.
109 * The destaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
110 * must be multiples of 4.
111 */
112 void pvr2_vram64_write_stride( sh4addr_t destaddr, unsigned char *src, uint32_t line_bytes,
113 uint32_t line_stride_bytes, uint32_t line_count )
114 {
115 int bank_flag = (destaddr & 0x04) >> 2;
116 uint32_t *banks[2];
117 uint32_t *dwsrc;
118 uint32_t line_gap;
119 int line_gap_flag;
120 int i,j;
122 destaddr = destaddr & 0x7FFFF8;
123 i = line_stride_bytes - line_bytes;
124 line_gap_flag = i & 0x04;
125 line_gap = i >> 3;
126 line_bytes >>= 2;
128 for( i=destaddr & 0xFFFFF000; i < destaddr + line_stride_bytes*line_count; i+= PAGE_SIZE ) {
129 texcache_invalidate_page( i );
130 }
132 banks[0] = (uint32_t *)(video_base + (destaddr >>1));
133 banks[1] = banks[0] + 0x100000;
134 if( bank_flag )
135 banks[0]++;
137 dwsrc = (uint32_t *)src;
138 for( i=0; i<line_count; i++ ) {
139 for( j=0; j<line_bytes; j++ ) {
140 *banks[bank_flag]++ = *dwsrc++;
141 bank_flag = !bank_flag;
142 }
143 banks[0] += line_gap;
144 banks[1] += line_gap;
145 if( line_gap_flag ) {
146 banks[bank_flag]++;
147 bank_flag = !bank_flag;
148 }
149 }
150 }
152 /**
153 * Read an image from 64-bit vram, with a destination line-stride different from the line-size.
154 * The srcaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
155 * must be multiples of 4. line_stride_bytes must be >= line_bytes.
156 * This method is used to extract a "stride" texture from vram.
157 */
158 void pvr2_vram64_read_stride( unsigned char *dest, uint32_t dest_line_bytes, sh4addr_t srcaddr,
159 uint32_t src_line_bytes, uint32_t line_count )
160 {
161 int bank_flag = (srcaddr & 0x04) >> 2;
162 uint32_t *banks[2];
163 uint32_t *dwdest;
164 uint32_t dest_line_gap = 0;
165 uint32_t src_line_gap = 0;
166 uint32_t line_bytes;
167 int src_line_gap_flag;
168 int i,j;
170 srcaddr = srcaddr & 0x7FFFF8;
171 if( src_line_bytes <= dest_line_bytes ) {
172 dest_line_gap = (dest_line_bytes - src_line_bytes) >> 2;
173 src_line_gap = 0;
174 src_line_gap_flag = 0;
175 line_bytes = src_line_bytes >> 2;
176 } else {
177 i = (src_line_bytes - dest_line_bytes);
178 src_line_gap_flag = i & 0x04;
179 src_line_gap = i >> 3;
180 line_bytes = dest_line_bytes >> 2;
181 }
183 banks[0] = (uint32_t *)(video_base + (srcaddr>>1));
184 banks[1] = banks[0] + 0x100000;
185 if( bank_flag )
186 banks[0]++;
188 dwdest = (uint32_t *)dest;
189 for( i=0; i<line_count; i++ ) {
190 for( j=0; j<line_bytes; j++ ) {
191 *dwdest++ = *banks[bank_flag]++;
192 bank_flag = !bank_flag;
193 }
194 dwdest += dest_line_gap;
195 banks[0] += src_line_gap;
196 banks[1] += src_line_gap;
197 if( src_line_gap_flag ) {
198 banks[bank_flag]++;
199 bank_flag = !bank_flag;
200 }
201 }
202 }
205 /**
206 * @param dest Destination image buffer
207 * @param banks Source data expressed as two bank pointers
208 * @param offset Offset into banks[0] specifying where the next byte
209 * to read is (0..3)
210 * @param x1,y1 Destination coordinates
211 * @param width Width of current destination block
212 * @param stride Total width of image (ie stride) in bytes
213 */
215 static void pvr2_vram64_detwiddle_4( uint8_t *dest, uint8_t *banks[2], int offset,
216 int x1, int y1, int width, int stride )
217 {
218 if( width == 2 ) {
219 x1 = x1 >> 1;
220 uint8_t t1 = *banks[offset<4?0:1]++;
221 uint8_t t2 = *banks[offset<3?0:1]++;
222 dest[y1*stride + x1] = (t1 & 0x0F) | (t2<<4);
223 dest[(y1+1)*stride + x1] = (t1>>4) | (t2&0xF0);
224 } else if( width == 4 ) {
225 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, 2, stride );
226 pvr2_vram64_detwiddle_4( dest, banks, offset+2, x1, y1+2, 2, stride );
227 pvr2_vram64_detwiddle_4( dest, banks, offset+4, x1+2, y1, 2, stride );
228 pvr2_vram64_detwiddle_4( dest, banks, offset+6, x1+2, y1+2, 2, stride );
230 } else {
231 int subdivide = width >> 1;
232 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, subdivide, stride );
233 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
234 pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
235 pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
236 }
237 }
239 /**
240 * @param dest Destination image buffer
241 * @param banks Source data expressed as two bank pointers
242 * @param offset Offset into banks[0] specifying where the next byte
243 * to read is (0..3)
244 * @param x1,y1 Destination coordinates
245 * @param width Width of current destination block
246 * @param stride Total width of image (ie stride)
247 */
249 static void pvr2_vram64_detwiddle_8( uint8_t *dest, uint8_t *banks[2], int offset,
250 int x1, int y1, int width, int stride )
251 {
252 if( width == 2 ) {
253 dest[y1*stride + x1] = *banks[0]++;
254 dest[(y1+1)*stride + x1] = *banks[offset<3?0:1]++;
255 dest[y1*stride + x1 + 1] = *banks[offset<2?0:1]++;
256 dest[(y1+1)*stride + x1 + 1] = *banks[offset==0?0:1]++;
257 uint8_t *tmp = banks[0]; /* swap banks */
258 banks[0] = banks[1];
259 banks[1] = tmp;
260 } else {
261 int subdivide = width >> 1;
262 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1, subdivide, stride );
263 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
264 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
265 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
266 }
267 }
269 /**
270 * @param dest Destination image buffer
271 * @param banks Source data expressed as two bank pointers
272 * @param offset Offset into banks[0] specifying where the next word
273 * to read is (0 or 1)
274 * @param x1,y1 Destination coordinates
275 * @param width Width of current destination block
276 * @param stride Total width of image (ie stride)
277 */
279 static void pvr2_vram64_detwiddle_16( uint16_t *dest, uint16_t *banks[2], int offset,
280 int x1, int y1, int width, int stride )
281 {
282 if( width == 2 ) {
283 dest[y1*stride + x1] = *banks[0]++;
284 dest[(y1+1)*stride + x1] = *banks[offset]++;
285 dest[y1*stride + x1 + 1] = *banks[1]++;
286 dest[(y1+1)*stride + x1 + 1] = *banks[offset^1]++;
287 } else {
288 int subdivide = width >> 1;
289 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1, subdivide, stride );
290 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
291 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
292 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
293 }
294 }
296 /**
297 * Read an image from 64-bit vram stored as twiddled 4-bit pixels. The
298 * image is written out to the destination in detwiddled form.
299 * @param dest destination buffer, which must be at least width*height/2 in length
300 * @param srcaddr source address in vram
301 * @param width image width (must be a power of 2)
302 * @param height image height (must be a power of 2)
303 */
304 void pvr2_vram64_read_twiddled_4( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
305 {
306 int offset_flag = (srcaddr & 0x07);
307 uint8_t *banks[2];
308 uint8_t *wdest = (uint8_t*)dest;
309 uint32_t stride = width >> 1;
310 int i;
312 srcaddr = srcaddr & 0x7FFFF8;
314 banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
315 banks[1] = banks[0] + 0x400000;
316 if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
317 uint8_t *tmp = banks[0];
318 banks[0] = banks[1];
319 banks[1] = tmp + 4;
320 offset_flag &= 0x03;
321 }
322 banks[0] += offset_flag;
324 if( width > height ) {
325 for( i=0; i<width; i+=height ) {
326 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, i, 0, height, stride );
327 }
328 } else if( height > width ) {
329 for( i=0; i<height; i+=width ) {
330 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, i, width, stride );
331 }
332 } else if( width == 1 ) {
333 *wdest = *banks[0];
334 } else {
335 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, 0, width, stride );
336 }
337 }
339 /**
340 * Read an image from 64-bit vram stored as twiddled 8-bit pixels. The
341 * image is written out to the destination in detwiddled form.
342 * @param dest destination buffer, which must be at least width*height in length
343 * @param srcaddr source address in vram
344 * @param width image width (must be a power of 2)
345 * @param height image height (must be a power of 2)
346 */
347 void pvr2_vram64_read_twiddled_8( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
348 {
349 int offset_flag = (srcaddr & 0x07);
350 uint8_t *banks[2];
351 uint8_t *wdest = (uint8_t*)dest;
352 int i;
354 srcaddr = srcaddr & 0x7FFFF8;
356 banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
357 banks[1] = banks[0] + 0x400000;
358 if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
359 uint8_t *tmp = banks[0];
360 banks[0] = banks[1];
361 banks[1] = tmp + 4;
362 offset_flag &= 0x03;
363 }
364 banks[0] += offset_flag;
366 if( width > height ) {
367 for( i=0; i<width; i+=height ) {
368 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, i, 0, height, width );
369 }
370 } else if( height > width ) {
371 for( i=0; i<height; i+=width ) {
372 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, i, width, width );
373 }
374 } else if( width == 1 ) {
375 *wdest = *banks[0];
376 } else {
377 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
378 }
379 }
381 /**
382 * Read an image from 64-bit vram stored as twiddled 16-bit pixels. The
383 * image is written out to the destination in detwiddled form.
384 * @param dest destination buffer, which must be at least width*height*2 in length
385 * @param srcaddr source address in vram (must be 16-bit aligned)
386 * @param width image width (must be a power of 2)
387 * @param height image height (must be a power of 2)
388 */
389 void pvr2_vram64_read_twiddled_16( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height ) {
390 int offset_flag = (srcaddr & 0x06) >> 1;
391 uint16_t *banks[2];
392 uint16_t *wdest = (uint16_t*)dest;
393 int i;
395 srcaddr = srcaddr & 0x7FFFF8;
397 banks[0] = (uint16_t *)(video_base + (srcaddr>>1));
398 banks[1] = banks[0] + 0x200000;
399 if( offset_flag & 0x02 ) { // If source is not 64-bit aligned, swap the banks
400 uint16_t *tmp = banks[0];
401 banks[0] = banks[1];
402 banks[1] = tmp + 2;
403 offset_flag &= 0x01;
404 }
405 banks[0] += offset_flag;
408 if( width > height ) {
409 for( i=0; i<width; i+=height ) {
410 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, i, 0, height, width );
411 }
412 } else if( height > width ) {
413 for( i=0; i<height; i+=width ) {
414 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, i, width, width );
415 }
416 } else if( width == 1 ) {
417 *wdest = *banks[0];
418 } else {
419 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
420 }
421 }
423 void pvr2_vram_write_invert( sh4addr_t destaddr, unsigned char *src, uint32_t length, uint32_t line_length,
424 uint32_t src_stride )
425 {
426 unsigned char *dest = video_base + (destaddr & 0x007FFFFF);
427 unsigned char *p = src + length - src_stride;
428 while( p >= src ) {
429 memcpy( dest, p, line_length );
430 p -= src_stride;
431 dest += line_length;
432 }
433 }
435 void pvr2_vram64_read( unsigned char *dest, sh4addr_t srcaddr, uint32_t length )
436 {
437 int bank_flag = (srcaddr & 0x04) >> 2;
438 uint32_t *banks[2];
439 uint32_t *dwdest;
440 int i;
442 srcaddr = srcaddr & 0x7FFFFF;
443 if( srcaddr + length > 0x800000 )
444 length = 0x800000 - srcaddr;
446 banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
447 banks[1] = banks[0] + 0x100000;
448 if( bank_flag )
449 banks[0]++;
451 /* Handle non-aligned start of source */
452 if( srcaddr & 0x03 ) {
453 char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
454 for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
455 *dest++ = *src++;
456 }
457 bank_flag = !bank_flag;
458 }
460 dwdest = (uint32_t *)dest;
461 while( length >= 4 ) {
462 *dwdest++ = *banks[bank_flag]++;
463 bank_flag = !bank_flag;
464 length -= 4;
465 }
467 /* Handle non-aligned end of source */
468 if( length ) {
469 dest = (unsigned char *)dwdest;
470 unsigned char *src = (unsigned char *)banks[bank_flag];
471 while( length-- > 0 ) {
472 *dest++ = *src++;
473 }
474 }
475 }
477 void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
478 {
479 uint32_t tmp[length>>2];
480 FILE *f = fopen(filename, "wo");
481 unsigned int i, j;
483 if( f == NULL ) {
484 ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
485 return;
486 }
487 pvr2_vram64_read( (unsigned char *)tmp, addr, length );
488 fprintf( f, "%08X\n", addr );
489 for( i =0; i<length>>2; i+=8 ) {
490 for( j=i; j<i+8; j++ ) {
491 if( j < length )
492 fprintf( f, " %08X", tmp[j] );
493 else
494 fprintf( f, " " );
495 }
496 fprintf( f, "\n" );
497 }
498 fclose(f);
499 }
501 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f )
502 {
503 unsigned char tmp[length];
504 pvr2_vram64_read( tmp, addr, length );
505 fwrite_dump( tmp, length, f );
506 }
510 /**
511 * Flush the indicated render buffer back to PVR. Caller is responsible for
512 * tracking whether there is actually anything in the buffer.
513 *
514 * @param buffer A render buffer indicating the address to store to, and the
515 * format the data needs to be in.
516 * @param backBuffer TRUE to flush the back buffer, FALSE for
517 * the front buffer.
518 */
519 void pvr2_render_buffer_copy_to_sh4( render_buffer_t buffer )
520 {
521 if( (buffer->address & 0xFF000000) == 0x04000000 ) {
522 /* Interlaced buffer. Go the double copy... :( */
523 unsigned char target[buffer->size];
524 display_driver->read_render_buffer( target, buffer, buffer->rowstride, buffer->colour_format );
525 pvr2_vram64_write( buffer->address, target, buffer->size );
526 } else {
527 /* Regular buffer */
528 unsigned char target[buffer->size];
529 int line_size = buffer->width * colour_formats[buffer->colour_format].bpp;
530 display_driver->read_render_buffer( target, buffer, buffer->rowstride, buffer->colour_format );
531 if( (buffer->scale & 0xFFFF) == 0x0800 ) {
532 pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, line_size << 1 );
533 } else {
534 pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, line_size );
535 }
536 }
537 }
.