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