nulldc-360/nullDC/dc/pvr/pvr_if.cpp
2022-02-11 13:27:24 +01:00

349 lines
6.9 KiB
C++

/*
PowerVR interface to plugins
Handles YUV convertion (slow and ugly -- but hey it works ...)
Most of this was hacked together when i needed support for YUV-dma for thps2 ;)
*/
#include <malloc.h>
#include "types.h"
#include "pvr_if.h"
#include "pvrLock.h"
#include "gui/base.h"
#include "dc/sh4/intc.h"
#include "dc/mem/_vmem.h"
//TODO : move code later to a plugin
//TODO : Fix registers arrays , they must be smaller now doe to the way SB registers are handled
#include "plugins/plugin_manager.h"
#include "dc/asic/asic.h"
//
//Update
/* 4/3/2006 -> it's a macro now
void UpdatePvr(u32 cycles)
{
libPvr.UpdatePvr(cycles);
}*/
//
//YUV converter code :)
//inits the YUV converter
u32 YUV_tempdata[512/4];//512 bytes
u32 YUV_index=0;
u32 YUV_dest=0;
u32 YUV_doneblocks;
u32 YUV_blockcount;
u32 YUV_x_curr;
u32 YUV_y_curr;
u32 YUV_x_size;
u32 YUV_y_size;
//writes 2 pixels to vram
INLINE void YUV_putpixel2(u32 x ,u32 y, u32 pixdata)
{
*(u32*) (&(vram.data [YUV_dest + (YUV_x_curr+x+(YUV_y_curr+y)*YUV_x_size)*2])) =pixdata;
}
void YUV_init()
{
YUV_index=0;
YUV_x_curr=0;
YUV_y_curr=0;
YUV_dest=pvr_readreg_TA(0x5F8148,4)&VRAM_MASK;//TODO : add the masking needed
YUV_doneblocks=0;
u32 TA_YUV_TEX_CTRL=pvr_readreg_TA(0x5F814C,4);
YUV_blockcount=(((TA_YUV_TEX_CTRL>>0)&0x3F)+1)*(((TA_YUV_TEX_CTRL>>8)&0x3F)+1);
if ((TA_YUV_TEX_CTRL>>16 )&1)
{ //w00t ?
YUV_x_size=16;
YUV_y_size=16;
}
else
{ //yesh!!!
YUV_x_size=(((TA_YUV_TEX_CTRL>>0)&0x3F)+1)*16;
YUV_y_size=(((TA_YUV_TEX_CTRL>>8)&0x3F)+1)*16;
}
}
INLINE u8 GetY420(int x, int y,u8* base)
{
//u32 base=0;
if (x>7)
{
x-=8;
base+=64;
}
if (y>7)
{
y-=8;
base+=128;
}
return base[x+y*8];
}
INLINE u8 GetUV420(int x, int y,u8* base)
{
int realx=x>>1;
int realy=y>>1;
return base[realx+realy*8];
}
INLINE void YUV_ConvertMacroBlock()
{
u32 TA_YUV_TEX_CTRL=pvr_readreg_TA(0x5F814C,4);
//do shit
YUV_doneblocks++;
YUV_index=0;
int block_size=(TA_YUV_TEX_CTRL & (1<<24))==0?384:512;
//YUYV
if (block_size==384)
{
u8* U=(u8*)&YUV_tempdata[0];
u8* V=(u8*)&YUV_tempdata[64/4];
u8* Y=(u8*)&YUV_tempdata[(64+64)/4];
u8 yuyv[4];
for (int y=0;y<16;y++)
{
for (int x=0;x<16;x+=2)
{
yuyv[1]=GetY420(x,y,Y);
yuyv[0]=GetUV420(x,y,U);
yuyv[3]=GetY420(x+1,y,Y);
yuyv[2]=GetUV420(x,y,V);
//pixel x,y , x+1,y
YUV_putpixel2(x,y,*(u32*)yuyv);
}
}
YUV_x_curr+=16;
if (YUV_x_curr==YUV_x_size)
{
YUV_x_curr=0;
YUV_y_curr+=16;
if (YUV_y_curr==YUV_y_size)
{
YUV_y_curr=0;
}
}
}
else
{
dlog("YUV4:2:2 not supported (YUV converter)\n");
/*u8* U0=(u8*)&YUV_tempdata[0];
u8* V0=(u8*)&YUV_tempdata[64/4];
u8* Y0=(u8*)&YUV_tempdata[(64+64)/4];
u8* U1=(u8*)&YUV_tempdata[256/4];
u8* V1=(u8*)&YUV_tempdata[(64+256)/4];
u8* Y1=(u8*)&YUV_tempdata[(64+64+256)/4];*/
}
if (YUV_blockcount==YUV_doneblocks)
{
YUV_init();
//TODO : Check if it's allrgiht to do it here?
asic_RaiseInterrupt(holly_YUV_DMA);
}
}
void YUV_data(u32* data , u32 count)
{
if (YUV_blockcount==0)
{
dlog("YUV_data : YUV decoder not inited , *WATCH*\n");
//wtf ? not inited
YUV_init();
}
//u32 TA_YUV_TEX_BASE=pvr_readreg_TA(0x5F8148,4);
u32 TA_YUV_TEX_CTRL=pvr_readreg_TA(0x5F814C,4);
//dlog("Yuv Converter : size %d\n",count);
//dlog("Yuv Format : %s , texture type %d , %d x %d [0x%X];",
// (TA_YUV_TEX_CTRL & (1<<24))==0?"YUV420":"YUV422",
// (TA_YUV_TEX_CTRL>>16 )&1,
// (((TA_YUV_TEX_CTRL>>0)&0x3F)+1)*16,
// (((TA_YUV_TEX_CTRL>>8)&0x3F)+1)*16,
// TA_YUV_TEX_CTRL);
// if ((TA_YUV_TEX_CTRL & (1<<24))==0)
// {
// dlog("%d blocks;",count*32/384);
// }
// else
// dlog("%d blocks;",count*32/512);
// dlog("Destination : 0x%X\n",TA_YUV_TEX_BASE);
//YUV420 is 384 bytes , YUV422 is 512 bytes
u32 block_size=(TA_YUV_TEX_CTRL & (1<<24))==0?384:512;
/*
for (u32 i=0;i<count*32;i+=4)
{
if (YUV_index==block_size)
YUV_ConvertMacroBlock();
YUV_tempdata[YUV_index>>2]=*data;
data++;
YUV_index+=4;
}
if (YUV_index==block_size)
YUV_ConvertMacroBlock();*/
count*=32;
while(count>0)
{
if ((YUV_index+count)>=block_size)
{ //more or exactly one block remaining
u32 dr=block_size-YUV_index; //remaining byts til block end
memcpy(&YUV_tempdata[YUV_index>>2],data,dr); //copy em
data+=dr>>2; //count em
count-=dr;
YUV_ConvertMacroBlock(); //convert block
}
else
{ //less that a hole block remaining
memcpy(&YUV_tempdata[YUV_index>>2],data,count); //append it
YUV_index+=count;
count=0;
}
}
}
//Regs
u32 pvr_readreg_TA(u32 addr,u32 sz)
{
if ((addr&0xFFFFFF)==0x5F8150) //TA_YUV_TEX_CNT
return YUV_doneblocks;
//EMUERROR3("Not implemented TA register read , addr=%d,sz=%d",addr,sz);
return libPvr.ReadReg(addr,sz);//__pvr_read__reg(addr);
}
void pvr_writereg_TA(u32 addr,u32 data,u32 sz)
{
//__pvr_write_reg(addr,data);
libPvr.WriteReg(addr,data,sz);
if ((addr&0xFFFFFF)==0x5F8148)
YUV_init();
}
//vram 32-64b
//read
u8 __fastcall pvr_read_area1_8(u32 addr)
{
dlog("8 bit vram reads are not possible\n");
return 0;
}
u16 __fastcall pvr_read_area1_16(u32 addr)
{
addr =vramlock_ConvOffset32toOffset64(addr);
return *(u16*)&vram[addr];
}
u32 __fastcall pvr_read_area1_32(u32 addr)
{
addr =vramlock_ConvOffset32toOffset64(addr);
return *(u32*)&vram[addr];
}
//write
void __fastcall pvr_write_area1_8(u32 addr,u8 data)
{
dlog("8 bit vram writes are not possible\n");
}
void __fastcall pvr_write_area1_16(u32 addr,u16 data)
{
addr=vramlock_ConvOffset32toOffset64(addr);
*(u16*)&vram[addr]=data;
}
void __fastcall pvr_write_area1_32(u32 addr,u32 data)
{
addr=vramlock_ConvOffset32toOffset64(addr);
*(u32*)&vram[addr]=data;
}
bool FASTCALL TAWrite(u32 address,u32* data,u32 count)
{
// dlog("TAWrite 0x%08X %08x %d\n",address,data,count);
/* buffer_dump(data,count*32);
printf("-----------\n"
buffer_dump(buf,count*32);*/
bool delayed=false;
u32 address_w=address&0x1FFFFFF;//correct ?
if (address_w<0x800000)//TA poly
{
libPvr.TaDMA(data,count);
}
else if(address_w<0x1000000) //Yuv Converter
{
YUV_data(data,count);
}
else //Vram Writef
{
die("shoudn't realy get here (?)"); // -> works on dc :D need to handle lmmodes
//dlog("Vram Write 0x%X , size %d\n",address,count*32);
memcpy(&vram.data[address&VRAM_MASK],data,count*32);
}
return delayed;
}
void FASTCALL TAWriteSQ(u32 address,u32* data)
{
// dlog("TAWriteSQ 0x%08X %08x\n",address,data);
u32 address_w=address&0x1FFFFFF;//correct ?
if (address_w<0x800000)//TA poly
{
libPvr.TaSQ(data);
}
else if(address_w<0x1000000) //Yuv Converter
{
YUV_data(data,1);
}
else //Vram Writef
{
die("shoudn't realy get here (?)");
//dlog("Vram Write 0x%X , size %d\n",address,count*32);
memcpy(&vram.data[address&VRAM_MASK],data,32);
}
}
//Misc interface
//Init/Term , global
void pvr_Init()
{
//vram.Init(sh4_reserved_mem,VRAM_SIZE);
}
void pvr_Term()
{
//vram.Term();
}
//Reset -> Reset - Initialise to defualt values
void pvr_Reset(bool Manual)
{
if (!Manual)
vram.Zero();
}