aboutsummaryrefslogtreecommitdiff
path: root/plugins/gpu_unai/gpu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/gpu_unai/gpu.cpp')
-rw-r--r--plugins/gpu_unai/gpu.cpp840
1 files changed, 840 insertions, 0 deletions
diff --git a/plugins/gpu_unai/gpu.cpp b/plugins/gpu_unai/gpu.cpp
new file mode 100644
index 0000000..ba32d18
--- /dev/null
+++ b/plugins/gpu_unai/gpu.cpp
@@ -0,0 +1,840 @@
+/***************************************************************************
+* Copyright (C) 2010 PCSX4ALL Team *
+* Copyright (C) 2010 Unai *
+* *
+* 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 *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
+***************************************************************************/
+
+#include "gpu.h"
+#include "port.h"
+#include "profiler.h"
+#include "debug.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 */
+
+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 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];
+
+///////////////////////////////////////////////////////////////////////////////
+// Rasterizer status
+u32 TextureWindow [4];
+u32 DrawingArea [4];
+u32 DrawingOffset [2];
+
+///////////////////////////////////////////////////////////////////////////////
+// Rasterizer status
+
+u16* TBA;
+u16* CBA;
+
+///////////////////////////////////////////////////////////////////////////////
+// Inner Loops
+s32 u4, du4;
+s32 v4, dv4;
+s32 r4, dr4;
+s32 g4, dg4;
+s32 b4, db4;
+u32 lInc;
+u32 tInc, tMsk;
+
+GPUPacket PacketBuffer;
+u16 GPU_FrameBuffer[FRAME_BUFFER_SIZE/2]; // FRAME_BUFFER_SIZE is defined in bytes
+u32 GPU_GP1;
+
+///////////////////////////////////////////////////////////////////////////////
+// Inner loop driver instanciation 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"
+
+///////////////////////////////////////////////////////////////////////////////
+// GPU internal line drawing functions
+#include "gpu_raster_line.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// GPU internal polygon drawing functions
+#include "gpu_raster_polygon.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// GPU internal sprite drawing functions
+#include "gpu_raster_sprite.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// GPU command buffer execution/store
+#include "gpu_command.h"
+
+///////////////////////////////////////////////////////////////////////////////
+INLINE 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;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+bool GPU_init(void)
+{
+ gpuReset();
+
+ // s_invTable
+ for(int i=1;i<=(1<<TABLE_BITS);++i)
+ {
+ double v = 1.0 / double(i);
+ #ifdef GPU_TABLE_10_BITS
+ v *= double(0xffffffff>>1);
+ #else
+ v *= double(0x80000000);
+ #endif
+ s_invTable[i-1]=s32(v);
+ }
+ return (0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void GPU_shutdown(void)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+long GPU_freeze(unsigned int bWrite, GPUFreeze_t* p2)
+{
+ if (!p2) return (0);
+ if (p2->Version != 1) return (0);
+
+ if (bWrite)
+ {
+ p2->GPU_gp1 = GPU_GP1;
+ memcpy(p2->FrameBuffer, (u16*)GPU_FrameBuffer, FRAME_BUFFER_SIZE);
+ return (1);
+ }
+ else
+ {
+ GPU_GP1 = p2->GPU_gp1;
+ memcpy((u16*)GPU_FrameBuffer, p2->FrameBuffer, FRAME_BUFFER_SIZE);
+ return (1);
+ }
+ return (0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// GPU DMA comunication
+
+///////////////////////////////////////////////////////////////////////////////
+u8 PacketSize[256] =
+{
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31
+ 3, 3, 3, 3, 6, 6, 6, 6, 4, 4, 4, 4, 8, 8, 8, 8, // 32-47
+ 5, 5, 5, 5, 8, 8, 8, 8, 7, 7, 7, 7, 11, 11, 11, 11, // 48-63
+ 2, 2, 2, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, // 64-79
+ 3, 3, 3, 3, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, // 80-95
+ 2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, // 96-111
+ 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, // 112-127
+ 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128-
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 //
+};
+
+///////////////////////////////////////////////////////////////////////////////
+INLINE void gpuSendPacket()
+{
+#ifdef DEBUG_ANALYSIS
+ dbg_anacnt_GPU_sendPacket++;
+#endif
+ gpuSendPacketFunction(PacketBuffer.U4[0]>>24);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+INLINE void gpuCheckPacket(u32 uData)
+{
+ if (PacketCount)
+ {
+ PacketBuffer.U4[PacketIndex++] = uData;
+ --PacketCount;
+ }
+ else
+ {
+ PacketBuffer.U4[0] = uData;
+ PacketCount = PacketSize[uData >> 24];
+ PacketIndex = 1;
+ }
+ if (!PacketCount) gpuSendPacket();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void GPU_writeDataMem(u32* dmaAddress, s32 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);
+ u32 data;
+ const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
+ GPU_GP1 &= ~0x14000000;
+
+ while (dmaCount)
+ {
+ if (FrameToWrite)
+ {
+ while (dmaCount--)
+ {
+ data = *dmaAddress++;
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ pvram[px] = data;
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram += 1024;
+ if (++py>=y_end)
+ {
+ FrameToWrite = 0;
+ GPU_GP1 &= ~0x08000000;
+ break;
+ }
+ }
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ pvram[px] = data>>16;
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram += 1024;
+ if (++py>=y_end)
+ {
+ FrameToWrite = 0;
+ GPU_GP1 &= ~0x08000000;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ data = *dmaAddress++;
+ dmaCount--;
+ gpuCheckPacket(data);
+ }
+ }
+
+ GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
+ pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+ pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
+}
+
+u32 *lUsedAddr[3];
+INLINE int CheckForEndlessLoop(u32 *laddr)
+{
+ if(laddr==lUsedAddr[1]) return 1;
+ if(laddr==lUsedAddr[2]) return 1;
+
+ if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
+ else lUsedAddr[2]=laddr;
+ lUsedAddr[0]=laddr;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void GPU_dmaChain(u32* baseAddr, u32 dmaVAddr)
+{
+#ifdef DEBUG_ANALYSIS
+ dbg_anacnt_GPU_dmaChain++;
+#endif
+ pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+ u32 data, *address, count, offset;
+ unsigned int DMACommandCounter = 0;
+
+ GPU_GP1 &= ~0x14000000;
+ lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=(u32*)0x1fffff;
+ dmaVAddr &= 0x001FFFFF;
+ while (dmaVAddr != 0x1FFFFF)
+ {
+ 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);
+ }
+ GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
+ pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+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;
+
+ if (FrameToWrite)
+ {
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ pvram[px]=(u16)data;
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram += 1024;
+ if (++py>=y_end)
+ {
+ FrameToWrite = 0;
+ GPU_GP1 &= ~0x08000000;
+ }
+ }
+ if (FrameToWrite)
+ {
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ pvram[px]=data>>16;
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram += 1024;
+ if (++py>=y_end)
+ {
+ FrameToWrite = 0;
+ GPU_GP1 &= ~0x08000000;
+ }
+ }
+ }
+ }
+ else
+ {
+ gpuCheckPacket(data);
+ }
+ GPU_GP1 |= 0x14000000;
+ pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+ pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
+
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+void GPU_readDataMem(u32* dmaAddress, s32 dmaCount)
+{
+ const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
+#ifdef DEBUG_ANALYSIS
+ dbg_anacnt_GPU_readDataMem++;
+#endif
+ if(!FrameToRead) return;
+
+ pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+ GPU_GP1 &= ~0x14000000;
+ do
+ {
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ // lower 16 bit
+ u32 data = (unsigned long)pvram[px];
+
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram += 1024;
+ }
+
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ // higher 16 bit (always, even if it's an odd width)
+ data |= (unsigned long)(pvram[px])<<16;
+
+ *dmaAddress++ = data;
+
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram += 1024;
+ if (++py>=y_end)
+ {
+ FrameToRead = 0;
+ GPU_GP1 &= ~0x08000000;
+ break;
+ }
+ }
+ } while (--dmaCount);
+
+ GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
+ pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+}
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+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)
+ {
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ GP0 = pvram[px];
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram += 1024;
+ if (++py>=y_end)
+ {
+ FrameToRead = 0;
+ GPU_GP1 &= ~0x08000000;
+ }
+ }
+ if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
+ GP0 |= pvram[px]<<16;
+ if (++px>=x_end)
+ {
+ px = 0;
+ pvram +=1024;
+ if (++py>=y_end)
+ {
+ FrameToRead = 0;
+ GPU_GP1 &= ~0x08000000;
+ }
+ }
+
+ }
+ GPU_GP1 |= 0x14000000;
+
+ pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_READ);
+ pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
+ return (GP0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+u32 GPU_readStatus(void)
+{
+#ifdef DEBUG_ANALYSIS
+ dbg_anacnt_GPU_readStatus++;
+#endif
+ return GPU_GP1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+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);
+ switch (data >> 24) {
+ case 0x00:
+ gpuReset();
+ break;
+ case 0x01:
+ GPU_GP1 &= ~0x08000000;
+ PacketCount = FrameToRead = FrameToWrite = 0;
+ break;
+ case 0x02:
+ GPU_GP1 &= ~0x08000000;
+ PacketCount = FrameToRead = FrameToWrite = 0;
+ break;
+ case 0x03:
+ GPU_GP1 = (GPU_GP1 & ~0x00800000) | ((data & 1) << 23);
+ break;
+ case 0x04:
+ if (data == 0x04000000)
+ PacketCount = 0;
+ GPU_GP1 = (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);
+ break;
+ case 0x07:
+ DisplayArea[4] = data & 0x000003FF; //(short)(data & 0x3ff);
+ DisplayArea[5] = (data & 0x000FFC00) >> 10; //(short)((data>>10) & 0x3ff);
+ 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
+ }
+ 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;
+ }
+ break;
+ }
+ pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
+ pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
+}
+
+// Blitting functions
+#include "gpu_blit.h"
+
+INLINE void gpuVideoOutput(void)
+{
+ static s16 old_res_horz, old_res_vert, old_rgb24;
+ s16 h0, x0, y0, w0, h1;
+
+ x0 = DisplayArea[0];
+ y0 = DisplayArea[1];
+
+ w0 = DisplayArea[2];
+ h0 = DisplayArea[3]; // video mode
+
+ h1 = DisplayArea[5] - 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);
+
+ /* 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();
+ }
+
+ // 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<h0) dest_screen16 += ((h0-h1)>>sizeShift)*VIDEO_WIDTH;
+
+ /* Main blitter */
+ int incY = (h0==480) ? 2 : 1;
+ h0=(h0==480 ? 2048 : 1024);
+
+ if (!progressInterlace)
+ {
+ const int li=linesInterlace;
+ switch ( w0 )
+ {
+ case 256:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if( 0 == (y0&li) ) GPU_BlitWWDWW( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 368:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if( 0 == (y0&li) ) GPU_BlitWWWWWWWWS( src_screen16, dest_screen16, isRGB24, 4);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 320:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if( 0 == (y0&li) ) GPU_BlitWW( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 384:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if( 0 == (y0&li) ) GPU_BlitWWWWWS( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 512:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if( 0 == (y0&li) ) GPU_BlitWWSWWSWS( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 640:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if( 0 == (y0&li) ) GPU_BlitWS( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ }
+ }
+ else
+ {
+ const int li=linesInterlace;
+ bool flag=progressInterlace_flag; /* progressive interlace */
+ switch ( w0 )
+ {
+ case 256:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWDWW( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 368:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWWWWWWWS( src_screen16, dest_screen16, isRGB24, 4);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 320:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWW( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 384:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWWWWS( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 512:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWSWWSWS( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ case 640:
+ for(int y1=y0+h1; y0<y1; y0+=incY)
+ {
+ if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWS( src_screen16, dest_screen16, isRGB24);
+ dest_screen16 += VIDEO_WIDTH;
+ src_screen16 += h0;
+ }
+ break;
+ }
+ progressInterlace_flag=!flag;
+ }
+ video_flip();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+void GPU_updateLace(void)
+{
+#ifdef ENABLE_GPU_LOG_SUPPORT
+ fprintf(stdout,"GPU_updateLace()\n");
+#endif
+#ifdef DEBUG_ANALYSIS
+ dbg_anacnt_GPU_updateLace++;
+#endif
+ pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_COUNTERS);
+#ifdef PROFILER_PCSX4ALL
+ pcsx4all_prof_frames++;
+#endif
+#ifdef DEBUG_FRAME
+ if(isdbg_frame())
+ {
+ static int passed=0;
+ if (!passed) dbg_enable();
+ else pcsx4all_exit();
+ passed++;
+ }
+#endif
+
+ // Frame skip table
+ static const unsigned char skipTable[12][12] =
+ {
+ { 0,0,0,0,0,0,0,0,0,0,0,0 },
+ { 0,0,0,0,0,0,0,0,0,0,0,1 },
+ { 0,0,0,0,0,1,0,0,0,0,0,1 },
+ { 0,0,0,1,0,0,0,1,0,0,0,1 },
+ { 0,0,1,0,0,1,0,0,1,0,0,1 },
+ { 0,1,0,0,1,0,1,0,0,1,0,1 },
+ { 0,1,0,1,0,1,0,1,0,1,0,1 },
+ { 0,1,0,1,1,0,1,0,1,1,0,1 },
+ { 0,1,1,0,1,1,0,1,1,0,1,1 },
+ { 0,1,1,1,0,1,1,1,0,1,1,1 },
+ { 0,1,1,1,1,1,0,1,1,1,1,1 },
+ { 0,1,1,1,1,1,1,1,1,1,1,1 }
+ };
+
+ // Interlace bit toggle
+ GPU_GP1 ^= 0x80000000;
+
+ // Update display
+ if ((!skipFrame) && (!isSkip) && (!(((GPU_GP1&0x08000000))||((GPU_GP1&0x00800000)))))
+ {
+ gpuVideoOutput(); // Display updated
+
+ if (DisplayArea[3] == 480)
+ {
+ if (linesInterlace_user) linesInterlace = 3; // 1/4 of lines
+ else linesInterlace = 1; // if 480 we only need half of lines
+ }
+ else if (linesInterlace != linesInterlace_user)
+ {
+ linesInterlace = linesInterlace_user; // resolution changed from 480 to lower one
+ video_clear();
+ }
+
+ // Limit FPS
+ if (frameLimit)
+ {
+ static unsigned next=get_ticks();
+ unsigned now=get_ticks();
+ if (!skipFrame)
+ {
+ if (now<next) wait_ticks(next-now);
+ }
+ next+=(isPAL?(1000000/50):((unsigned)(1000000.0/59.94)));
+ }
+ }
+
+ // 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);
+}