Search
lxdream.org :: lxdream/src/pvr2/pvr2mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2mem.c
changeset 645:a7392098299c
prev561:533f6b478071
next669:ab344e42bca9
author nkeynes
date Thu Mar 06 08:22:00 2008 +0000 (12 years ago)
branchlxdream-render
permissions -rw-r--r--
last change More refactor work in progress - nearly done now
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"
    24 extern unsigned char *video_base;
    26 void pvr2_dma_write( sh4addr_t destaddr, unsigned char *src, uint32_t count )
    27 {
    28     int region;
    30     switch( destaddr & 0x13800000 ) {
    31     case 0x10000000:
    32     case 0x12000000:
    33 	pvr2_ta_write( src, count );
    34 	break;
    35     case 0x11000000:
    36     case 0x11800000:
    37 	region = MMIO_READ( ASIC, PVRDMARGN1 );
    38 	if( region == 0 ) {
    39 	    pvr2_vram64_write( destaddr, src, count );
    40 	} else {
    41 	    unsigned char *dest = mem_get_region(destaddr);
    42 	    memcpy( dest, src, count );
    43 	}
    44 	break;
    45     case 0x10800000:
    46     case 0x12800000:
    47 	pvr2_yuv_write( src, count );
    48 	break;
    49     case 0x13000000:
    50     case 0x13800000:
    51 	region = MMIO_READ( ASIC, PVRDMARGN2 );
    52 	if( region == 0 ) {
    53 	    pvr2_vram64_write( destaddr, src, count );
    54 	} else {
    55 	    unsigned char *dest = mem_get_region(destaddr);
    56 	    memcpy( dest, src, count );
    57 	}
    58     }	    
    59 }
    61 void pvr2_vram64_write( sh4addr_t destaddr, unsigned char *src, uint32_t length )
    62 {
    63     int bank_flag = (destaddr & 0x04) >> 2;
    64     uint32_t *banks[2];
    65     uint32_t *dwsrc;
    66     int i;
    68     destaddr = destaddr & 0x7FFFFF;
    69     if( destaddr + length > 0x800000 ) {
    70 	length = 0x800000 - destaddr;
    71     }
    73     for( i=destaddr & 0xFFFFF000; i < destaddr + length; i+= PAGE_SIZE ) {
    74 	texcache_invalidate_page( i );
    75     }
    77     banks[0] = ((uint32_t *)(video_base + ((destaddr & 0x007FFFF8) >>1)));
    78     banks[1] = banks[0] + 0x100000;
    79     if( bank_flag ) 
    80 	banks[0]++;
    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-- ) {
    86 	    *dest++ = *src++;
    87 	}
    88 	bank_flag = !bank_flag;
    89     }
    91     dwsrc = (uint32_t *)src;
    92     while( length >= 4 ) {
    93 	*banks[bank_flag]++ = *dwsrc++;
    94 	bank_flag = !bank_flag;
    95 	length -= 4;
    96     }
    98     /* Handle non-aligned end of source */
    99     if( length ) {
   100 	src = (unsigned char *)dwsrc;
   101 	unsigned char *dest = (unsigned char *)banks[bank_flag];
   102 	while( length-- > 0 ) {
   103 	    *dest++ = *src++;
   104 	}
   105     }  
   106 }
   108 /**
   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.
   112  */
   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 )
   115 {
   116     int bank_flag = (destaddr & 0x04) >> 2;
   117     uint32_t *banks[2];
   118     uint32_t *dwsrc;
   119     uint32_t line_gap;
   120     int line_gap_flag;
   121     int i,j;
   123     destaddr = destaddr & 0x7FFFF8;
   124     i = line_stride_bytes - line_bytes;
   125     line_gap_flag = i & 0x04;
   126     line_gap = i >> 3;
   127     line_bytes >>= 2;
   129     for( i=destaddr & 0xFFFFF000; i < destaddr + line_stride_bytes*line_count; i+= PAGE_SIZE ) {
   130 	texcache_invalidate_page( i );
   131     }
   133     banks[0] = (uint32_t *)(video_base + (destaddr >>1));
   134     banks[1] = banks[0] + 0x100000;
   135     if( bank_flag ) 
   136 	banks[0]++;
   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;
   143 	}
   144 	banks[0] += line_gap;
   145 	banks[1] += line_gap;
   146 	if( line_gap_flag ) {
   147 	    banks[bank_flag]++;
   148 	    bank_flag = !bank_flag;
   149 	}
   150     }    
   151 }
   153 /**
   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.
   158  */
   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 )
   161 {
   162     int bank_flag = (srcaddr & 0x04) >> 2;
   163     uint32_t *banks[2];
   164     uint32_t *dwdest;
   165     uint32_t dest_line_gap = 0;
   166     uint32_t src_line_gap = 0;
   167     uint32_t line_bytes;
   168     int src_line_gap_flag;
   169     int i,j;
   171     srcaddr = srcaddr & 0x7FFFF8;
   172     if( src_line_bytes <= dest_line_bytes ) {
   173 	dest_line_gap = (dest_line_bytes - src_line_bytes) >> 2;
   174 	src_line_gap = 0;
   175 	src_line_gap_flag = 0;
   176 	line_bytes = src_line_bytes >> 2;
   177     } else {
   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;
   182     }
   184     banks[0] = (uint32_t *)(video_base + (srcaddr>>1));
   185     banks[1] = banks[0] + 0x100000;
   186     if( bank_flag )
   187 	banks[0]++;
   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;
   194 	}
   195 	dwdest += dest_line_gap;
   196 	banks[0] += src_line_gap;
   197 	banks[1] += src_line_gap;
   198 	if( src_line_gap_flag ) {
   199 	    banks[bank_flag]++;
   200 	    bank_flag = !bank_flag;
   201 	}
   202     }    
   203 }
   206 /**
   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
   210  *  to read is (0..3)
   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
   214  */
   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 )
   218 {
   219     if( width == 2 ) {
   220 	x1 = x1 >> 1;
   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 );
   231     } else {
   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 );
   237     }
   238 }
   240 /**
   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
   244  *  to read is (0..3)
   245  * @param x1,y1 Destination coordinates
   246  * @param width Width of current destination block
   247  * @param stride Total width of image (ie stride)
   248  */
   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 )
   252 {
   253     if( width == 2 ) {
   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 */
   259 	banks[0] = banks[1];
   260 	banks[1] = tmp;
   261     } else {
   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 );
   267     }
   268 }
   270 /**
   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)
   278  */
   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 )
   282 {
   283     if( width == 2 ) {
   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]++;
   288     } else {
   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 );
   294     }
   295 }
   297 /**
   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)
   304  */
   305 void pvr2_vram64_read_twiddled_4( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
   306 {
   307     int offset_flag = (srcaddr & 0x07);
   308     uint8_t *banks[2];
   309     uint8_t *wdest = (uint8_t*)dest;
   310     uint32_t stride = width >> 1;
   311     int i;
   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];
   319 	banks[0] = banks[1];
   320 	banks[1] = tmp + 4;
   321 	offset_flag &= 0x03;
   322     }
   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 );
   328 	}
   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 );
   332 	}
   333     } else if( width == 1 ) {
   334 	*wdest = *banks[0];
   335     } else {
   336 	pvr2_vram64_detwiddle_4( wdest, banks, offset_flag, 0, 0, width, stride );
   337     }   
   338 }
   340 /**
   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)
   347  */
   348 void pvr2_vram64_read_twiddled_8( unsigned char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
   349 {
   350     int offset_flag = (srcaddr & 0x07);
   351     uint8_t *banks[2];
   352     uint8_t *wdest = (uint8_t*)dest;
   353     int i;
   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];
   361 	banks[0] = banks[1];
   362 	banks[1] = tmp + 4;
   363 	offset_flag &= 0x03;
   364     }
   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 );
   370 	}
   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 );
   374 	}
   375     } else if( width == 1 ) {
   376 	*wdest = *banks[0];
   377     } else {
   378 	pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
   379     }   
   380 }
   382 /**
   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)
   389  */
   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;
   392     uint16_t *banks[2];
   393     uint16_t *wdest = (uint16_t*)dest;
   394     int i;
   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];
   402 	banks[0] = banks[1];
   403 	banks[1] = tmp + 2;
   404 	offset_flag &= 0x01;
   405     }
   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 );
   412 	}
   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 );
   416 	}
   417     } else if( width == 1 ) {
   418 	*wdest = *banks[0];
   419     } else {
   420 	pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
   421     }    
   422 }
   424 void pvr2_vram_write_invert( sh4addr_t destaddr, unsigned char *src, uint32_t length, uint32_t line_length,
   425 			     uint32_t src_stride )
   426 {
   427     unsigned char *dest = video_base + (destaddr & 0x007FFFFF);
   428     unsigned char *p = src + length - src_stride;
   429     while( p >= src ) {
   430 	memcpy( dest, p, line_length );
   431 	p -= src_stride;
   432 	dest += line_length;
   433     }
   434 }
   436 void pvr2_vram64_read( unsigned char *dest, sh4addr_t srcaddr, uint32_t length )
   437 {
   438     int bank_flag = (srcaddr & 0x04) >> 2;
   439     uint32_t *banks[2];
   440     uint32_t *dwdest;
   441     int i;
   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;
   449     if( bank_flag )
   450 	banks[0]++;
   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-- ) {
   456 	    *dest++ = *src++;
   457 	}
   458 	bank_flag = !bank_flag;
   459     }
   461     dwdest = (uint32_t *)dest;
   462     while( length >= 4 ) {
   463 	*dwdest++ = *banks[bank_flag]++;
   464 	bank_flag = !bank_flag;
   465 	length -= 4;
   466     }
   468     /* Handle non-aligned end of source */
   469     if( length ) {
   470 	dest = (unsigned char *)dwdest;
   471 	unsigned char *src = (unsigned char *)banks[bank_flag];
   472 	while( length-- > 0 ) {
   473 	    *dest++ = *src++;
   474 	}
   475     }
   476 }
   478 void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
   479 {
   480     uint32_t tmp[length>>2];
   481     FILE *f = fopen(filename, "wo");
   482     unsigned int i, j;
   484     if( f == NULL ) {
   485 	ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
   486 	return;
   487     }
   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++ ) {
   492 	    if( j < length )
   493 		fprintf( f, " %08X", tmp[j] );
   494 	    else
   495 		fprintf( f, "         " );
   496 	}
   497 	fprintf( f, "\n" );
   498     }
   499     fclose(f);
   500 }
   502 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f ) 
   503 {
   504     unsigned char tmp[length];
   505     pvr2_vram64_read( tmp, addr, length );
   506     fwrite_dump( tmp, length, f );
   507 }
   511 /**
   512  * Flush the indicated render buffer back to PVR. Caller is responsible for
   513  * tracking whether there is actually anything in the buffer.
   514  *
   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 
   518  * the front buffer.
   519  */
   520 void pvr2_render_buffer_copy_to_sh4( render_buffer_t buffer )
   521 {
   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 );
   527     } else {
   528 	/* Regular buffer */
   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 );
   534         } else {
   535             pvr2_vram_write_invert( buffer->address, target, buffer->size, line_size, line_size );
   536         }
   537     }
   538 }
.