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