filename | src/pvr2/pvr2mem.c |
changeset | 315:2d8ba198d62c |
prev | 310:00cd8897ad5e |
next | 325:5717ae5d4746 |
author | nkeynes |
date | Thu Jan 25 08:16:02 2007 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Fix 16-bit palettes Up texture count to 128 |
view | annotate | diff | log | raw |
1 /**
2 * $Id: pvr2mem.c,v 1.5 2007-01-23 11:19:32 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 <stdio.h>
20 #include <errno.h>
22 extern char *video_base;
24 void pvr2_vram64_write( sh4addr_t destaddr, char *src, uint32_t length )
25 {
26 int bank_flag = (destaddr & 0x04) >> 2;
27 uint32_t *banks[2];
28 uint32_t *dwsrc;
29 int i;
31 destaddr = destaddr & 0x7FFFFF;
32 if( destaddr + length > 0x800000 ) {
33 length = 0x800000 - destaddr;
34 }
36 for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) {
37 texcache_invalidate_page( i );
38 }
40 banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
41 banks[1] = banks[0] + 0x100000;
42 if( bank_flag )
43 banks[0]++;
45 /* Handle non-aligned start of source */
46 if( destaddr & 0x03 ) {
47 char *dest = ((char *)banks[bank_flag]) + (destaddr & 0x03);
48 for( i= destaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
49 *dest++ = *src++;
50 }
51 bank_flag = !bank_flag;
52 }
54 dwsrc = (uint32_t *)src;
55 while( length >= 4 ) {
56 *banks[bank_flag]++ = *dwsrc++;
57 bank_flag = !bank_flag;
58 length -= 4;
59 }
61 /* Handle non-aligned end of source */
62 if( length ) {
63 src = (char *)dwsrc;
64 char *dest = (char *)banks[bank_flag];
65 while( length-- > 0 ) {
66 *dest++ = *src++;
67 }
68 }
69 }
71 /**
72 * Write an image to 64-bit vram, with a line-stride different from the line-size.
73 * The destaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
74 * must be multiples of 4.
75 */
76 void pvr2_vram64_write_stride( sh4addr_t destaddr, char *src, uint32_t line_bytes,
77 uint32_t line_stride_bytes, uint32_t line_count )
78 {
79 int bank_flag = (destaddr & 0x04) >> 2;
80 uint32_t *banks[2];
81 uint32_t *dwsrc;
82 uint32_t line_gap;
83 int line_gap_flag;
84 int i,j;
86 destaddr = destaddr & 0x7FFFF8;
87 i = line_stride_bytes - line_bytes;
88 line_gap_flag = i & 0x04;
89 line_gap = i >> 3;
90 line_bytes >>= 2;
92 for( i=destaddr & 0xFFFFF000; i < destaddr + line_stride_bytes*line_count; i+= PAGE_SIZE ) {
93 texcache_invalidate_page( i );
94 }
96 banks[0] = (uint32_t *)(video_base + (destaddr >>1));
97 banks[1] = banks[0] + 0x100000;
98 if( bank_flag )
99 banks[0]++;
101 dwsrc = (uint32_t *)src;
102 for( i=0; i<line_count; i++ ) {
103 for( j=0; j<line_bytes; j++ ) {
104 *banks[bank_flag]++ = *dwsrc++;
105 bank_flag = !bank_flag;
106 }
107 banks[0] += line_gap;
108 banks[1] += line_gap;
109 if( line_gap_flag ) {
110 banks[bank_flag]++;
111 bank_flag = !bank_flag;
112 }
113 }
114 }
116 /**
117 * Read an image from 64-bit vram, with a destination line-stride different from the line-size.
118 * The srcaddr must be 32-bit aligned, and both line_bytes and line_stride_bytes
119 * must be multiples of 4. line_stride_bytes must be >= line_bytes.
120 * This method is used to extract a "stride" texture from vram.
121 */
122 void pvr2_vram64_read_stride( char *dest, uint32_t dest_line_bytes, sh4addr_t srcaddr,
123 uint32_t src_line_bytes, uint32_t line_count )
124 {
125 int bank_flag = (srcaddr & 0x04) >> 2;
126 uint32_t *banks[2];
127 uint32_t *dwdest;
128 uint32_t dest_line_gap;
129 uint32_t src_line_gap;
130 uint32_t line_bytes;
131 int src_line_gap_flag;
132 int i,j;
134 srcaddr = srcaddr & 0x7FFFF8;
135 if( src_line_bytes <= dest_line_bytes ) {
136 dest_line_gap = (dest_line_bytes - src_line_bytes) >> 2;
137 src_line_gap = 0;
138 src_line_gap_flag = 0;
139 line_bytes = src_line_bytes >> 2;
140 } else {
141 i = (src_line_bytes - dest_line_bytes);
142 src_line_gap_flag = i & 0x04;
143 src_line_gap = i >> 3;
144 line_bytes = dest_line_bytes >> 2;
145 }
147 banks[0] = (uint32_t *)(video_base + (srcaddr>>1));
148 banks[1] = banks[0] + 0x100000;
149 if( bank_flag )
150 banks[0]++;
152 dwdest = (uint32_t *)dest;
153 for( i=0; i<line_count; i++ ) {
154 for( j=0; j<line_bytes; j++ ) {
155 *dwdest++ = *banks[bank_flag]++;
156 bank_flag = !bank_flag;
157 }
158 dwdest += dest_line_gap;
159 banks[0] += src_line_gap;
160 banks[1] += src_line_gap;
161 if( src_line_gap_flag ) {
162 banks[bank_flag]++;
163 bank_flag = !bank_flag;
164 }
165 }
166 }
169 /**
170 * @param dest Destination image buffer
171 * @param banks Source data expressed as two bank pointers
172 * @param offset Offset into banks[0] specifying where the next byte
173 * to read is (0..3)
174 * @param x1,y1 Destination coordinates
175 * @param width Width of current destination block
176 * @param stride Total width of image (ie stride) in bytes
177 */
179 static void pvr2_vram64_detwiddle_4( uint8_t *dest, uint8_t *banks[2], int offset,
180 int x1, int y1, int width, int stride )
181 {
182 if( width == 2 ) {
183 x1 = x1 >> 1;
184 uint8_t t1 = *banks[offset<4?0:1]++;
185 uint8_t t2 = *banks[offset<3?0:1]++;
186 dest[y1*stride + x1] = (t1 & 0x0F) | (t2<<4);
187 dest[(y1+1)*stride + x1] = (t1>>4) | (t2&0xF0);
188 } else if( width == 4 ) {
189 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, 2, stride );
190 pvr2_vram64_detwiddle_4( dest, banks, offset+2, x1, y1+2, 2, stride );
191 pvr2_vram64_detwiddle_4( dest, banks, offset+4, x1+2, y1, 2, stride );
192 pvr2_vram64_detwiddle_4( dest, banks, offset+6, x1+2, y1+2, 2, stride );
194 } else {
195 int subdivide = width >> 1;
196 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1, subdivide, stride );
197 pvr2_vram64_detwiddle_4( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
198 pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
199 pvr2_vram64_detwiddle_4( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
200 }
201 }
203 /**
204 * @param dest Destination image buffer
205 * @param banks Source data expressed as two bank pointers
206 * @param offset Offset into banks[0] specifying where the next byte
207 * to read is (0..3)
208 * @param x1,y1 Destination coordinates
209 * @param width Width of current destination block
210 * @param stride Total width of image (ie stride)
211 */
213 static void pvr2_vram64_detwiddle_8( uint8_t *dest, uint8_t *banks[2], int offset,
214 int x1, int y1, int width, int stride )
215 {
216 if( width == 2 ) {
217 dest[y1*stride + x1] = *banks[0]++;
218 dest[(y1+1)*stride + x1] = *banks[offset<3?0:1]++;
219 dest[y1*stride + x1 + 1] = *banks[offset<2?0:1]++;
220 dest[(y1+1)*stride + x1 + 1] = *banks[offset==0?0:1]++;
221 uint8_t *tmp = banks[0]; /* swap banks */
222 banks[0] = banks[1];
223 banks[1] = tmp;
224 } else {
225 int subdivide = width >> 1;
226 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1, subdivide, stride );
227 pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
228 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
229 pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
230 }
231 }
233 /**
234 * @param dest Destination image buffer
235 * @param banks Source data expressed as two bank pointers
236 * @param offset Offset into banks[0] specifying where the next word
237 * to read is (0 or 1)
238 * @param x1,y1 Destination coordinates
239 * @param width Width of current destination block
240 * @param stride Total width of image (ie stride)
241 */
243 static void pvr2_vram64_detwiddle_16( uint16_t *dest, uint16_t *banks[2], int offset,
244 int x1, int y1, int width, int stride )
245 {
246 if( width == 2 ) {
247 dest[y1*stride + x1] = *banks[0]++;
248 dest[(y1+1)*stride + x1] = *banks[offset]++;
249 dest[y1*stride + x1 + 1] = *banks[1]++;
250 dest[(y1+1)*stride + x1 + 1] = *banks[offset^1]++;
251 } else {
252 int subdivide = width >> 1;
253 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1, subdivide, stride );
254 pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1+subdivide, subdivide, stride );
255 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1, subdivide, stride );
256 pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, stride );
257 }
258 }
260 /**
261 * Read an image from 64-bit vram stored as twiddled 4-bit pixels. The
262 * image is written out to the destination in detwiddled form.
263 * @param dest destination buffer, which must be at least width*height/2 in length
264 * @param srcaddr source address in vram
265 * @param width image width (must be a power of 2)
266 * @param height image height (must be a power of 2)
267 */
268 void pvr2_vram64_read_twiddled_4( char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
269 {
270 int offset_flag = (srcaddr & 0x07);
271 uint8_t *banks[2];
272 uint8_t *wdest = (uint8_t*)dest;
273 uint32_t stride = width >> 1;
274 int i,j;
276 srcaddr = srcaddr & 0x7FFFF8;
278 banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
279 banks[1] = banks[0] + 0x400000;
280 if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
281 uint8_t *tmp = banks[0];
282 banks[0] = banks[1];
283 banks[1] = tmp + 4;
284 offset_flag &= 0x03;
285 }
286 banks[0] += offset_flag;
288 if( width > height ) {
289 for( i=0; i<width; i+=height ) {
290 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, i, 0, height, stride );
291 }
292 } else if( height > width ) {
293 for( i=0; i<height; i+=width ) {
294 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, i, width, stride );
295 }
296 } else if( width == 1 ) {
297 *wdest = *banks[0];
298 } else {
299 pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, 0, width, stride );
300 }
301 }
303 /**
304 * Read an image from 64-bit vram stored as twiddled 8-bit pixels. The
305 * image is written out to the destination in detwiddled form.
306 * @param dest destination buffer, which must be at least width*height in length
307 * @param srcaddr source address in vram
308 * @param width image width (must be a power of 2)
309 * @param height image height (must be a power of 2)
310 */
311 void pvr2_vram64_read_twiddled_8( char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
312 {
313 int offset_flag = (srcaddr & 0x07);
314 uint8_t *banks[2];
315 uint8_t *wdest = (uint8_t*)dest;
316 int i,j;
318 srcaddr = srcaddr & 0x7FFFF8;
320 banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
321 banks[1] = banks[0] + 0x400000;
322 if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
323 uint8_t *tmp = banks[0];
324 banks[0] = banks[1];
325 banks[1] = tmp + 4;
326 offset_flag &= 0x03;
327 }
328 banks[0] += offset_flag;
330 if( width > height ) {
331 for( i=0; i<width; i+=height ) {
332 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, i, 0, height, width );
333 }
334 } else if( height > width ) {
335 for( i=0; i<height; i+=width ) {
336 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, i, width, width );
337 }
338 } else if( width == 1 ) {
339 *wdest = *banks[0];
340 } else {
341 pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
342 }
343 }
345 /**
346 * Read an image from 64-bit vram stored as twiddled 16-bit pixels. The
347 * image is written out to the destination in detwiddled form.
348 * @param dest destination buffer, which must be at least width*height*2 in length
349 * @param srcaddr source address in vram (must be 16-bit aligned)
350 * @param width image width (must be a power of 2)
351 * @param height image height (must be a power of 2)
352 */
353 void pvr2_vram64_read_twiddled_16( char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height ) {
354 int offset_flag = (srcaddr & 0x06) >> 1;
355 uint16_t *banks[2];
356 uint16_t *wdest = (uint16_t*)dest;
357 int i,j;
359 srcaddr = srcaddr & 0x7FFFF8;
361 banks[0] = (uint16_t *)(video_base + (srcaddr>>1));
362 banks[1] = banks[0] + 0x200000;
363 if( offset_flag & 0x02 ) { // If source is not 64-bit aligned, swap the banks
364 uint16_t *tmp = banks[0];
365 banks[0] = banks[1];
366 banks[1] = tmp + 2;
367 offset_flag &= 0x01;
368 }
369 banks[0] += offset_flag;
372 if( width > height ) {
373 for( i=0; i<width; i+=height ) {
374 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, i, 0, height, width );
375 }
376 } else if( height > width ) {
377 for( i=0; i<height; i+=width ) {
378 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, i, width, width );
379 }
380 } else if( width == 1 ) {
381 *wdest = *banks[0];
382 } else {
383 pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
384 }
385 }
387 void pvr2_vram_write_invert( sh4addr_t destaddr, char *src, uint32_t length, uint32_t line_length )
388 {
389 char *dest = video_base + (destaddr & 0x007FFFFF);
390 char *p = src + length - line_length;
391 while( p >= src ) {
392 memcpy( dest, p, line_length );
393 p -= line_length;
394 dest += line_length;
395 }
396 }
398 void pvr2_vram64_read( char *dest, sh4addr_t srcaddr, uint32_t length )
399 {
400 int bank_flag = (srcaddr & 0x04) >> 2;
401 uint32_t *banks[2];
402 uint32_t *dwdest;
403 int i;
405 srcaddr = srcaddr & 0x7FFFFF;
406 if( srcaddr + length > 0x800000 )
407 length = 0x800000 - srcaddr;
409 banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
410 banks[1] = banks[0] + 0x100000;
411 if( bank_flag )
412 banks[0]++;
414 /* Handle non-aligned start of source */
415 if( srcaddr & 0x03 ) {
416 char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
417 for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
418 *dest++ = *src++;
419 }
420 bank_flag = !bank_flag;
421 }
423 dwdest = (uint32_t *)dest;
424 while( length >= 4 ) {
425 *dwdest++ = *banks[bank_flag]++;
426 bank_flag = !bank_flag;
427 length -= 4;
428 }
430 /* Handle non-aligned end of source */
431 if( length ) {
432 dest = (char *)dwdest;
433 char *src = (char *)banks[bank_flag];
434 while( length-- > 0 ) {
435 *dest++ = *src++;
436 }
437 }
438 }
440 void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
441 {
442 uint32_t tmp[length>>2];
443 FILE *f = fopen(filename, "wo");
444 unsigned int i, j;
446 if( f == NULL ) {
447 ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
448 return;
449 }
450 pvr2_vram64_read( tmp, addr, length );
451 fprintf( f, "%08X\n", addr );
452 for( i =0; i<length>>2; i+=8 ) {
453 for( j=i; j<i+8; j++ ) {
454 if( j < length )
455 fprintf( f, " %08X", tmp[j] );
456 else
457 fprintf( f, " " );
458 }
459 fprintf( f, "\n" );
460 }
461 fclose(f);
462 }
464 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f )
465 {
466 char tmp[length];
467 pvr2_vram64_read( tmp, addr, length );
468 fwrite_dump( tmp, length, f );
469 }
473 /**
474 * Flush the indicated render buffer back to PVR. Caller is responsible for
475 * tracking whether there is actually anything in the buffer.
476 *
477 * @param buffer A render buffer indicating the address to store to, and the
478 * format the data needs to be in.
479 * @param backBuffer TRUE to flush the back buffer, FALSE for
480 * the front buffer.
481 */
482 void pvr2_render_buffer_copy_to_sh4( pvr2_render_buffer_t buffer,
483 gboolean backBuffer )
484 {
485 if( buffer->render_addr == -1 )
486 return;
487 GLenum type, format = GL_BGRA;
488 int line_size = buffer->width, size;
490 switch( buffer->colour_format ) {
491 case COLFMT_RGB565:
492 type = GL_UNSIGNED_SHORT_5_6_5;
493 format = GL_BGR;
494 line_size <<= 1;
495 break;
496 case COLFMT_RGB888:
497 type = GL_UNSIGNED_BYTE;
498 format = GL_BGR;
499 line_size = (line_size<<1)+line_size;
500 break;
501 case COLFMT_ARGB1555:
502 type = GL_UNSIGNED_SHORT_5_5_5_1;
503 line_size <<= 1;
504 break;
505 case COLFMT_ARGB4444:
506 type = GL_UNSIGNED_SHORT_4_4_4_4;
507 line_size <<= 1;
508 break;
509 case COLFMT_ARGB8888:
510 type = GL_UNSIGNED_INT_8_8_8_8;
511 line_size <<= 2;
512 break;
513 }
514 size = line_size * buffer->height;
516 if( backBuffer ) {
517 glFinish();
518 glReadBuffer( GL_BACK );
519 } else {
520 glReadBuffer( GL_FRONT );
521 }
523 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
524 /* Interlaced buffer. Go the double copy... :( */
525 char target[size];
526 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
527 pvr2_vram64_write( buffer->render_addr, target, size );
528 } else {
529 /* Regular buffer */
530 char target[size];
531 glReadPixels( 0, 0, buffer->width, buffer->height, format, type, target );
532 pvr2_vram_write_invert( buffer->render_addr, target, size, line_size );
533 }
534 }
537 /**
538 * Copy data from PVR ram into the GL render buffer.
539 *
540 * @param buffer A render buffer indicating the address to read from, and the
541 * format the data is in.
542 * @param backBuffer TRUE to write the back buffer, FALSE for
543 * the front buffer.
544 */
545 void pvr2_render_buffer_copy_from_sh4( pvr2_render_buffer_t buffer,
546 gboolean backBuffer )
547 {
548 if( buffer->render_addr == -1 )
549 return;
550 GLenum type, format = GL_RGBA;
551 int size = buffer->width * buffer->height;
553 switch( buffer->colour_format ) {
554 case COLFMT_RGB565:
555 type = GL_UNSIGNED_SHORT_5_6_5;
556 format = GL_RGB;
557 size <<= 1;
558 break;
559 case COLFMT_RGB888:
560 type = GL_UNSIGNED_BYTE;
561 format = GL_BGR;
562 size = (size<<1)+size;
563 break;
564 case COLFMT_ARGB1555:
565 type = GL_UNSIGNED_SHORT_5_5_5_1;
566 size <<= 1;
567 break;
568 case COLFMT_ARGB4444:
569 type = GL_UNSIGNED_SHORT_4_4_4_4;
570 size <<= 1;
571 break;
572 case COLFMT_ARGB8888:
573 type = GL_UNSIGNED_INT_8_8_8_8;
574 size <<= 2;
575 break;
576 }
578 if( backBuffer ) {
579 glDrawBuffer( GL_BACK );
580 } else {
581 glDrawBuffer( GL_FRONT );
582 }
584 glRasterPos2i( 0, 0 );
585 if( buffer->render_addr & 0xFF000000 == 0x04000000 ) {
586 /* Interlaced buffer. Go the double copy... :( */
587 char target[size];
588 pvr2_vram64_read( target, buffer->render_addr, size );
589 glDrawPixels( buffer->width, buffer->height,
590 format, type, target );
591 } else {
592 /* Regular buffer - go direct */
593 char *target = mem_get_region( buffer->render_addr );
594 glDrawPixels( buffer->width, buffer->height,
595 format, type, target );
596 }
597 }
.