The Dreamcast's PVR video hardware features native support for several nice colorspaces, but not YUV420.
YUV420 is the native colorspace for almost all video codecs, and some image formats.
What the Dreamcast's PVR does feature, is a 'pipeline' for converting YUV(420) data to UYVY(YUV422), effectively offloading colorspace conversion from the CPU, onto the GPU.
I guess the UYVY data gets converted by the PVR Core to RGB565 before it is drawn to the screen, clamped in the range of 255, but that is beyond our concern here. All we need to know is that UYVY is a natively supported by the PVR.
YUV->UYVY conversion is done by transferring macroblocks of YUV data through the Tile Accelerator, via DMA transfers.
Before sending YUV data through DMA, some registers need to be set on the PVR:
Code: Select all
/* Allocate (UYVY) texture space for a 512x256 texture */
pvr_ptr_t * pvr_decoded_frame[0];
pvr_decoded_frame[0] = pvr_mem_malloc(512 *256 * 2);
/* Set the PVR YUV converter destination address */
PVR_SET( PVR_YUV_ADDR, pvr_decoded_frame[0] );
/* Set the YUV texture data configuration */
/* Byte 4: 0x00 - 0x00 = sending YUV420
0x01 = sending YUV422
Byte 3: 0x00 - 0x00 = render all macroblocks for a single frame into a single polygon
0x01 = render each macroblock into its own polygon
Byte 2: 0x0F - (Texture height/16)-1
Byte 1: 0x1F - (Texture width/16)-1
*/
PVR_SET( PVR_YUV_CFG_1, 0x00000F1F );
PVR_GET( PVR_YUV_CFG_1 );
Code: Select all
#define PVR_DMA_VRAM64 0 /*< Transfer to VRAM in interleaved mode */
#define PVR_DMA_VRAM32 1 /*< Transfer to VRAM in linear mode */
#define PVR_DMA_TA 2 /*< Transfer to the tile accelerator */
#define PVR_DMA_YUV 3 /*< Transfer to the yuv converter */
/* Send the data to the right place */
if (type == PVR_DMA_TA)
dest_addr = (((unsigned long)dest) & 0xFFFFFF) | 0x10000000;
else if (type == PVR_DMA_YUV)
dest_addr = (((unsigned long)dest) & 0xFFFFFF) | 0x10800000;
else
dest_addr = (((unsigned long)dest) & 0xFFFFFF) | 0x11000000;
16x16 pixels Udata ( 64 bytes )
16x16 pixels Vdata ( 64 bytes )
16x16 pixels Ydata ( 256 bytes )
And, I think this is my problem, sending the data correctly. I have the converter working, but the displayed image is not correct.
Code: Select all
#define PVR_YUV_STAT 0x0150 /* The number of YUV macroblocks converted */
void pvr_yuv_transfer( unsigned char * image, pvr_ptr_t * uyvy_dst, int texWidth, int texHeight ) {
uint16 * udst = image->u;
uint16 * vdst = image->v;
uint16 * ydst = image->y;
int mblock, mblocks;
mblock = 0, mblocks = (texWidth/16)*(texHeight/16);
while( mblock < mblocks ) {
dcache_flush_range((unsigned)udst,64);
while (!pvr_dma_ready());
pvr_dma_transfer( (void*)udst, (uint32)uyvy_dst, 64, 3, 0, NULL, NULL);
udst+=64;
dcache_flush_range((unsigned)vdst,64);
while (!pvr_dma_ready());
pvr_dma_transfer( (void*)vdst, (uint32)uyvy_dst, 64, 3, 0, NULL, NULL);
vdst+=64;
dcache_flush_range((unsigned)ydst,256);
while (!pvr_dma_ready());
pvr_dma_transfer( (void*)ydst, (uint32)uyvy_dst, 256, 3, 0, NULL, NULL);
ydst+=256;
mblock++;
}
printf("PVR: YUV Macroblocks Converted: %i\n", PVR_GET(PVR_YUV_STAT) );
}
As always, any help is appreciated!