Search
lxdream.org :: lxdream/src/pvr2/pvr2mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2mem.c
changeset 352:f0df7a6d4703
prev333:e29561c998f5
next429:e581b90c3fb3
author nkeynes
date Sun Feb 11 10:09:32 2007 +0000 (12 years ago)
permissions -rw-r--r--
last change Bug 27: Implement opengl framebuffer objects
Rewrite much of the final video output stage. Now uses generic "render
buffers", implemented on GL using framebuffer objects + textures.
view annotate diff log raw
     1 /**
     2  * $Id: pvr2mem.c,v 1.9 2007-02-11 10:09: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 "asic.h"
    20 #include <stdio.h>
    21 #include <errno.h>
    23 extern char *video_base;
    25 void pvr2_dma_write( sh4addr_t destaddr, 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, 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 	char *dest = ((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 = (char *)dwsrc;
   100 	char *dest = (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, 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( 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;
   165     uint32_t src_line_gap;
   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( 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,j;
   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( 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,j;
   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( 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,j;
   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, char *src, uint32_t length, uint32_t line_length,
   424 			     uint32_t src_stride )
   425 {
   426     char *dest = video_base + (destaddr & 0x007FFFFF);
   427     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( 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 = (char *)dwdest;
   470 	char *src = (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( (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     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 	char target[buffer->size];
   524 	display_driver->read_render_buffer( buffer, target );
   525 	pvr2_vram64_write( buffer->address, target, buffer->size );
   526     } else {
   527 	/* Regular buffer */
   528         char target[buffer->size];
   529 	int line_size = buffer->width * colour_formats[buffer->colour_format].bpp;
   530 	display_driver->read_render_buffer( buffer, target );
   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 }
.