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