filename | src/pvr2/pvr2mem.c |
changeset | 315:2d8ba198d62c |
prev | 310:00cd8897ad5e |
next | 325: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 | } |
.