nkeynes@281 | 1 | /**
|
nkeynes@282 | 2 | * $Id: yuv.c,v 1.2 2007-01-14 11:43:00 nkeynes Exp $
|
nkeynes@281 | 3 | *
|
nkeynes@281 | 4 | * YUV420 and YUV422 decoding
|
nkeynes@281 | 5 | *
|
nkeynes@281 | 6 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@281 | 7 | *
|
nkeynes@281 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@281 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@281 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@281 | 11 | * (at your option) any later version.
|
nkeynes@281 | 12 | *
|
nkeynes@281 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@281 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@281 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@281 | 16 | * GNU General Public License for more details.
|
nkeynes@281 | 17 | */
|
nkeynes@281 | 18 | #include "dream.h"
|
nkeynes@282 | 19 | #include "asic.h"
|
nkeynes@282 | 20 | #include "pvr2/pvr2.h"
|
nkeynes@281 | 21 |
|
nkeynes@281 | 22 | #define YUV420_BLOCK_SIZE 384
|
nkeynes@282 | 23 | #define YUV422_BLOCK_SIZE 512
|
nkeynes@281 | 24 |
|
nkeynes@282 | 25 | #define FORMAT_YUV420 0
|
nkeynes@282 | 26 | #define FORMAT_YUV422 1
|
nkeynes@282 | 27 |
|
nkeynes@282 | 28 |
|
nkeynes@282 | 29 | static int yuv_block_size[2] = { YUV420_BLOCK_SIZE, YUV422_BLOCK_SIZE };
|
nkeynes@282 | 30 |
|
nkeynes@282 | 31 | struct yuv_state {
|
nkeynes@282 | 32 | uint32_t target;
|
nkeynes@282 | 33 | int width;
|
nkeynes@282 | 34 | int height;
|
nkeynes@282 | 35 | int input_format;
|
nkeynes@282 | 36 | char data[512];
|
nkeynes@282 | 37 | int data_length;
|
nkeynes@282 | 38 | int x, y;
|
nkeynes@282 | 39 | } pvr2_yuv_state;
|
nkeynes@282 | 40 |
|
nkeynes@282 | 41 | /**
|
nkeynes@282 | 42 | * Transformation table for yuv420.
|
nkeynes@282 | 43 | */
|
nkeynes@282 | 44 | uint16_t yuv420_lut[512] = { 0, 128, 64, 129, 1, 130, 65, 131, 2, 132, 66, 133, 3, 134, 67, 135, 4, 192, 68, 193, 5, 194, 69, 195, 6, 196, 70, 197, 7, 198, 71, 199,
|
nkeynes@282 | 45 | 0, 136, 64, 137, 1, 138, 65, 139, 2, 140, 66, 141, 3, 142, 67, 143, 4, 200, 68, 201, 5, 202, 69, 203, 6, 204, 70, 205, 7, 206, 71, 207,
|
nkeynes@282 | 46 | 8, 144, 72, 145, 9, 146, 73, 147, 10, 148, 74, 149, 11, 150, 75, 151, 12, 208, 76, 209, 13, 210, 77, 211, 14, 212, 78, 213, 15, 214, 79, 215,
|
nkeynes@282 | 47 | 8, 152, 72, 153, 9, 154, 73, 155, 10, 156, 74, 157, 11, 158, 75, 159, 12, 216, 76, 217, 13, 218, 77, 219, 14, 220, 78, 221, 15, 222, 79, 223,
|
nkeynes@282 | 48 | 16, 160, 80, 161, 17, 162, 81, 163, 18, 164, 82, 165, 19, 166, 83, 167, 20, 224, 84, 225, 21, 226, 85, 227, 22, 228, 86, 229, 23, 230, 87, 231,
|
nkeynes@282 | 49 | 16, 168, 80, 169, 17, 170, 81, 171, 18, 172, 82, 173, 19, 174, 83, 175, 20, 232, 84, 233, 21, 234, 85, 235, 22, 236, 86, 237, 23, 238, 87, 239,
|
nkeynes@282 | 50 | 24, 176, 88, 177, 25, 178, 89, 179, 26, 180, 90, 181, 27, 182, 91, 183, 28, 240, 92, 241, 29, 242, 93, 243, 30, 244, 94, 245, 31, 246, 95, 247,
|
nkeynes@282 | 51 | 24, 184, 88, 185, 25, 186, 89, 187, 26, 188, 90, 189, 27, 190, 91, 191, 28, 248, 92, 249, 29, 250, 93, 251, 30, 252, 94, 253, 31, 254, 95, 255,
|
nkeynes@282 | 52 | 32, 256, 96, 257, 33, 258, 97, 259, 34, 260, 98, 261, 35, 262, 99, 263, 36, 320, 100, 321, 37, 322, 101, 323, 38, 324, 102, 325, 39, 326, 103, 327,
|
nkeynes@282 | 53 | 32, 264, 96, 265, 33, 266, 97, 267, 34, 268, 98, 269, 35, 270, 99, 271, 36, 328, 100, 329, 37, 330, 101, 331, 38, 332, 102, 333, 39, 334, 103, 335,
|
nkeynes@282 | 54 | 40, 272, 104, 273, 41, 274, 105, 275, 42, 276, 106, 277, 43, 278, 107, 279, 44, 336, 108, 337, 45, 338, 109, 339, 46, 340, 110, 341, 47, 342, 111, 343,
|
nkeynes@282 | 55 | 40, 280, 104, 281, 41, 282, 105, 283, 42, 284, 106, 285, 43, 286, 107, 287, 44, 344, 108, 345, 45, 346, 109, 347, 46, 348, 110, 349, 47, 350, 111, 351,
|
nkeynes@282 | 56 | 48, 288, 112, 289, 49, 290, 113, 291, 50, 292, 114, 293, 51, 294, 115, 295, 52, 352, 116, 353, 53, 354, 117, 355, 54, 356, 118, 357, 55, 358, 119, 359,
|
nkeynes@282 | 57 | 48, 296, 112, 297, 49, 298, 113, 299, 50, 300, 114, 301, 51, 302, 115, 303, 52, 360, 116, 361, 53, 362, 117, 363, 54, 364, 118, 365, 55, 366, 119, 367,
|
nkeynes@282 | 58 | 56, 304, 120, 305, 57, 306, 121, 307, 58, 308, 122, 309, 59, 310, 123, 311, 60, 368, 124, 369, 61, 370, 125, 371, 62, 372, 126, 373, 63, 374, 127, 375,
|
nkeynes@282 | 59 | 56, 312, 120, 313, 57, 314, 121, 315, 58, 316, 122, 317, 59, 318, 123, 319, 60, 376, 124, 377, 61, 378, 125, 379, 62, 380, 126, 381, 63, 382, 127, 383 };
|
nkeynes@282 | 60 |
|
nkeynes@282 | 61 |
|
nkeynes@282 | 62 | /**
|
nkeynes@282 | 63 | * Input is 8x8 U, 8x8 V, 8x8 Y00, 8x8 Y01, 8x8 Y10, 8x8 Y11, 8 bits each,
|
nkeynes@282 | 64 | * for a total of 384 bytes.
|
nkeynes@282 | 65 | * Output is UVYV = 32 bits = 2 horizontal pixels, 8x16 = 512 bytes
|
nkeynes@282 | 66 | */
|
nkeynes@282 | 67 | void pvr2_decode_yuv420( char *dest, char *src )
|
nkeynes@281 | 68 | {
|
nkeynes@282 | 69 | int i;
|
nkeynes@282 | 70 | for( i=0; i<512; i++ ) {
|
nkeynes@282 | 71 | dest[i] = src[yuv420_lut[i]];
|
nkeynes@282 | 72 | }
|
nkeynes@282 | 73 | }
|
nkeynes@282 | 74 |
|
nkeynes@282 | 75 | void pvr2_decode_yuv422( char *dest, char *src )
|
nkeynes@282 | 76 | {
|
nkeynes@281 | 77 |
|
nkeynes@281 | 78 | }
|
nkeynes@281 | 79 |
|
nkeynes@281 | 80 | /**
|
nkeynes@282 | 81 | * Process a single macroblock of YUV data and write it out to
|
nkeynes@282 | 82 | * texture vram.
|
nkeynes@281 | 83 | */
|
nkeynes@282 | 84 | void pvr2_yuv_process_block( char *data )
|
nkeynes@281 | 85 | {
|
nkeynes@282 | 86 | char output[512];
|
nkeynes@282 | 87 |
|
nkeynes@282 | 88 | if( pvr2_yuv_state.input_format == FORMAT_YUV420 ) {
|
nkeynes@282 | 89 | pvr2_decode_yuv420( output, data );
|
nkeynes@282 | 90 | } else {
|
nkeynes@282 | 91 | pvr2_decode_yuv422( output, data );
|
nkeynes@282 | 92 | }
|
nkeynes@281 | 93 |
|
nkeynes@282 | 94 | uint32_t target = pvr2_yuv_state.target +
|
nkeynes@282 | 95 | (pvr2_yuv_state.y * pvr2_yuv_state.width * 512) +
|
nkeynes@282 | 96 | (pvr2_yuv_state.x * 32);
|
nkeynes@282 | 97 |
|
nkeynes@282 | 98 | pvr2_vram64_write_stride( target, output, 32, pvr2_yuv_state.width*32, 16 );
|
nkeynes@282 | 99 | if( ++pvr2_yuv_state.x >= pvr2_yuv_state.width ) {
|
nkeynes@282 | 100 | pvr2_yuv_state.x = 0;
|
nkeynes@282 | 101 | pvr2_yuv_state.y++;
|
nkeynes@282 | 102 | if( pvr2_yuv_state.y >= pvr2_yuv_state.height ) {
|
nkeynes@282 | 103 | asic_event( EVENT_PVR_YUV_DONE );
|
nkeynes@281 | 104 | }
|
nkeynes@282 | 105 | }
|
nkeynes@282 | 106 |
|
nkeynes@282 | 107 | MMIO_WRITE( PVR2, YUV_COUNT, MMIO_READ( PVR2, YUV_COUNT ) + 1 );
|
nkeynes@282 | 108 | }
|
nkeynes@282 | 109 |
|
nkeynes@282 | 110 | /**
|
nkeynes@282 | 111 | * Receive data from the SH4, usually via DMA. This method is mainly responsible
|
nkeynes@282 | 112 | * for buffering the data into macroblock chunks and then passing it on to the
|
nkeynes@282 | 113 | * real processing
|
nkeynes@282 | 114 | */
|
nkeynes@282 | 115 | void pvr2_yuv_write( char *data, uint32_t length )
|
nkeynes@282 | 116 | {
|
nkeynes@282 | 117 | int block_size = yuv_block_size[pvr2_yuv_state.input_format];
|
nkeynes@282 | 118 |
|
nkeynes@282 | 119 | if( pvr2_yuv_state.data_length != 0 ) { /* Append to existing data */
|
nkeynes@282 | 120 | int tmp = MIN( length, block_size - pvr2_yuv_state.data_length );
|
nkeynes@282 | 121 | memcpy( pvr2_yuv_state.data + pvr2_yuv_state.data_length,
|
nkeynes@282 | 122 | data, tmp );
|
nkeynes@282 | 123 | pvr2_yuv_state.data_length += tmp;
|
nkeynes@282 | 124 | data += tmp;
|
nkeynes@282 | 125 | length -= tmp;
|
nkeynes@282 | 126 | if( pvr2_yuv_state.data_length == block_size ) {
|
nkeynes@282 | 127 | pvr2_yuv_process_block( pvr2_yuv_state.data );
|
nkeynes@282 | 128 | }
|
nkeynes@282 | 129 | }
|
nkeynes@282 | 130 |
|
nkeynes@282 | 131 | while( length >= block_size ) {
|
nkeynes@282 | 132 | pvr2_yuv_process_block( data );
|
nkeynes@282 | 133 | data += block_size;
|
nkeynes@282 | 134 | length -= block_size;
|
nkeynes@282 | 135 | }
|
nkeynes@282 | 136 |
|
nkeynes@282 | 137 | if( length != 0 ) { /* Save the left over data */
|
nkeynes@282 | 138 | memcpy( pvr2_yuv_state.data, data, length );
|
nkeynes@282 | 139 | pvr2_yuv_state.data_length = length;
|
nkeynes@281 | 140 | }
|
nkeynes@281 | 141 | }
|
nkeynes@281 | 142 |
|
nkeynes@282 | 143 | void pvr2_yuv_init( uint32_t target, uint32_t config )
|
nkeynes@281 | 144 | {
|
nkeynes@282 | 145 | pvr2_yuv_state.target = target;
|
nkeynes@282 | 146 | pvr2_yuv_state.width = (config & 0x3f) + 1;
|
nkeynes@282 | 147 | pvr2_yuv_state.height = ((config>>8) & 0x3f) +1;
|
nkeynes@282 | 148 | pvr2_yuv_state.x = 0;
|
nkeynes@282 | 149 | pvr2_yuv_state.y = 0;
|
nkeynes@282 | 150 | pvr2_yuv_state.data_length = 0;
|
nkeynes@282 | 151 | pvr2_yuv_state.input_format = (config & 0x01000000) ? FORMAT_YUV420 : FORMAT_YUV422;
|
nkeynes@282 | 152 | if( config & 0x00010000 ) {
|
nkeynes@282 | 153 | pvr2_yuv_state.height *= pvr2_yuv_state.width;
|
nkeynes@282 | 154 | pvr2_yuv_state.width = 1;
|
nkeynes@281 | 155 | }
|
nkeynes@282 | 156 | MMIO_WRITE( PVR2, YUV_COUNT, 0 );
|
nkeynes@281 | 157 | }
|