Search
lxdream.org :: lxdream/src/pvr2/pvr2mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/pvr2mem.c
changeset 310:00cd8897ad5e
prev309:e2750808d02c
next315:2d8ba198d62c
author nkeynes
date Mon Jan 22 11:45:37 2007 +0000 (14 years ago)
permissions -rw-r--r--
last change Add methods to detwiddle directly out of vram64
view annotate diff log raw
     1 /**
     2  * $Id: pvr2mem.c,v 1.4 2007-01-22 11:45:37 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 }
   168 /**
   169  * @param dest Destination image buffer
   170  * @param banks Source data expressed as two bank pointers
   171  * @param offset Offset into banks[0] specifying where the next byte
   172  *  to read is (0..3)
   173  * @param x1,y1 Destination coordinates
   174  * @param width Width of current destination block
   175  * @param image_width Total width of image (ie stride)
   176  */
   178 static void pvr2_vram64_detwiddle_8( uint8_t *dest, uint8_t *banks[2], int offset,
   179 				     int x1, int y1, int width, int image_width )
   180 {
   181     if( width == 2 ) {
   182 	dest[y1*image_width + x1] = *banks[0]++;
   183 	dest[(y1+1)*image_width + x1] = *banks[offset<3?0:1]++;
   184 	dest[y1*image_width + x1 + 1] = *banks[offset<2?0:1]++;
   185 	dest[(y1+1)*image_width + x1 + 1] = *banks[offset==0?0:1]++;
   186 	uint8_t *tmp = banks[0]; /* swap banks */
   187 	banks[0] = banks[1];
   188 	banks[1] = tmp;
   189     } else {
   190 	int subdivide = width >> 1;
   191 	pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1, subdivide, image_width );
   192 	pvr2_vram64_detwiddle_8( dest, banks, offset, x1, y1+subdivide, subdivide, image_width );
   193 	pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1, subdivide, image_width );
   194 	pvr2_vram64_detwiddle_8( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, image_width );
   195     }
   196 }
   198 /**
   199  * @param dest Destination image buffer
   200  * @param banks Source data expressed as two bank pointers
   201  * @param offset Offset into banks[0] specifying where the next word
   202  *  to read is (0 or 1)
   203  * @param x1,y1 Destination coordinates
   204  * @param width Width of current destination block
   205  * @param image_width Total width of image (ie stride)
   206  */
   208 static void pvr2_vram64_detwiddle_16( uint16_t *dest, uint16_t *banks[2], int offset,
   209 				      int x1, int y1, int width, int image_width )
   210 {
   211     if( width == 2 ) {
   212 	dest[y1*image_width + x1] = *banks[0]++;
   213 	dest[(y1+1)*image_width + x1] = *banks[offset]++;
   214 	dest[y1*image_width + x1 + 1] = *banks[1]++;
   215 	dest[(y1+1)*image_width + x1 + 1] = *banks[offset^1]++;
   216     } else {
   217 	int subdivide = width >> 1;
   218 	pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1, subdivide, image_width );
   219 	pvr2_vram64_detwiddle_16( dest, banks, offset, x1, y1+subdivide, subdivide, image_width );
   220 	pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1, subdivide, image_width );
   221 	pvr2_vram64_detwiddle_16( dest, banks, offset, x1+subdivide, y1+subdivide, subdivide, image_width );
   222     }
   223 }
   225 /**
   226  * Read an image from 64-bit vram stored as twiddled 8-bit pixels. The 
   227  * image is written out to the destination in detwiddled form.
   228  * @param dest destination buffer, which must be at least width*height in length
   229  * @param srcaddr source address in vram
   230  * @param width image width (must be a power of 2)
   231  * @param height image height (must be a power of 2)
   232  */
   233 void pvr2_vram64_read_twiddled_8( char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height )
   234 {
   235     int offset_flag = (srcaddr & 0x07);
   236     uint8_t *banks[2];
   237     uint8_t *wdest = (uint8_t*)dest;
   238     int i,j;
   240     srcaddr = srcaddr & 0x7FFFF8;
   242     banks[0] = (uint8_t *)(video_base + (srcaddr>>1));
   243     banks[1] = banks[0] + 0x400000;
   244     if( offset_flag & 0x04 ) { // If source is not 64-bit aligned, swap the banks
   245 	uint8_t *tmp = banks[0];
   246 	banks[0] = banks[1];
   247 	banks[1] = tmp + 4;
   248 	offset_flag &= 0x03;
   249     }
   250     banks[0] += offset_flag;
   252     if( width > height ) {
   253 	for( i=0; i<width; i+=height ) {
   254 	    pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, i, 0, height, width );
   255 	}
   256     } else if( height > width ) {
   257 	for( i=0; i<height; i+=width ) {
   258 	    pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, i, width, width );
   259 	}
   260     } else if( width == 1 ) {
   261 	*wdest = *banks[0];
   262     } else {
   263 	pvr2_vram64_detwiddle_8( wdest, banks, offset_flag, 0, 0, width, width );
   264     }   
   265 }
   267 /**
   268  * Read an image from 64-bit vram stored as twiddled 16-bit pixels. The 
   269  * image is written out to the destination in detwiddled form.
   270  * @param dest destination buffer, which must be at least width*height*2 in length
   271  * @param srcaddr source address in vram (must be 16-bit aligned)
   272  * @param width image width (must be a power of 2)
   273  * @param height image height (must be a power of 2)
   274  */
   275 void pvr2_vram64_read_twiddled_16( char *dest, sh4addr_t srcaddr, uint32_t width, uint32_t height ) {
   276     int offset_flag = (srcaddr & 0x06) >> 1;
   277     uint16_t *banks[2];
   278     uint16_t *wdest = (uint16_t*)dest;
   279     int i,j;
   281     srcaddr = srcaddr & 0x7FFFF8;
   283     banks[0] = (uint16_t *)(video_base + (srcaddr>>1));
   284     banks[1] = banks[0] + 0x200000;
   285     if( offset_flag & 0x02 ) { // If source is not 64-bit aligned, swap the banks
   286 	uint16_t *tmp = banks[0];
   287 	banks[0] = banks[1];
   288 	banks[1] = tmp + 2;
   289 	offset_flag &= 0x01;
   290     }
   291     banks[0] += offset_flag;
   294     if( width > height ) {
   295 	for( i=0; i<width; i+=height ) {
   296 	    pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, i, 0, height, width );
   297 	}
   298     } else if( height > width ) {
   299 	for( i=0; i<height; i+=width ) {
   300 	    pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, i, width, width );
   301 	}
   302     } else if( width == 1 ) {
   303 	*wdest = *banks[0];
   304     } else {
   305 	pvr2_vram64_detwiddle_16( wdest, banks, offset_flag, 0, 0, width, width );
   306     }    
   307 }
   309 void pvr2_vram_write_invert( sh4addr_t destaddr, char *src, uint32_t length, uint32_t line_length )
   310 {
   311     char *dest = video_base + (destaddr & 0x007FFFFF);
   312     char *p = src + length - line_length;
   313     while( p >= src ) {
   314 	memcpy( dest, p, line_length );
   315 	p -= line_length;
   316 	dest += line_length;
   317     }
   318 }
   320 void pvr2_vram64_read( char *dest, sh4addr_t srcaddr, uint32_t length )
   321 {
   322     int bank_flag = (srcaddr & 0x04) >> 2;
   323     uint32_t *banks[2];
   324     uint32_t *dwdest;
   325     int i;
   327     srcaddr = srcaddr & 0x7FFFFF;
   328     if( srcaddr + length > 0x800000 )
   329 	length = 0x800000 - srcaddr;
   331     banks[0] = ((uint32_t *)(video_base + ((srcaddr&0x007FFFF8)>>1)));
   332     banks[1] = banks[0] + 0x100000;
   333     if( bank_flag )
   334 	banks[0]++;
   336     /* Handle non-aligned start of source */
   337     if( srcaddr & 0x03 ) {
   338 	char *src = ((char *)banks[bank_flag]) + (srcaddr & 0x03);
   339 	for( i= srcaddr & 0x03; i < 4 && length > 0; i++, length-- ) {
   340 	    *dest++ = *src++;
   341 	}
   342 	bank_flag = !bank_flag;
   343     }
   345     dwdest = (uint32_t *)dest;
   346     while( length >= 4 ) {
   347 	*dwdest++ = *banks[bank_flag]++;
   348 	bank_flag = !bank_flag;
   349 	length -= 4;
   350     }
   352     /* Handle non-aligned end of source */
   353     if( length ) {
   354 	dest = (char *)dwdest;
   355 	char *src = (char *)banks[bank_flag];
   356 	while( length-- > 0 ) {
   357 	    *dest++ = *src++;
   358 	}
   359     }
   360 }
   362 void pvr2_vram64_dump_file( sh4addr_t addr, uint32_t length, gchar *filename )
   363 {
   364     uint32_t tmp[length>>2];
   365     FILE *f = fopen(filename, "wo");
   366     unsigned int i, j;
   368     if( f == NULL ) {
   369 	ERROR( "Unable to write to dump file '%s' (%s)", filename, strerror(errno) );
   370 	return;
   371     }
   372     pvr2_vram64_read( tmp, addr, length );
   373     fprintf( f, "%08X\n", addr );
   374     for( i =0; i<length>>2; i+=8 ) {
   375 	for( j=i; j<i+8; j++ ) {
   376 	    if( j < length )
   377 		fprintf( f, " %08X", tmp[j] );
   378 	    else
   379 		fprintf( f, "         " );
   380 	}
   381 	fprintf( f, "\n" );
   382     }
   383     fclose(f);
   384 }
   386 void pvr2_vram64_dump( sh4addr_t addr, uint32_t length, FILE *f ) 
   387 {
   388     char tmp[length];
   389     pvr2_vram64_read( tmp, addr, length );
   390     fwrite_dump( tmp, length, f );
   391 }
.