X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=plugins%2Fgpu_unai%2Fgpu.cpp;h=1552bed90af2c2a92cce7b7bb6e88e1a06649277;hp=0ef8f51f8893b770be45e6d9af748042d516ca53;hb=HEAD;hpb=69f0df9cbaed6620a190ac289958c5bf7c079d92 diff --git a/plugins/gpu_unai/gpu.cpp b/plugins/gpu_unai/gpu.cpp index 0ef8f51f..c3f70954 100644 --- a/plugins/gpu_unai/gpu.cpp +++ b/plugins/gpu_unai/gpu.cpp @@ -1,6 +1,7 @@ /*************************************************************************** * Copyright (C) 2010 PCSX4ALL Team * * Copyright (C) 2010 Unai * +* Copyright (C) 2016 Senquack (dansilsby gmail com) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * @@ -18,103 +19,42 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. * ***************************************************************************/ -#include "port.h" -#include "gpu.h" -#include "profiler.h" -#include "debug.h" +#include +#include "plugins.h" +#include "psxcommon.h" +//#include "port.h" +#include "gpu_unai.h" -int skipCount = 2; /* frame skip (0,1,2,3...) */ -int skCount=0; /* internal frame skip */ -int linesInterlace = 0; /* internal lines interlace */ -int linesInterlace_user = 0; /* Lines interlace */ +#define VIDEO_WIDTH 320 -bool isSkip=false; /* skip frame (info coming from GPU) */ -bool skipFrame=false; /* skip frame (according to frame skip) */ -bool alt_fps = false; /* Alternative FPS algorithm */ -bool show_fps = false; /* Show FPS statistics */ - -bool isPAL=false; /* PAL video timing */ -bool progressInterlace_flag = false; /* Progressive interlace flag */ -bool progressInterlace = false; /* Progressive interlace option*/ -bool frameLimit = false; /* frames to wait */ -bool light = true; /* lighting */ -bool blend = true; /* blending */ - -bool fb_dirty = false; - -bool enableAbbeyHack = false; /* Abe's Odyssey hack */ -u8 BLEND_MODE; -u8 TEXT_MODE; -u8 Masking; - -u16 PixelMSB; -u16 PixelData; - -/////////////////////////////////////////////////////////////////////////////// -// GPU Global data -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// Dma Transfers info -s32 px,py; -s32 x_end,y_end; -u16* pvram; - -u32 FrameToRead; -u32 FrameToWrite; - -u32 GP0; -s32 PacketCount; -s32 PacketIndex; - -/////////////////////////////////////////////////////////////////////////////// -// Display status -u32 DisplayArea [6]; +#ifdef TIME_IN_MSEC +#define TPS 1000 +#else +#define TPS 1000000 +#endif -/////////////////////////////////////////////////////////////////////////////// -// Rasterizer status -u32 TextureWindow [4]; -u32 DrawingArea [4]; -u32 DrawingOffset [2]; +#define IS_PAL (gpu_unai.GPU_GP1&(0x08<<17)) -/////////////////////////////////////////////////////////////////////////////// -// Rasterizer status - -u16* TBA; -u16* CBA; +//senquack - Original 512KB of guard space seems not to be enough, as Xenogears +// accesses outside this range and crashes in town intro fight sequence. +// Increased to 2MB total (double PSX VRAM) and Xenogears no longer +// crashes, but some textures are still messed up. Also note that alignment min +// is 16 bytes, needed for pixel-skipping rendering/blitting in high horiz res. +// Extra 4KB is for guard room at beginning. +// TODO: Determine cause of out-of-bounds write/reads. <-- Note: this is largely +// solved by adoption of PCSX Rearmed's 'gpulib' in gpulib_if.cpp, which +// replaces this file (gpu.cpp) +//u16 GPU_FrameBuffer[(FRAME_BUFFER_SIZE+512*1024)/2] __attribute__((aligned(32))); +static u16 GPU_FrameBuffer[(FRAME_BUFFER_SIZE*2 + 4096)/2] __attribute__((aligned(32))); /////////////////////////////////////////////////////////////////////////////// -// Inner Loops -s32 u4, du4; -s32 v4, dv4; -s32 r4, dr4; -s32 g4, dg4; -s32 b4, db4; -u32 lInc; -u32 tInc, tMsk; - -GPUPacket PacketBuffer; -// FRAME_BUFFER_SIZE is defined in bytes; 512K is guard memory for out of range reads -u16 GPU_FrameBuffer[(FRAME_BUFFER_SIZE+512*1024)/2] __attribute__((aligned(16))); -u32 GPU_GP1; +// GPU fixed point math +#include "gpu_fixedpoint.h" /////////////////////////////////////////////////////////////////////////////// -// Inner loop driver instanciation file +// Inner loop driver instantiation file #include "gpu_inner.h" -/////////////////////////////////////////////////////////////////////////////// -// GPU Raster Macros -#define GPU_RGB16(rgb) ((((rgb)&0xF80000)>>9)|(((rgb)&0xF800)>>6)|(((rgb)&0xF8)>>3)) - -#define GPU_EXPANDSIGN_POLY(x) (((s32)(x)<<20)>>20) -//#define GPU_EXPANDSIGN_POLY(x) (((s32)(x)<<21)>>21) -#define GPU_EXPANDSIGN_SPRT(x) (((s32)(x)<<21)>>21) - -//#define GPU_TESTRANGE(x) { if((u32)(x+1024) > 2047) return; } -#define GPU_TESTRANGE(x) { if ((x<-1023) || (x>1023)) return; } - -#define GPU_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);} - /////////////////////////////////////////////////////////////////////////////// // GPU internal image drawing functions #include "gpu_raster_image.h" @@ -136,72 +76,88 @@ u32 GPU_GP1; #include "gpu_command.h" /////////////////////////////////////////////////////////////////////////////// -INLINE void gpuReset(void) +static void gpuReset(void) { - GPU_GP1 = 0x14802000; - TextureWindow[0] = 0; - TextureWindow[1] = 0; - TextureWindow[2] = 255; - TextureWindow[3] = 255; - DrawingArea[2] = 256; - DrawingArea[3] = 240; - DisplayArea[2] = 256; - DisplayArea[3] = 240; - DisplayArea[5] = 240; + memset((void*)&gpu_unai, 0, sizeof(gpu_unai)); + gpu_unai.vram = (u16*)GPU_FrameBuffer + (4096/2); //4kb guard room in front + gpu_unai.GPU_GP1 = 0x14802000; + gpu_unai.DrawingArea[2] = 256; + gpu_unai.DrawingArea[3] = 240; + gpu_unai.DisplayArea[2] = 256; + gpu_unai.DisplayArea[3] = 240; + gpu_unai.DisplayArea[5] = 240; + gpu_unai.TextureWindow[0] = 0; + gpu_unai.TextureWindow[1] = 0; + gpu_unai.TextureWindow[2] = 255; + gpu_unai.TextureWindow[3] = 255; + //senquack - new vars must be updated whenever texture window is changed: + // (used for polygon-drawing in gpu_inner.h, gpu_raster_polygon.h) + const u32 fb = FIXED_BITS; // # of fractional fixed-pt bits of u4/v4 + gpu_unai.u_msk = (((u32)gpu_unai.TextureWindow[2]) << fb) | ((1 << fb) - 1); + gpu_unai.v_msk = (((u32)gpu_unai.TextureWindow[3]) << fb) | ((1 << fb) - 1); + + // Configuration options + gpu_unai.config = gpu_unai_config_ext; + gpu_unai.ilace_mask = gpu_unai.config.ilace_force; + gpu_unai.frameskip.skipCount = gpu_unai.config.frameskip_count; + + SetupLightLUT(); + SetupDitheringConstants(); } /////////////////////////////////////////////////////////////////////////////// -bool GPU_init(void) +long GPU_init(void) { gpuReset(); - + +#ifdef GPU_UNAI_USE_INT_DIV_MULTINV // s_invTable - for(int i=1;i<=(1<>1); - #else - v *= double(0x80000000); - #endif - s_invTable[i-1]=s32(v); + s_invTable[i-1]=0x7fffffff/i; } +#endif + + gpu_unai.fb_dirty = true; + gpu_unai.dma.last_dma = NULL; return (0); } /////////////////////////////////////////////////////////////////////////////// -void GPU_shutdown(void) +long GPU_shutdown(void) { + return 0; } /////////////////////////////////////////////////////////////////////////////// -long GPU_freeze(unsigned int bWrite, GPUFreeze_t* p2) +long GPU_freeze(u32 bWrite, GPUFreeze_t* p2) { if (!p2) return (0); - if (p2->Version != 1) return (0); + if (p2->ulFreezeVersion != 1) return (0); if (bWrite) { - p2->GPU_gp1 = GPU_GP1; - memset(p2->Control, 0, sizeof(p2->Control)); + p2->ulStatus = gpu_unai.GPU_GP1; + memset(p2->ulControl, 0, sizeof(p2->ulControl)); // save resolution and registers for P.E.Op.S. compatibility - p2->Control[3] = (3 << 24) | ((GPU_GP1 >> 23) & 1); - p2->Control[4] = (4 << 24) | ((GPU_GP1 >> 29) & 3); - p2->Control[5] = (5 << 24) | (DisplayArea[0] | (DisplayArea[1] << 10)); - p2->Control[6] = (6 << 24) | (2560 << 12); - p2->Control[7] = (7 << 24) | (DisplayArea[4] | (DisplayArea[5] << 10)); - p2->Control[8] = (8 << 24) | ((GPU_GP1 >> 17) & 0x3f) | ((GPU_GP1 >> 10) & 0x40); - memcpy(p2->FrameBuffer, (u16*)GPU_FrameBuffer, FRAME_BUFFER_SIZE); + p2->ulControl[3] = (3 << 24) | ((gpu_unai.GPU_GP1 >> 23) & 1); + p2->ulControl[4] = (4 << 24) | ((gpu_unai.GPU_GP1 >> 29) & 3); + p2->ulControl[5] = (5 << 24) | (gpu_unai.DisplayArea[0] | (gpu_unai.DisplayArea[1] << 10)); + p2->ulControl[6] = (6 << 24) | (2560 << 12); + p2->ulControl[7] = (7 << 24) | (gpu_unai.DisplayArea[4] | (gpu_unai.DisplayArea[5] << 10)); + p2->ulControl[8] = (8 << 24) | ((gpu_unai.GPU_GP1 >> 17) & 0x3f) | ((gpu_unai.GPU_GP1 >> 10) & 0x40); + memcpy((void*)p2->psxVRam, (void*)gpu_unai.vram, FRAME_BUFFER_SIZE); return (1); } else { - GPU_GP1 = p2->GPU_gp1; - memcpy((u16*)GPU_FrameBuffer, p2->FrameBuffer, FRAME_BUFFER_SIZE); - GPU_writeStatus((5 << 24) | p2->Control[5]); - GPU_writeStatus((7 << 24) | p2->Control[7]); - GPU_writeStatus((8 << 24) | p2->Control[8]); - gpuSetTexture(GPU_GP1); + extern void GPU_writeStatus(u32 data); + gpu_unai.GPU_GP1 = p2->ulStatus; + memcpy((void*)gpu_unai.vram, (void*)p2->psxVRam, FRAME_BUFFER_SIZE); + GPU_writeStatus((5 << 24) | p2->ulControl[5]); + GPU_writeStatus((7 << 24) | p2->ulControl[7]); + GPU_writeStatus((8 << 24) | p2->ulControl[8]); + gpuSetTexture(gpu_unai.GPU_GP1); return (1); } return (0); @@ -234,71 +190,69 @@ u8 PacketSize[256] = /////////////////////////////////////////////////////////////////////////////// INLINE void gpuSendPacket() { -#ifdef DEBUG_ANALYSIS - dbg_anacnt_GPU_sendPacket++; -#endif - gpuSendPacketFunction(PacketBuffer.U4[0]>>24); + gpuSendPacketFunction(gpu_unai.PacketBuffer.U4[0]>>24); } /////////////////////////////////////////////////////////////////////////////// INLINE void gpuCheckPacket(u32 uData) { - if (PacketCount) + if (gpu_unai.PacketCount) { - PacketBuffer.U4[PacketIndex++] = uData; - --PacketCount; + gpu_unai.PacketBuffer.U4[gpu_unai.PacketIndex++] = uData; + --gpu_unai.PacketCount; } else { - PacketBuffer.U4[0] = uData; - PacketCount = PacketSize[uData >> 24]; - PacketIndex = 1; + gpu_unai.PacketBuffer.U4[0] = uData; + gpu_unai.PacketCount = PacketSize[uData >> 24]; + gpu_unai.PacketIndex = 1; } - if (!PacketCount) gpuSendPacket(); + if (!gpu_unai.PacketCount) gpuSendPacket(); } /////////////////////////////////////////////////////////////////////////////// -void GPU_writeDataMem(u32* dmaAddress, s32 dmaCount) +void GPU_writeDataMem(u32* dmaAddress, int dmaCount) { -#ifdef DEBUG_ANALYSIS - dbg_anacnt_GPU_writeDataMem++; -#endif - pcsx4all_prof_pause(PCSX4ALL_PROF_CPU); - pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_writeDataMem(%d)\n",dmaCount); + #endif u32 data; - const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1); - GPU_GP1 &= ~0x14000000; + const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1; + gpu_unai.GPU_GP1 &= ~0x14000000; while (dmaCount) { - if (FrameToWrite) + if (gpu_unai.dma.FrameToWrite) { - while (dmaCount--) + while (dmaCount) { + dmaCount--; data = *dmaAddress++; - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; - pvram[px] = data; - if (++px>=x_end) + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; + gpu_unai.dma.pvram[gpu_unai.dma.px] = data; + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram += 1024; - if (++py>=y_end) + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; + if (++gpu_unai.dma.py >= gpu_unai.dma.y_end) { - FrameToWrite = 0; - GPU_GP1 &= ~0x08000000; + gpu_unai.dma.FrameToWrite = false; + gpu_unai.GPU_GP1 &= ~0x08000000; + gpu_unai.fb_dirty = true; break; } } - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; - pvram[px] = data>>16; - if (++px>=x_end) + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; + gpu_unai.dma.pvram[gpu_unai.dma.px] = data>>16; + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram += 1024; - if (++py>=y_end) + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; + if (++gpu_unai.dma.py >= gpu_unai.dma.y_end) { - FrameToWrite = 0; - GPU_GP1 &= ~0x08000000; + gpu_unai.dma.FrameToWrite = false; + gpu_unai.GPU_GP1 &= ~0x08000000; + gpu_unai.fb_dirty = true; break; } } @@ -312,91 +266,100 @@ void GPU_writeDataMem(u32* dmaAddress, s32 dmaCount) } } - GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000; - fb_dirty = true; - pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); - pcsx4all_prof_resume(PCSX4ALL_PROF_CPU); + gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 | 0x14000000) & ~0x60000000; } -u32 *lUsedAddr[3]; -INLINE int CheckForEndlessLoop(u32 *laddr) +long GPU_dmaChain(u32 *rambase, u32 start_addr) { - if(laddr==lUsedAddr[1]) return 1; - if(laddr==lUsedAddr[2]) return 1; + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_dmaChain(0x%x)\n",start_addr); + #endif - if(laddr> 24; + addr = list[0] & 0xffffff; + + dma_words += 1 + len; + + // add loop detection marker + list[0] |= 0x800000; + + if (len) GPU_writeDataMem(list + 1, len); + + if (addr & 0x800000) + { + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_dmaChain(LOOP)\n"); + #endif + break; + } + } + + // remove loop detection markers + addr = start_addr & 0x1fffff; + while (count-- > 0) { - address = (baseAddr + (dmaVAddr >> 2)); - if(DMACommandCounter++ > 2000000) break; - if(CheckForEndlessLoop(address)) break; - data = *address++; - count = (data >> 24); - offset = data & 0x001FFFFF; - if (dmaVAddr != offset) dmaVAddr = offset; - else dmaVAddr = 0x1FFFFF; - - if(count>0) GPU_writeDataMem(address,count); + list = rambase + addr / 4; + addr = list[0] & 0x1fffff; + list[0] &= ~0x800000; } - GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000; - pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); + + if (gpu_unai.dma.last_dma) *gpu_unai.dma.last_dma &= ~0x800000; + gpu_unai.dma.last_dma = rambase + (start_addr & 0x1fffff) / 4; + + gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 | 0x14000000) & ~0x60000000; + + return dma_words; } /////////////////////////////////////////////////////////////////////////////// -void GPU_writeData(u32 data) +void GPU_writeData(u32 data) { - const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1); -#ifdef DEBUG_ANALYSIS - dbg_anacnt_GPU_writeData++; -#endif - pcsx4all_prof_pause(PCSX4ALL_PROF_CPU); - pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); - GPU_GP1 &= ~0x14000000; + const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1; + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_writeData()\n"); + #endif + gpu_unai.GPU_GP1 &= ~0x14000000; - if (FrameToWrite) + if (gpu_unai.dma.FrameToWrite) { - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; - pvram[px]=(u16)data; - if (++px>=x_end) + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; + gpu_unai.dma.pvram[gpu_unai.dma.px]=(u16)data; + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram += 1024; - if (++py>=y_end) + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; + if (++gpu_unai.dma.py >= gpu_unai.dma.y_end) { - FrameToWrite = 0; - GPU_GP1 &= ~0x08000000; + gpu_unai.dma.FrameToWrite = false; + gpu_unai.GPU_GP1 &= ~0x08000000; + gpu_unai.fb_dirty = true; } } - if (FrameToWrite) + if (gpu_unai.dma.FrameToWrite) { - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; - pvram[px]=data>>16; - if (++px>=x_end) + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; + gpu_unai.dma.pvram[gpu_unai.dma.px]=data>>16; + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram += 1024; - if (++py>=y_end) + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; + if (++gpu_unai.dma.py >= gpu_unai.dma.y_end) { - FrameToWrite = 0; - GPU_GP1 &= ~0x08000000; + gpu_unai.dma.FrameToWrite = false; + gpu_unai.GPU_GP1 &= ~0x08000000; + gpu_unai.fb_dirty = true; } } } @@ -405,572 +368,463 @@ void GPU_writeData(u32 data) { gpuCheckPacket(data); } - GPU_GP1 |= 0x14000000; - fb_dirty = true; - pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); - pcsx4all_prof_resume(PCSX4ALL_PROF_CPU); - + gpu_unai.GPU_GP1 |= 0x14000000; } /////////////////////////////////////////////////////////////////////////////// -void GPU_readDataMem(u32* dmaAddress, s32 dmaCount) +void GPU_readDataMem(u32* dmaAddress, int dmaCount) { - const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1); -#ifdef DEBUG_ANALYSIS - dbg_anacnt_GPU_readDataMem++; -#endif - if(!FrameToRead) return; + const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1; + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_readDataMem(%d)\n",dmaCount); + #endif + if(!gpu_unai.dma.FrameToRead) return; - pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); - GPU_GP1 &= ~0x14000000; + gpu_unai.GPU_GP1 &= ~0x14000000; do { - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; // lower 16 bit - u32 data = (unsigned long)pvram[px]; + //senquack - 64-bit fix (from notaz) + //u32 data = (unsigned long)gpu_unai.dma.pvram[gpu_unai.dma.px]; + u32 data = (u32)gpu_unai.dma.pvram[gpu_unai.dma.px]; - if (++px>=x_end) + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram += 1024; + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; } - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; // higher 16 bit (always, even if it's an odd width) - data |= (unsigned long)(pvram[px])<<16; + //senquack - 64-bit fix (from notaz) + //data |= (unsigned long)(gpu_unai.dma.pvram[gpu_unai.dma.px])<<16; + data |= (u32)(gpu_unai.dma.pvram[gpu_unai.dma.px])<<16; *dmaAddress++ = data; - if (++px>=x_end) + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram += 1024; - if (++py>=y_end) + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; + if (++gpu_unai.dma.py >= gpu_unai.dma.y_end) { - FrameToRead = 0; - GPU_GP1 &= ~0x08000000; + gpu_unai.dma.FrameToRead = false; + gpu_unai.GPU_GP1 &= ~0x08000000; break; } } } while (--dmaCount); - GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000; - pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); + gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 | 0x14000000) & ~0x60000000; } /////////////////////////////////////////////////////////////////////////////// -u32 GPU_readData(void) +u32 GPU_readData(void) { - const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1); -#ifdef DEBUG_ANALYSIS - dbg_anacnt_GPU_readData++; -#endif - pcsx4all_prof_pause(PCSX4ALL_PROF_CPU); - pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_READ); - GPU_GP1 &= ~0x14000000; - if (FrameToRead) + const u16 *VIDEO_END = (u16*)gpu_unai.vram+(FRAME_BUFFER_SIZE/2)-1; + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_readData()\n"); + #endif + gpu_unai.GPU_GP1 &= ~0x14000000; + if (gpu_unai.dma.FrameToRead) { - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; - GP0 = pvram[px]; - if (++px>=x_end) + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; + gpu_unai.GPU_GP0 = gpu_unai.dma.pvram[gpu_unai.dma.px]; + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram += 1024; - if (++py>=y_end) + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; + if (++gpu_unai.dma.py >= gpu_unai.dma.y_end) { - FrameToRead = 0; - GPU_GP1 &= ~0x08000000; + gpu_unai.dma.FrameToRead = false; + gpu_unai.GPU_GP1 &= ~0x08000000; } } - if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024; - GP0 |= pvram[px]<<16; - if (++px>=x_end) + if ((&gpu_unai.dma.pvram[gpu_unai.dma.px])>(VIDEO_END)) gpu_unai.dma.pvram-=512*1024; + gpu_unai.GPU_GP0 |= gpu_unai.dma.pvram[gpu_unai.dma.px]<<16; + if (++gpu_unai.dma.px >= gpu_unai.dma.x_end) { - px = 0; - pvram +=1024; - if (++py>=y_end) + gpu_unai.dma.px = 0; + gpu_unai.dma.pvram += 1024; + if (++gpu_unai.dma.py >= gpu_unai.dma.y_end) { - FrameToRead = 0; - GPU_GP1 &= ~0x08000000; + gpu_unai.dma.FrameToRead = false; + gpu_unai.GPU_GP1 &= ~0x08000000; } } } - GPU_GP1 |= 0x14000000; + gpu_unai.GPU_GP1 |= 0x14000000; - pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_READ); - pcsx4all_prof_resume(PCSX4ALL_PROF_CPU); - return (GP0); + return (gpu_unai.GPU_GP0); } /////////////////////////////////////////////////////////////////////////////// -u32 GPU_readStatus(void) +u32 GPU_readStatus(void) { -#ifdef DEBUG_ANALYSIS - dbg_anacnt_GPU_readStatus++; -#endif - return GPU_GP1; + return gpu_unai.GPU_GP1; +} + +INLINE void GPU_NoSkip(void) +{ + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_NoSkip()\n"); + #endif + gpu_unai.frameskip.wasSkip = gpu_unai.frameskip.isSkip; + if (gpu_unai.frameskip.isSkip) + { + gpu_unai.frameskip.isSkip = false; + gpu_unai.frameskip.skipGPU = false; + } + else + { + gpu_unai.frameskip.isSkip = gpu_unai.frameskip.skipFrame; + gpu_unai.frameskip.skipGPU = gpu_unai.frameskip.skipFrame; + } } /////////////////////////////////////////////////////////////////////////////// void GPU_writeStatus(u32 data) { -#ifdef DEBUG_ANALYSIS - dbg_anacnt_GPU_writeStatus++; -#endif - pcsx4all_prof_pause(PCSX4ALL_PROF_CPU); - pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_writeStatus(%d,%d)\n",data>>24,data & 0xff); + #endif switch (data >> 24) { case 0x00: gpuReset(); break; case 0x01: - GPU_GP1 &= ~0x08000000; - PacketCount = FrameToRead = FrameToWrite = 0; + gpu_unai.GPU_GP1 &= ~0x08000000; + gpu_unai.PacketCount = 0; + gpu_unai.dma.FrameToRead = gpu_unai.dma.FrameToWrite = false; break; case 0x02: - GPU_GP1 &= ~0x08000000; - PacketCount = FrameToRead = FrameToWrite = 0; + gpu_unai.GPU_GP1 &= ~0x08000000; + gpu_unai.PacketCount = 0; + gpu_unai.dma.FrameToRead = gpu_unai.dma.FrameToWrite = false; break; case 0x03: - GPU_GP1 = (GPU_GP1 & ~0x00800000) | ((data & 1) << 23); + gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x00800000) | ((data & 1) << 23); break; case 0x04: - if (data == 0x04000000) - PacketCount = 0; - GPU_GP1 = (GPU_GP1 & ~0x60000000) | ((data & 3) << 29); + if (data == 0x04000000) gpu_unai.PacketCount = 0; + gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x60000000) | ((data & 3) << 29); break; case 0x05: - DisplayArea[0] = (data & 0x000003FF); //(short)(data & 0x3ff); - DisplayArea[1] = ((data & 0x0007FC00)>>10); //(data & 0x000FFC00) >> 10; //(short)((data>>10)&0x1ff); - fb_dirty = true; + // Start of Display Area in VRAM + gpu_unai.DisplayArea[0] = data & 0x3ff; // X (0..1023) + gpu_unai.DisplayArea[1] = (data >> 10) & 0x1ff; // Y (0..511) + GPU_NoSkip(); + break; + case 0x06: + // GP1(06h) - Horizontal Display range (on Screen) + // 0-11 X1 (260h+0) ;12bit ;\counted in 53.222400MHz units, + // 12-23 X2 (260h+320*8) ;12bit ;/relative to HSYNC + + // senquack - gpu_unai completely ignores GP1(0x06) command and + // lacks even a place in DisplayArea[] array to store the values. + // It seems to have been concerned only with vertical display range + // and centering top/bottom. I will not add support here, and + // focus instead on the gpulib version (gpulib_if.cpp) which uses + // gpulib for its PS1->host framebuffer blitting. break; case 0x07: - DisplayArea[4] = data & 0x000003FF; //(short)(data & 0x3ff); - DisplayArea[5] = (data & 0x000FFC00) >> 10; //(short)((data>>10) & 0x3ff); - fb_dirty = true; + // GP1(07h) - Vertical Display range (on Screen) + // 0-9 Y1 (NTSC=88h-(224/2), (PAL=A3h-(264/2)) ;\scanline numbers on screen, + // 10-19 Y2 (NTSC=88h+(224/2), (PAL=A3h+(264/2)) ;/relative to VSYNC + // 20-23 Not used (zero) + { + u32 v1=data & 0x000003FF; //(short)(data & 0x3ff); + u32 v2=(data & 0x000FFC00) >> 10; //(short)((data>>10) & 0x3ff); + if ((gpu_unai.DisplayArea[4]!=v1)||(gpu_unai.DisplayArea[5]!=v2)) + { + gpu_unai.DisplayArea[4] = v1; + gpu_unai.DisplayArea[5] = v2; + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"video_clear(CHANGE_Y)\n"); + #endif + video_clear(); + } + } break; case 0x08: { - GPU_GP1 = (GPU_GP1 & ~0x007F0000) | ((data & 0x3F) << 17) | ((data & 0x40) << 10); - static u32 HorizontalResolution[8] = { 256, 368, 320, 384, 512, 512, 640, 640 }; - DisplayArea[2] = HorizontalResolution[(GPU_GP1 >> 16) & 7]; - static u32 VerticalResolution[4] = { 240, 480, 256, 480 }; - DisplayArea[3] = VerticalResolution[(GPU_GP1 >> 19) & 3]; - isPAL = (data & 0x08) ? true : false; // if 1 - PAL mode, else NTSC + static const u32 HorizontalResolution[8] = { 256, 368, 320, 384, 512, 512, 640, 640 }; + static const u32 VerticalResolution[4] = { 240, 480, 256, 480 }; + gpu_unai.GPU_GP1 = (gpu_unai.GPU_GP1 & ~0x007F0000) | ((data & 0x3F) << 17) | ((data & 0x40) << 10); + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_writeStatus(RES=%dx%d,BITS=%d,PAL=%d)\n",HorizontalResolution[(gpu_unai.GPU_GP1 >> 16) & 7], + VerticalResolution[(gpu_unai.GPU_GP1 >> 19) & 3],(gpu_unai.GPU_GP1&0x00200000?24:15),(IS_PAL?1:0)); + #endif + // Video mode change + u32 new_width = HorizontalResolution[(gpu_unai.GPU_GP1 >> 16) & 7]; + u32 new_height = VerticalResolution[(gpu_unai.GPU_GP1 >> 19) & 3]; + + if (gpu_unai.DisplayArea[2] != new_width || gpu_unai.DisplayArea[3] != new_height) + { + // Update width + gpu_unai.DisplayArea[2] = new_width; + + if (PixelSkipEnabled()) { + // Set blit_mask for high horizontal resolutions. This allows skipping + // rendering pixels that would never get displayed on low-resolution + // platforms that use simple pixel-dropping scaler. + switch (gpu_unai.DisplayArea[2]) + { + case 512: gpu_unai.blit_mask = 0xa4; break; // GPU_BlitWWSWWSWS + case 640: gpu_unai.blit_mask = 0xaa; break; // GPU_BlitWS + default: gpu_unai.blit_mask = 0; break; + } + } else { + gpu_unai.blit_mask = 0; + } + + // Update height + gpu_unai.DisplayArea[3] = new_height; + + if (LineSkipEnabled()) { + // Set rendering line-skip (only render every other line in high-res + // 480 vertical mode, or, optionally, force it for all video modes) + + if (gpu_unai.DisplayArea[3] == 480) { + if (gpu_unai.config.ilace_force) { + gpu_unai.ilace_mask = 3; // Only need 1/4 of lines + } else { + gpu_unai.ilace_mask = 1; // Only need 1/2 of lines + } + } else { + // Vert resolution changed from 480 to lower one + gpu_unai.ilace_mask = gpu_unai.config.ilace_force; + } + } else { + gpu_unai.ilace_mask = 0; + } + + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"video_clear(CHANGE_RES)\n"); + #endif + video_clear(); + } + } - fb_dirty = true; break; case 0x10: - switch (data & 0xffff) { - case 0: - case 1: - case 3: - GP0 = (DrawingArea[1] << 10) | DrawingArea[0]; - break; - case 4: - GP0 = ((DrawingArea[3]-1) << 10) | (DrawingArea[2]-1); - break; - case 6: - case 5: - GP0 = (DrawingOffset[1] << 11) | DrawingOffset[0]; - break; - case 7: - GP0 = 2; - break; - default: - GP0 = 0; + switch (data & 0xff) { + case 2: gpu_unai.GPU_GP0 = gpu_unai.tex_window; break; + case 3: gpu_unai.GPU_GP0 = (gpu_unai.DrawingArea[1] << 10) | gpu_unai.DrawingArea[0]; break; + case 4: gpu_unai.GPU_GP0 = ((gpu_unai.DrawingArea[3]-1) << 10) | (gpu_unai.DrawingArea[2]-1); break; + case 5: case 6: gpu_unai.GPU_GP0 = (((u32)gpu_unai.DrawingOffset[1] & 0x7ff) << 11) | ((u32)gpu_unai.DrawingOffset[0] & 0x7ff); break; + case 7: gpu_unai.GPU_GP0 = 2; break; + case 8: case 15: gpu_unai.GPU_GP0 = 0xBFC03720; break; } break; } - pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE); - pcsx4all_prof_resume(PCSX4ALL_PROF_CPU); } -#ifndef REARMED - // Blitting functions #include "gpu_blit.h" -INLINE void gpuVideoOutput(void) +static void gpuVideoOutput(void) { - static s16 old_res_horz, old_res_vert, old_rgb24; - s16 h0, x0, y0, w0, h1; + int h0, x0, y0, w0, h1; - x0 = DisplayArea[0]; - y0 = DisplayArea[1]; + x0 = gpu_unai.DisplayArea[0]; + y0 = gpu_unai.DisplayArea[1]; - w0 = DisplayArea[2]; - h0 = DisplayArea[3]; // video mode + w0 = gpu_unai.DisplayArea[2]; + h0 = gpu_unai.DisplayArea[3]; // video mode - h1 = DisplayArea[5] - DisplayArea[4]; // display needed + h1 = gpu_unai.DisplayArea[5] - gpu_unai.DisplayArea[4]; // display needed if (h0 == 480) h1 = Min2(h1*2,480); - u16* dest_screen16 = SCREEN; - u16* src_screen16 = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0,y0)]; - u32 isRGB24 = (GPU_GP1 & 0x00200000 ? 32 : 0); + bool isRGB24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false); + u16* dst16 = SCREEN; + u16* src16 = (u16*)gpu_unai.vram; - /* Clear the screen if resolution changed to prevent interlacing and clipping to clash */ - if( (w0 != old_res_horz || h1 != old_res_vert || (s16)isRGB24 != old_rgb24) ) - { - // Update old resolution - old_res_horz = w0; - old_res_vert = h1; - old_rgb24 = (s16)isRGB24; - // Finally, clear the screen for this special case - video_clear(); - } + // PS1 fb read wraps around (fixes black screen in 'Tobal no. 1') + unsigned int src16_offs_msk = 1024*512-1; + unsigned int src16_offs = (x0 + y0*1024) & src16_offs_msk; // Height centering int sizeShift = 1; - if(h0==256) h0 = 240; else if(h0==480) sizeShift = 2; - if(h1>h0) { src_screen16 += ((h1-h0)>>sizeShift)*1024; h1 = h0; } - else if(h1>sizeShift)*VIDEO_WIDTH; + if (h0 == 256) { + h0 = 240; + } else if (h0 == 480) { + sizeShift = 2; + } + if (h1 > h0) { + src16_offs = (src16_offs + (((h1-h0) / 2) * 1024)) & src16_offs_msk; + h1 = h0; + } else if (h1> sizeShift) * VIDEO_WIDTH; + } + /* Main blitter */ int incY = (h0==480) ? 2 : 1; h0=(h0==480 ? 2048 : 1024); - if (!progressInterlace) { - const int li=linesInterlace; + const int li=gpu_unai.ilace_mask; + bool pi = ProgressiveInterlaceEnabled(); + bool pif = gpu_unai.prog_ilace_flag; switch ( w0 ) { case 256: for(int y1=y0+h1; y0>3 (8 times per second) +#define GPU_FRAMESKIP_UPDATE 3 - // Show FPS statistics - if (show_fps) - { - static u32 real_fps=0; - static u32 prev=get_ticks(); - static char msg[24]="FPS=000/00 SPD=000%"; - u32 now=get_ticks(); - real_fps++; - if ((now-prev)>=1000000) - { - u32 expected_fps=(isPAL?50:60); - sprintf(msg,"FPS=%3d/%2d SPD=%3d%%",((real_fps*(12-skipCount))/12),((expected_fps*(12-skipCount))/12),((real_fps*100)/expected_fps)); - prev=now; - real_fps=0; - } - port_printf(5,5,msg); - } - - // Update frame-skip - if (!alt_fps) - { - // Video frame-skip - skipFrame=skipTable[skipCount][skCount]; - skCount--; if (skCount<0) skCount=11; - isSkip=skipFrame; - } - else - { - // Game frame-skip - if (!isSkip) - { - skipFrame=skipTable[skipCount][skCount]; - skCount--; if (skCount<0) skCount=11; - isSkip=true; - } - } - - pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_COUNTERS); -} - -#else - -#include "../../frontend/plugin_lib.h" -#include "../../frontend/arm_utils.h" - -extern "C" { - -static const struct rearmed_cbs *cbs; -static void *screen_buf; - -static void blit(void) +static void GPU_frameskip (bool show) { - static s16 old_res_horz, old_res_vert, old_rgb24; - s16 isRGB24 = (GPU_GP1 & 0x00200000) ? 1 : 0; - s16 h0, x0, y0, w0, h1; - u16 *srcs; - u8 *dest; - - x0 = DisplayArea[0] & ~1; // alignment needed by blitter - y0 = DisplayArea[1]; - srcs = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0,y0)]; - - w0 = DisplayArea[2]; - h0 = DisplayArea[3]; // video mode - - h1 = DisplayArea[5] - DisplayArea[4]; // display needed - if (h0 == 480) h1 = Min2(h1*2,480); + u32 now=get_ticks(); // current frame - if (h1 <= 0) - return; - - if (w0 != old_res_horz || h1 != old_res_vert || isRGB24 != old_rgb24) - { - old_res_horz = w0; - old_res_vert = h1; - old_rgb24 = (s16)isRGB24; - screen_buf = cbs->pl_fbdev_set_mode(w0, h1, isRGB24 ? 24 : 16); - } - dest = (u8 *)screen_buf; - - if (isRGB24) + // Update frameskip + if (gpu_unai.frameskip.skipCount==0) gpu_unai.frameskip.skipFrame=false; // frameskip off + else if (gpu_unai.frameskip.skipCount==7) { if (show) gpu_unai.frameskip.skipFrame=!gpu_unai.frameskip.skipFrame; } // frameskip medium + else if (gpu_unai.frameskip.skipCount==8) gpu_unai.frameskip.skipFrame=true; // frameskip maximum + else { -#ifndef MAEMO - for (; h1-- > 0; dest += w0 * 3, srcs += 1024) + static u32 spd=100; // speed % + static u32 frames=0; // frames counter + static u32 prev=now; // previous fps calculation + frames++; + if ((now-prev)>=(TPS>>GPU_FRAMESKIP_UPDATE)) { - bgr888_to_rgb888(dest, srcs, w0 * 3); - } -#else - for (; h1-- > 0; dest += w0 * 2, srcs += 1024) - { - bgr888_to_rgb565(dest, srcs, w0 * 3); + if (IS_PAL) spd=(frames<<1); + else spd=((frames*1001)/600); + spd<<=GPU_FRAMESKIP_UPDATE; + frames=0; + prev=now; } -#endif - } - else - { - for (; h1-- > 0; dest += w0 * 2, srcs += 1024) + switch(gpu_unai.frameskip.skipCount) { - bgr555_to_rgb565(dest, srcs, w0 * 2); + case 1: if (spd<50) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<50%) + case 2: if (spd<60) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<60%) + case 3: if (spd<70) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<70%) + case 4: if (spd<80) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<80%) + case 5: if (spd<90) gpu_unai.frameskip.skipFrame=true; else gpu_unai.frameskip.skipFrame=false; break; // frameskip on (spd<90%) } } - - screen_buf = cbs->pl_fbdev_flip(); } +/////////////////////////////////////////////////////////////////////////////// void GPU_updateLace(void) { // Interlace bit toggle - GPU_GP1 ^= 0x80000000; - - if (!fb_dirty || (GPU_GP1&0x08800000)) - return; + gpu_unai.GPU_GP1 ^= 0x80000000; - if (!isSkip) { - blit(); - - fb_dirty = false; - if (*cbs->fskip_option) - isSkip = true; + // Update display? + if ((gpu_unai.fb_dirty) && (!gpu_unai.frameskip.wasSkip) && (!(gpu_unai.GPU_GP1&0x00800000))) + { + // Display updated + gpuVideoOutput(); + GPU_frameskip(true); + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_updateLace(UPDATE)\n"); + #endif + } else { + GPU_frameskip(false); + #ifdef ENABLE_GPU_LOG_SUPPORT + fprintf(stdout,"GPU_updateLace(SKIP)\n"); + #endif } - else - isSkip = false; -} -long GPUopen(unsigned long *, char *, char *) -{ - cbs->pl_fbdev_open(); - screen_buf = cbs->pl_fbdev_flip(); - return 0; -} + if ((!gpu_unai.frameskip.skipCount) && (gpu_unai.DisplayArea[3] == 480)) gpu_unai.frameskip.skipGPU=true; // Tekken 3 hack -long GPUclose(void) -{ - cbs->pl_fbdev_close(); - return 0; + gpu_unai.fb_dirty=false; + gpu_unai.dma.last_dma = NULL; } -long GPUfreeze(unsigned int ulGetFreezeData, GPUFreeze_t* p2) +// Allows frontend to signal plugin to redraw screen after returning to emu +void GPU_requestScreenRedraw() { - if (ulGetFreezeData > 1) - return 0; - - return GPU_freeze(ulGetFreezeData, p2); + gpu_unai.fb_dirty = true; } -void GPUrearmedCallbacks(const struct rearmed_cbs *cbs_) +void GPU_getScreenInfo(GPUScreenInfo_t *sinfo) { - cbs = cbs_; + bool depth24 = (gpu_unai.GPU_GP1 & 0x00200000 ? true : false); + int16_t hres = (uint16_t)gpu_unai.DisplayArea[2]; + int16_t vres = (uint16_t)gpu_unai.DisplayArea[3]; + int16_t w = hres; // Original gpu_unai doesn't support width < 100% + int16_t h = gpu_unai.DisplayArea[5] - gpu_unai.DisplayArea[4]; + if (vres == 480) + h *= 2; + if (h <= 0 || h > vres) + h = vres; + + sinfo->vram = (uint8_t*)gpu_unai.vram; + sinfo->x = (uint16_t)gpu_unai.DisplayArea[0]; + sinfo->y = (uint16_t)gpu_unai.DisplayArea[1]; + sinfo->w = w; + sinfo->h = h; + sinfo->hres = hres; + sinfo->vres = vres; + sinfo->depth24 = depth24; + sinfo->pal = IS_PAL; } - -} /* extern "C" */ - -#endif