4 * PVR2 (Video) VRAM handling routines (mainly for the 64-bit region)
6 * Copyright (c) 2005 Nathan Keynes.
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.
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.
24 extern unsigned char *video_base;
26 void pvr2_dma_write( sh4addr_t destaddr, unsigned char *src, uint32_t count )
30 switch( destaddr & 0x13800000 ) {
33 pvr2_ta_write( src, count );
37 region = MMIO_READ( ASIC, PVRDMARGN1 );
39 pvr2_vram64_write( destaddr, src, count );
41 unsigned char *dest = mem_get_region(destaddr);
42 memcpy( dest, src, count );
47 pvr2_yuv_write( src, count );
51 region = MMIO_READ( ASIC, PVRDMARGN2 );
53 pvr2_vram64_write( destaddr, src, count );
55 unsigned char *dest = mem_get_region(destaddr);
56 memcpy( dest, src, count );
61 void pvr2_vram64_write( sh4addr_t destaddr, unsigned char *src, uint32_t length )
63 int bank_flag = (destaddr & 0x04) >> 2;
68 destaddr = destaddr & 0x7FFFFF;
69 if( destaddr + length > 0x800000 ) {
70 length = 0x800000 - destaddr;
73 for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) {
74 texcache_invalidate_page( i );
77 banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
78 banks[1] = banks[0] + 0x100000;
82 /* Handle non-aligned start of source */
83 if( destaddr & 0x03 ) {
84 unsigned char *dest = ((unsigned char *)banks[bank_flag]) + (destaddr & 0x03);
85 for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
88 bank_flag = !bank_flag;
91 dwsrc = (uint32_t *)src;
92 while( length >= 4 ) {
93 *banks[bank_flag]++ = *dwsrc++;
94 bank_flag = !bank_flag;
98 /* Handle non-aligned end of source */
100 src = (unsigned char *)dwsrc;
101 unsigned char *dest = (unsigned char *)banks[bank_flag];
102 while( length-- > 0 ) {
109 * Write an image to 64-bit vram, with a line-stride different from the line-size.
110 * The destaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
111 * must be multiples of 4.
113 void pvr2_vram64_write_stride( sh4addr_t destaddr, unsigned char *src, uint32_t line_bytes,
114 uint32_t line_stride_bytes, uint32_t line_count )
116 int bank_flag = (destaddr & 0x04) >> 2;
123 destaddr = destaddr & 0x7FFFF8;
124 i = line_stride_bytes - line_bytes;
125 line_gap_flag = i & 0x04;
129 for( i=destaddr & 0xFFFFF000; i < destaddr + line_stride_bytes*line_count; i+= PAGE_SIZE ) {
130 texcache_invalidate_page( i );
133 banks[0] = (uint32_t *)(video_base + (destaddr >>1));
134 banks[1] = banks[0] + 0x100000;
138 dwsrc = (uint32_t *)src;
139 for( i=0; i<line_count; i++ ) {
140 for( j=0; j<line_bytes; j++ ) {
141 *banks[bank_flag]++ = *dwsrc++;
142 bank_flag = !bank_flag;
144 banks[0] += line_gap;
145 banks[1] += line_gap;
146 if( line_gap_flag ) {
148 bank_flag = !bank_flag;
154 * Read an image from 64-bit vram, with a destination line-stride different from the line-size.
155 * The srcaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
156 * must be multiples of 4. line_stride_bytes must be >= line_bytes.
157 * This method is used to extract a "stride" texture from vram.
159 void pvr2_vram64_read_stride( unsigned char *dest, uint32_t dest_line_bytes, sh4addr_t srcaddr,
160 uint32_t src_line_bytes, uint32_t line_count )
162 int bank_flag = (srcaddr & 0x04) >> 2;
165 uint32_t dest_line_gap = 0;
166 uint32_t src_line_gap = 0;
168 int src_line_gap_flag;
171 srcaddr = srcaddr & 0x7FFFF8;
172 if( src_line_bytes <= dest_line_bytes ) {
173 dest_line_gap = (dest_line_bytes - src_line_bytes) >> 2;
175 src_line_gap_flag = 0;
176 line_bytes = src_line_bytes >> 2;
178 i = (src_line_bytes - dest_line_bytes);
179 src_line_gap_flag = i & 0x04;
180 src_line_gap = i >> 3;
181 line_bytes = dest_line_bytes >> 2;
184 banks[0] = (uint32_t *)(video_base + (srcaddr>>1));
185 banks[1] = banks[0] + 0x100000;
189 dwdest = (uint32_t *)dest;
190 for( i=0; i<line_count; i++ ) {
191 for( j=0; j<line_bytes; j++ ) {
192 *dwdest++ = *banks[bank_flag]++;
193 bank_flag = !bank_flag;
195 dwdest += dest_line_gap;
196 banks[0] += src_line_gap;
197 banks[1] += src_line_gap;
198 if( src_line_gap_flag ) {
200 bank_flag = !bank_flag;
207 * @param dest Destination image buffer
208 * @param banks Source data expressed as two bank pointers
209 * @param offset Offset into banks[0] specifying where the next byte
211 * @param x1,y1 Destination coordinates
212 * @param width Width of current destination block
213 * @param stride Total width of image (ie stride) in bytes
216 static void pvr2_vram64_detwiddle_4( uint8_t *dest, uint8_t *banks[2], int offset,
217 int x1, int y1, int width, int stride )
221 uint8_t t1 = *banks[offset<4?0:1]++;
222 uint8_t t2 = *banks[offset<3?0:1]++;
223 dest[y1*stride + x1] = (t1 & 0x0F) | (t2<<4);
224 dest[(y1+1)*stride + x1] = (t1>>4) | (t2&0xF0);
225 } else if( width == 4 ) {
226 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, 2, stride );
227 pvr2_vram64_detwiddle_4( dest, banks, offset+2, x1, y1+2, 2, stride );
228 pvr2_vram64_detwiddle_4( dest, banks, offset+4, x1+2, y1, 2, stride );
229 pvr2_vram64_detwiddle_4( dest, banks, offset+6, x1+2, y1+2, 2, stride );
232 int subdivide = width >> 1;
233 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, subdivide, stride );
234 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
235 pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
236 pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
241 * @param dest Destination image buffer
242 * @param banks Source data expressed as two bank pointers
243 * @param offset Offset into banks[0] specifying where the next byte
245 * @param x1,y1 Destination coordinates
246 * @param width Width of current destination block
247 * @param stride Total width of image (ie stride)
250 static void pvr2_vram64_detwiddle_8( uint8_t *dest, uint8_t *banks[2], int offset,
251 int x1, int y1, int width, int stride )
254 dest[y1*stride + x1] = *banks[0]++;
255 dest[(y1+1)*stride + x1] = *banks[offset<3?0:1]++;
256 dest[y1*stride + x1 + 1] = *banks[offset<2?0:1]++;
257 dest[(y1+1)*stride + x1 + 1] = *banks[offset==0?0:1]++;
258 uint8_t *tmp = banks[0]; /* swap banks */
262 int subdivide = width >> 1;
263 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1, subdivide, stride );
264 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
265 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
266 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
271 * @param dest Destination image buffer
272 * @param banks Source data expressed as two bank pointers
273 * @param offset Offset into banks[0] specifying where the next word
274 * to read is (0 or 1)
275 * @param x1,y1 Destination coordinates
276 * @param width Width of current destination block
277 * @param stride Total width of image (ie stride)
280 static void pvr2_vram64_detwiddle_16( uint16_t *dest, uint16_t *banks[2], int offset,
281 int x1, int y1, int width, int stride )
284 dest[y1*stride + x1] = *banks[0]++;
285 dest[(y1+1)*stride + x1] = *banks[offset]++;
286 dest[y1*stride + x1 + 1] = *banks[1]++;
287 dest[(y1+1)*stride + x1 + 1] = *banks[offset^1]++;
289 int subdivide = width >> 1;
290 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1, subdivide, stride );
291 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
292 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
293 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
298 * Read an image from 64-bit vram stored as twiddled 4-bit pixels. The
299 * image is written out to the destination in detwiddled form.
300 * @param dest destination buffer, which must be at least width*height/2 in length
301 * @param srcaddr source address in vram
302 * @param width image width (must be a power of 2)
303 * @param height image height (must be a power of 2)
305 void pvr2_vram64_read_twiddled_4( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
307 int offset_flag = (srcaddr & 0x07);
309 uint8_t *wdest = (uint8_t*)dest;
310 uint32_t stride = width >> 1;
313 srcaddr = srcaddr & 0x7FFFF8;
315 banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
316 banks[1] = banks[0] + 0x400000;
317 if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
318 uint8_t *tmp = banks[0];
323 banks[0] += offset_flag;
325 if( width > height ) {
326 for( i=0; i<width; i+=height ) {
327 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, i, 0, height, stride );
329 } else if( height > width ) {
330 for( i=0; i<height; i+=width ) {
331 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, i, width, stride );
333 } else if( width == 1 ) {
336 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, 0, width, stride );
341 * Read an image from 64-bit vram stored as twiddled 8-bit pixels. The
342 * image is written out to the destination in detwiddled form.
343 * @param dest destination buffer, which must be at least width*height in length
344 * @param srcaddr source address in vram
345 * @param width image width (must be a power of 2)
346 * @param height image height (must be a power of 2)
348 void pvr2_vram64_read_twiddled_8( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
350 int offset_flag = (srcaddr & 0x07);
352 uint8_t *wdest = (uint8_t*)dest;
355 srcaddr = srcaddr & 0x7FFFF8;
357 banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
358 banks[1] = banks[0] + 0x400000;
359 if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
360 uint8_t *tmp = banks[0];
365 banks[0] += offset_flag;
367 if( width > height ) {
368 for( i=0; i<width; i+=height ) {
369 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, i, 0, height, width );
371 } else if( height > width ) {
372 for( i=0; i<height; i+=width ) {
373 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, i, width, width );
375 } else if( width == 1 ) {
378 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
383 * Read an image from 64-bit vram stored as twiddled 16-bit pixels. The
384 * image is written out to the destination in detwiddled form.
385 * @param dest destination buffer, which must be at least width*height*2 in length
386 * @param srcaddr source address in vram (must be 16-bit aligned)
387 * @param width image width (must be a power of 2)
388 * @param height image height (must be a power of 2)
390 void pvr2_vram64_read_twiddled_16( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height ) {
391 int offset_flag = (srcaddr & 0x06) >> 1;
393 uint16_t *wdest = (uint16_t*)dest;
396 srcaddr = srcaddr & 0x7FFFF8;
398 banks[0] = (uint16_t *)(video_base + (srcaddr>>1));
399 banks[1] = banks[0] + 0x200000;
400 if( offset_flag & 0x02 ) { // If source is not 64-bit aligned, swap the banks
401 uint16_t *tmp = banks[0];
406 banks[0] += offset_flag;
409 if( width > height ) {
410 for( i=0; i<width; i+=height ) {
411 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, i, 0, height, width );
413 } else if( height > width ) {
414 for( i=0; i<height; i+=width ) {
415 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, i, width, width );
417 } else if( width == 1 ) {
420 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
424 void pvr2_vram_write_invert( sh4addr_t destaddr, unsigned char *src, uint32_t length, uint32_t line_length,
425 uint32_t src_stride )
427 unsigned char *dest = video_base + (destaddr & 0x007FFFFF);
428 unsigned char *p = src + length - src_stride;
430 memcpy( dest, p, line_length );
436 void pvr2_vram64_read( unsigned char *dest, sh4addr_t srcaddr, uint32_t length )
438 int bank_flag = (srcaddr & 0x04) >> 2;
443 srcaddr = srcaddr & 0x7FFFFF;
444 if( srcaddr + length > 0x800000 )
445 length = 0x800000 - srcaddr;
447 banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
448 banks[1] = banks[0] + 0x100000;
452 /* Handle non-aligned start of source */
453 if( srcaddr & 0x03 ) {
454 char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
455 for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
458 bank_flag = !bank_flag;
461 dwdest = (uint32_t *)dest;
462 while( length >= 4 ) {
463 *dwdest++ = *banks[bank_flag]++;
464 bank_flag = !bank_flag;
468 /* Handle non-aligned end of source */
470 dest = (unsigned char *)dwdest;
471 unsigned char *src = (unsigned char *)banks[bank_flag];
472 while( length-- > 0 ) {
478 void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
480 uint32_t tmp[length>>2];
481 FILE *f = fopen(filename, "wo");
485 ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
488 pvr2_vram64_read( (unsigned char *)tmp, addr, length );
489 fprintf( f, "%08X\n", addr );
490 for( i =0; i<length>>2; i+=8 ) {
491 for( j=i; j<i+8; j++ ) {
493 fprintf( f, " %08X", tmp[j] );
502 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f )
504 unsigned char tmp[length];
505 pvr2_vram64_read( tmp, addr, length );
506 fwrite_dump( tmp, length, f );
512 * Flush the indicated render buffer back to PVR. Caller is responsible for
513 * tracking whether there is actually anything in the buffer.
515 * @param buffer A render buffer indicating the address to store to, and the
516 * format the data needs to be in.
517 * @param backBuffer TRUE to flush the back buffer, FALSE for
520 void pvr2_render_buffer_copy_to_sh4( render_buffer_t buffer )
522 if( (buffer->address & 0xFF000000) == 0x04000000 ) {
523 /* Interlaced buffer. Go the double copy... :( */
524 unsigned char target[buffer->size];
525 display_driver->read_render_buffer( target, buffer, buffer->rowstride, buffer->colour_format );
526 pvr2_vram64_write( buffer->address, target, buffer->size );
529 unsigned char target[buffer->size];
530 int line_size = buffer->width * colour_formats[buffer->colour_format].bpp;
531 display_driver->read_render_buffer( target, buffer, buffer->rowstride, buffer->colour_format );
532 if( (buffer->scale & 0xFFFF) == 0x0800 ) {
533 pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, line_size << 1 );
535 pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, line_size );
.