gpu_unai: pcsx-rearmed port
[pcsx_rearmed.git] / plugins / gpu_unai / gpu.cpp
1 /***************************************************************************
2 *   Copyright (C) 2010 PCSX4ALL Team                                      *
3 *   Copyright (C) 2010 Unai                                               *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 *                                                                         *
10 *   This program is distributed in the hope that it will be useful,       *
11 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13 *   GNU General Public License for more details.                          *
14 *                                                                         *
15 *   You should have received a copy of the GNU General Public License     *
16 *   along with this program; if not, write to the                         *
17 *   Free Software Foundation, Inc.,                                       *
18 *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
19 ***************************************************************************/
20
21 #include "port.h"
22 #include "gpu.h"
23 #include "profiler.h"
24 #include "debug.h"
25
26 int skipCount = 2; /* frame skip (0,1,2,3...) */
27 int skCount=0; /* internal frame skip */
28 int linesInterlace = 0;  /* internal lines interlace */
29 int linesInterlace_user = 0; /* Lines interlace */
30
31 bool isSkip=false; /* skip frame (info coming from GPU) */
32 bool skipFrame=false; /* skip frame (according to frame skip) */
33 bool alt_fps = false; /* Alternative FPS algorithm */
34 bool show_fps = false; /* Show FPS statistics */
35
36 bool isPAL=false; /* PAL video timing */
37 bool progressInterlace_flag = false; /* Progressive interlace flag */
38 bool progressInterlace = false; /* Progressive interlace option*/
39 bool frameLimit = false; /* frames to wait */
40 bool light = true; /* lighting */
41 bool blend = true; /* blending */
42
43 bool enableAbbeyHack = false; /* Abe's Odyssey hack */
44 u8 BLEND_MODE;
45 u8 TEXT_MODE;
46 u8 Masking;
47
48 u16 PixelMSB;
49 u16 PixelData;
50
51 ///////////////////////////////////////////////////////////////////////////////
52 //  GPU Global data
53 ///////////////////////////////////////////////////////////////////////////////
54
55 ///////////////////////////////////////////////////////////////////////////////
56 //  Dma Transfers info
57 s32             px,py;
58 s32             x_end,y_end;
59 u16*  pvram;
60
61 u32 FrameToRead;
62 u32 FrameToWrite;
63
64 u32 GP0;
65 s32 PacketCount;
66 s32 PacketIndex;
67
68 ///////////////////////////////////////////////////////////////////////////////
69 //  Display status
70 u32 DisplayArea   [6];
71
72 ///////////////////////////////////////////////////////////////////////////////
73 //  Rasterizer status
74 u32 TextureWindow [4];
75 u32 DrawingArea   [4];
76 u32 DrawingOffset [2];
77
78 ///////////////////////////////////////////////////////////////////////////////
79 //  Rasterizer status
80
81 u16* TBA;
82 u16* CBA;
83
84 ///////////////////////////////////////////////////////////////////////////////
85 //  Inner Loops
86 s32   u4, du4;
87 s32   v4, dv4;
88 s32   r4, dr4;
89 s32   g4, dg4;
90 s32   b4, db4;
91 u32   lInc;
92 u32   tInc, tMsk;
93
94 GPUPacket PacketBuffer;
95 u16   GPU_FrameBuffer[FRAME_BUFFER_SIZE/2] __attribute__((aligned(16)));    // FRAME_BUFFER_SIZE is defined in bytes
96 u32   GPU_GP1;
97
98 ///////////////////////////////////////////////////////////////////////////////
99 //  Inner loop driver instanciation file
100 #include "gpu_inner.h"
101
102 ///////////////////////////////////////////////////////////////////////////////
103 //  GPU Raster Macros
104 #define GPU_RGB16(rgb)        ((((rgb)&0xF80000)>>9)|(((rgb)&0xF800)>>6)|(((rgb)&0xF8)>>3))
105
106 #define GPU_EXPANDSIGN_POLY(x)  (((s32)(x)<<20)>>20)
107 //#define GPU_EXPANDSIGN_POLY(x)  (((s32)(x)<<21)>>21)
108 #define GPU_EXPANDSIGN_SPRT(x)  (((s32)(x)<<21)>>21)
109
110 //#define       GPU_TESTRANGE(x)      { if((u32)(x+1024) > 2047) return; }
111 #define GPU_TESTRANGE(x)      { if ((x<-1023) || (x>1023)) return; }
112
113 #define GPU_SWAP(a,b,t) {(t)=(a);(a)=(b);(b)=(t);}
114
115 ///////////////////////////////////////////////////////////////////////////////
116 // GPU internal image drawing functions
117 #include "gpu_raster_image.h"
118
119 ///////////////////////////////////////////////////////////////////////////////
120 // GPU internal line drawing functions
121 #include "gpu_raster_line.h"
122
123 ///////////////////////////////////////////////////////////////////////////////
124 // GPU internal polygon drawing functions
125 #include "gpu_raster_polygon.h"
126
127 ///////////////////////////////////////////////////////////////////////////////
128 // GPU internal sprite drawing functions
129 #include "gpu_raster_sprite.h"
130
131 ///////////////////////////////////////////////////////////////////////////////
132 // GPU command buffer execution/store
133 #include "gpu_command.h"
134
135 ///////////////////////////////////////////////////////////////////////////////
136 INLINE void gpuReset(void)
137 {
138         GPU_GP1 = 0x14802000;
139         TextureWindow[0] = 0;
140         TextureWindow[1] = 0;
141         TextureWindow[2] = 255;
142         TextureWindow[3] = 255;
143         DrawingArea[2] = 256;
144         DrawingArea[3] = 240;
145         DisplayArea[2] = 256;
146         DisplayArea[3] = 240;
147         DisplayArea[5] = 240;
148 }
149
150 ///////////////////////////////////////////////////////////////////////////////
151 bool  GPU_init(void)
152 {
153         gpuReset();
154         
155         // s_invTable
156         for(int i=1;i<=(1<<TABLE_BITS);++i)
157         {
158                 double v = 1.0 / double(i);
159                 #ifdef GPU_TABLE_10_BITS
160                 v *= double(0xffffffff>>1);
161                 #else
162                 v *= double(0x80000000);
163                 #endif
164                 s_invTable[i-1]=s32(v);
165         }
166         return (0);
167 }
168
169 ///////////////////////////////////////////////////////////////////////////////
170 void  GPU_shutdown(void)
171 {
172 }
173
174 ///////////////////////////////////////////////////////////////////////////////
175 long  GPU_freeze(unsigned int bWrite, GPUFreeze_t* p2)
176 {
177         if (!p2) return (0);
178         if (p2->Version != 1) return (0);
179
180         if (bWrite)
181         {
182                 p2->GPU_gp1 = GPU_GP1;
183                 memcpy(p2->FrameBuffer, (u16*)GPU_FrameBuffer, FRAME_BUFFER_SIZE);
184                 return (1);
185         }
186         else
187         {
188                 GPU_GP1 = p2->GPU_gp1;
189                 memcpy((u16*)GPU_FrameBuffer, p2->FrameBuffer, FRAME_BUFFER_SIZE);
190                 return (1);
191         }
192         return (0);
193 }
194
195 ///////////////////////////////////////////////////////////////////////////////
196 //  GPU DMA comunication
197
198 ///////////////////////////////////////////////////////////////////////////////
199 u8 PacketSize[256] =
200 {
201         0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //              0-15
202         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //              16-31
203         3, 3, 3, 3, 6, 6, 6, 6, 4, 4, 4, 4, 8, 8, 8, 8, //              32-47
204         5, 5, 5, 5, 8, 8, 8, 8, 7, 7, 7, 7, 11, 11, 11, 11,     //      48-63
205         2, 2, 2, 2, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, //              64-79
206         3, 3, 3, 3, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, //              80-95
207         2, 2, 2, 2, 3, 3, 3, 3, 1, 1, 1, 1, 2, 2, 2, 2, //              96-111
208         1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 2, 2, 2, 2, //              112-127
209         3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //              128-
210         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //              144
211         2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //              160
212         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
213         2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
214         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
215         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //
216         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  //
217 };
218
219 ///////////////////////////////////////////////////////////////////////////////
220 INLINE void gpuSendPacket()
221 {
222 #ifdef DEBUG_ANALYSIS
223         dbg_anacnt_GPU_sendPacket++;
224 #endif
225         gpuSendPacketFunction(PacketBuffer.U4[0]>>24);
226 }
227
228 ///////////////////////////////////////////////////////////////////////////////
229 INLINE void gpuCheckPacket(u32 uData)
230 {
231         if (PacketCount)
232         {
233                 PacketBuffer.U4[PacketIndex++] = uData;
234                 --PacketCount;
235         }
236         else
237         {
238                 PacketBuffer.U4[0] = uData;
239                 PacketCount = PacketSize[uData >> 24];
240                 PacketIndex = 1;
241         }
242         if (!PacketCount) gpuSendPacket();
243 }
244
245 ///////////////////////////////////////////////////////////////////////////////
246 void  GPU_writeDataMem(u32* dmaAddress, s32 dmaCount)
247 {
248 #ifdef DEBUG_ANALYSIS
249         dbg_anacnt_GPU_writeDataMem++;
250 #endif
251         pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
252         pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
253         u32 data;
254         const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
255         GPU_GP1 &= ~0x14000000;
256
257         while (dmaCount) 
258         {
259                 if (FrameToWrite) 
260                 {
261                         while (dmaCount--) 
262                         {
263                                 data = *dmaAddress++;
264                                 if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
265                                 pvram[px] = data;
266                                 if (++px>=x_end) 
267                                 {
268                                         px = 0;
269                                         pvram += 1024;
270                                         if (++py>=y_end) 
271                                         {
272                                                 FrameToWrite = 0;
273                                                 GPU_GP1 &= ~0x08000000;
274                                                 break;
275                                         }
276                                 }
277                                 if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
278                                 pvram[px] = data>>16;
279                                 if (++px>=x_end) 
280                                 {
281                                         px = 0;
282                                         pvram += 1024;
283                                         if (++py>=y_end) 
284                                         {
285                                                 FrameToWrite = 0;
286                                                 GPU_GP1 &= ~0x08000000;
287                                                 break;
288                                         }
289                                 }
290                         }
291                 }
292                 else
293                 {
294                         data = *dmaAddress++;
295                         dmaCount--;
296                         gpuCheckPacket(data);
297                 }
298         }
299
300         GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
301         pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
302         pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
303 }
304
305 u32 *lUsedAddr[3];
306 INLINE int CheckForEndlessLoop(u32 *laddr)
307 {
308         if(laddr==lUsedAddr[1]) return 1;
309         if(laddr==lUsedAddr[2]) return 1;
310
311         if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
312         else                   lUsedAddr[2]=laddr;
313         lUsedAddr[0]=laddr;
314         return 0;
315 }
316
317 ///////////////////////////////////////////////////////////////////////////////
318 void  GPU_dmaChain(u32* baseAddr, u32 dmaVAddr)
319 {
320 #ifdef DEBUG_ANALYSIS
321         dbg_anacnt_GPU_dmaChain++;
322 #endif
323         pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
324         u32 data, *address, count, offset;
325         unsigned int DMACommandCounter = 0;
326
327         GPU_GP1 &= ~0x14000000;
328         lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=(u32*)0x1fffff;
329         dmaVAddr &= 0x001FFFFF;
330         while (dmaVAddr != 0x1FFFFF)
331         {
332                 address = (baseAddr + (dmaVAddr >> 2));
333                 if(DMACommandCounter++ > 2000000) break;
334                 if(CheckForEndlessLoop(address)) break;
335                 data = *address++;
336                 count = (data >> 24);
337                 offset = data & 0x001FFFFF;
338                 if (dmaVAddr != offset) dmaVAddr = offset;
339                 else dmaVAddr = 0x1FFFFF;
340
341                 if(count>0) GPU_writeDataMem(address,count);
342         }
343         GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
344         pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
345 }
346
347 ///////////////////////////////////////////////////////////////////////////////
348 void  GPU_writeData(u32 data)
349 {
350         const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
351 #ifdef DEBUG_ANALYSIS
352         dbg_anacnt_GPU_writeData++;
353 #endif
354         pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
355         pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
356         GPU_GP1 &= ~0x14000000;
357
358         if (FrameToWrite)
359         {
360                 if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
361                 pvram[px]=(u16)data;
362                 if (++px>=x_end)
363                 {
364                         px = 0;
365                         pvram += 1024;
366                         if (++py>=y_end) 
367                         {
368                                 FrameToWrite = 0;
369                                 GPU_GP1 &= ~0x08000000;
370                         }
371                 }
372                 if (FrameToWrite)
373                 {
374                         if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
375                         pvram[px]=data>>16;
376                         if (++px>=x_end)
377                         {
378                                 px = 0;
379                                 pvram += 1024;
380                                 if (++py>=y_end) 
381                                 {
382                                         FrameToWrite = 0;
383                                         GPU_GP1 &= ~0x08000000;
384                                 }
385                         }
386                 }
387         }
388         else
389         {
390                 gpuCheckPacket(data);
391         }
392         GPU_GP1 |= 0x14000000;
393         pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
394         pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
395
396 }
397
398
399 ///////////////////////////////////////////////////////////////////////////////
400 void  GPU_readDataMem(u32* dmaAddress, s32 dmaCount)
401 {
402         const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
403 #ifdef DEBUG_ANALYSIS
404         dbg_anacnt_GPU_readDataMem++;
405 #endif
406         if(!FrameToRead) return;
407
408         pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
409         GPU_GP1 &= ~0x14000000;
410         do 
411         {
412                 if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
413                 // lower 16 bit
414                 u32 data = (unsigned long)pvram[px];
415
416                 if (++px>=x_end) 
417                 {
418                         px = 0;
419                         pvram += 1024;
420                 }
421
422                 if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
423                 // higher 16 bit (always, even if it's an odd width)
424                 data |= (unsigned long)(pvram[px])<<16;
425                 
426                 *dmaAddress++ = data;
427
428                 if (++px>=x_end) 
429                 {
430                         px = 0;
431                         pvram += 1024;
432                         if (++py>=y_end) 
433                         {
434                                 FrameToRead = 0;
435                                 GPU_GP1 &= ~0x08000000;
436                                 break;
437                         }
438                 }
439         } while (--dmaCount);
440
441         GPU_GP1 = (GPU_GP1 | 0x14000000) & ~0x60000000;
442         pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
443 }
444
445
446
447 ///////////////////////////////////////////////////////////////////////////////
448 u32  GPU_readData(void)
449 {
450         const u16 *VIDEO_END=(GPU_FrameBuffer+(FRAME_BUFFER_SIZE/2)-1);
451 #ifdef DEBUG_ANALYSIS
452         dbg_anacnt_GPU_readData++;
453 #endif
454         pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
455         pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_READ);
456         GPU_GP1 &= ~0x14000000;
457         if (FrameToRead)
458         {
459                 if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
460                 GP0 = pvram[px];
461                 if (++px>=x_end)
462                 {
463                         px = 0;
464                         pvram += 1024;
465                         if (++py>=y_end) 
466                         {
467                                 FrameToRead = 0;
468                                 GPU_GP1 &= ~0x08000000;
469                         }
470                 }
471                 if ((&pvram[px])>(VIDEO_END)) pvram-=512*1024;
472                 GP0 |= pvram[px]<<16;
473                 if (++px>=x_end)
474                 {
475                         px = 0;
476                         pvram +=1024;
477                         if (++py>=y_end) 
478                         {
479                                 FrameToRead = 0;
480                                 GPU_GP1 &= ~0x08000000;
481                         }
482                 }
483
484         }
485         GPU_GP1 |= 0x14000000;
486
487         pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_READ);
488         pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
489         return (GP0);
490 }
491
492 ///////////////////////////////////////////////////////////////////////////////
493 u32     GPU_readStatus(void)
494 {
495 #ifdef DEBUG_ANALYSIS
496         dbg_anacnt_GPU_readStatus++;
497 #endif
498         return GPU_GP1;
499 }
500
501 ///////////////////////////////////////////////////////////////////////////////
502 void  GPU_writeStatus(u32 data)
503 {
504 #ifdef DEBUG_ANALYSIS
505         dbg_anacnt_GPU_writeStatus++;
506 #endif
507         pcsx4all_prof_pause(PCSX4ALL_PROF_CPU);
508         pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
509         switch (data >> 24) {
510         case 0x00:
511                 gpuReset();
512                 break;
513         case 0x01:
514                 GPU_GP1 &= ~0x08000000;
515                 PacketCount = FrameToRead = FrameToWrite = 0;
516                 break;
517         case 0x02:
518                 GPU_GP1 &= ~0x08000000;
519                 PacketCount = FrameToRead = FrameToWrite = 0;
520                 break;
521         case 0x03:
522                 GPU_GP1 = (GPU_GP1 & ~0x00800000) | ((data & 1) << 23);
523                 break;
524         case 0x04:
525                 if (data == 0x04000000)
526                 PacketCount = 0;
527                 GPU_GP1 = (GPU_GP1 & ~0x60000000) | ((data & 3) << 29);
528                 break;
529         case 0x05:
530                 DisplayArea[0] = (data & 0x000003FF); //(short)(data & 0x3ff);
531                 DisplayArea[1] = ((data & 0x0007FC00)>>10); //(data & 0x000FFC00) >> 10; //(short)((data>>10)&0x1ff);
532                 break;
533         case 0x07:
534                 DisplayArea[4] = data & 0x000003FF; //(short)(data & 0x3ff);
535                 DisplayArea[5] = (data & 0x000FFC00) >> 10; //(short)((data>>10) & 0x3ff);
536                 break;
537         case 0x08:
538                 {
539                         GPU_GP1 = (GPU_GP1 & ~0x007F0000) | ((data & 0x3F) << 17) | ((data & 0x40) << 10);
540                         static u32 HorizontalResolution[8] = { 256, 368, 320, 384, 512, 512, 640, 640 };
541                         DisplayArea[2] = HorizontalResolution[(GPU_GP1 >> 16) & 7];
542                         static u32 VerticalResolution[4] = { 240, 480, 256, 480 };
543                         DisplayArea[3] = VerticalResolution[(GPU_GP1 >> 19) & 3];
544                         isPAL = (data & 0x08) ? true : false; // if 1 - PAL mode, else NTSC
545                 }
546                 break;
547         case 0x10:
548                 switch (data & 0xffff) {
549                 case 0:
550                 case 1:
551                 case 3:
552                         GP0 = (DrawingArea[1] << 10) | DrawingArea[0];
553                         break;
554                 case 4:
555                         GP0 = ((DrawingArea[3]-1) << 10) | (DrawingArea[2]-1);
556                         break;
557                 case 6:
558                 case 5:
559                         GP0 = (DrawingOffset[1] << 11) | DrawingOffset[0];
560                         break;
561                 case 7:
562                         GP0 = 2;
563                         break;
564                 default:
565                         GP0 = 0;
566                 }
567                 break;
568         }
569         pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
570         pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
571 }
572
573 #ifndef REARMED
574
575 // Blitting functions
576 #include "gpu_blit.h"
577
578 INLINE void gpuVideoOutput(void)
579 {
580         static s16 old_res_horz, old_res_vert, old_rgb24;
581         s16 h0, x0, y0, w0, h1;
582
583         x0 = DisplayArea[0];
584         y0 = DisplayArea[1];
585
586         w0 = DisplayArea[2];
587         h0 = DisplayArea[3];  // video mode
588
589         h1 = DisplayArea[5] - DisplayArea[4]; // display needed
590         if (h0 == 480) h1 = Min2(h1*2,480);
591
592         u16* dest_screen16 = SCREEN;
593         u16* src_screen16  = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0,y0)];
594         u32 isRGB24 = (GPU_GP1 & 0x00200000 ? 32 : 0);
595
596         /* Clear the screen if resolution changed to prevent interlacing and clipping to clash */
597         if( (w0 != old_res_horz || h1 != old_res_vert || (s16)isRGB24 != old_rgb24) )
598         {
599                 // Update old resolution
600                 old_res_horz = w0;
601                 old_res_vert = h1;
602                 old_rgb24 = (s16)isRGB24;
603                 // Finally, clear the screen for this special case
604                 video_clear();
605         }
606
607         //  Height centering
608         int sizeShift = 1;
609         if(h0==256) h0 = 240; else if(h0==480) sizeShift = 2;
610         if(h1>h0) { src_screen16 += ((h1-h0)>>sizeShift)*1024; h1 = h0; }
611         else if(h1<h0) dest_screen16 += ((h0-h1)>>sizeShift)*VIDEO_WIDTH;
612
613         /* Main blitter */
614         int incY = (h0==480) ? 2 : 1;
615         h0=(h0==480 ? 2048 : 1024);
616
617         if (!progressInterlace)
618         {
619                 const int li=linesInterlace;
620                 switch ( w0 )
621                 {
622                         case 256:
623                                 for(int y1=y0+h1; y0<y1; y0+=incY)
624                                 {
625                                         if( 0 == (y0&li) ) GPU_BlitWWDWW(       src_screen16,   dest_screen16, isRGB24);
626                                         dest_screen16 += VIDEO_WIDTH;
627                                         src_screen16  += h0;
628                                 }
629                                 break;
630                         case 368:
631                                 for(int y1=y0+h1; y0<y1; y0+=incY)
632                                 {
633                                         if( 0 == (y0&li) ) GPU_BlitWWWWWWWWS(   src_screen16,   dest_screen16, isRGB24, 4);
634                                         dest_screen16 += VIDEO_WIDTH;
635                                         src_screen16  += h0;
636                                 }
637                                 break;
638                         case 320:
639                                 for(int y1=y0+h1; y0<y1; y0+=incY)
640                                 {
641                                         if( 0 == (y0&li) ) GPU_BlitWW(  src_screen16,   dest_screen16, isRGB24);
642                                         dest_screen16 += VIDEO_WIDTH;
643                                         src_screen16  += h0;
644                                 }
645                                 break;
646                         case 384:
647                                 for(int y1=y0+h1; y0<y1; y0+=incY)
648                                 {
649                                         if( 0 == (y0&li) ) GPU_BlitWWWWWS(      src_screen16,   dest_screen16, isRGB24);
650                                         dest_screen16 += VIDEO_WIDTH;
651                                         src_screen16  += h0;
652                                 }
653                                 break;
654                         case 512:
655                                 for(int y1=y0+h1; y0<y1; y0+=incY)
656                                 {
657                                         if( 0 == (y0&li) ) GPU_BlitWWSWWSWS(    src_screen16, dest_screen16, isRGB24);
658                                         dest_screen16 += VIDEO_WIDTH;
659                                         src_screen16  += h0;
660                                 }
661                                 break;
662                         case 640:
663                                 for(int y1=y0+h1; y0<y1; y0+=incY)
664                                 {
665                                         if( 0 == (y0&li) ) GPU_BlitWS(  src_screen16, dest_screen16, isRGB24);
666                                         dest_screen16 += VIDEO_WIDTH;
667                                         src_screen16  += h0;
668                                 }
669                                 break;
670                 }
671         }
672         else
673         {
674                 const int li=linesInterlace;
675                 bool flag=progressInterlace_flag; /* progressive interlace */
676                 switch ( w0 )
677                 {
678                         case 256:
679                                 for(int y1=y0+h1; y0<y1; y0+=incY)
680                                 {
681                                         if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWDWW(     src_screen16,   dest_screen16, isRGB24);
682                                         dest_screen16 += VIDEO_WIDTH;
683                                         src_screen16  += h0;
684                                 }
685                                 break;
686                         case 368:
687                                 for(int y1=y0+h1; y0<y1; y0+=incY)
688                                 {
689                                         if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWWWWWWWS( src_screen16,   dest_screen16, isRGB24, 4);
690                                         dest_screen16 += VIDEO_WIDTH;
691                                         src_screen16  += h0;
692                                 }
693                                 break;
694                         case 320:
695                                 for(int y1=y0+h1; y0<y1; y0+=incY)
696                                 {
697                                         if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWW(        src_screen16,   dest_screen16, isRGB24);
698                                         dest_screen16 += VIDEO_WIDTH;
699                                         src_screen16  += h0;
700                                 }
701                                 break;
702                         case 384:
703                                 for(int y1=y0+h1; y0<y1; y0+=incY)
704                                 {
705                                         if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWWWWS(    src_screen16,   dest_screen16, isRGB24);
706                                         dest_screen16 += VIDEO_WIDTH;
707                                         src_screen16  += h0;
708                                 }
709                                 break;
710                         case 512:
711                                 for(int y1=y0+h1; y0<y1; y0+=incY)
712                                 {
713                                         if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWWSWWSWS(  src_screen16, dest_screen16, isRGB24);
714                                         dest_screen16 += VIDEO_WIDTH;
715                                         src_screen16  += h0;
716                                 }
717                                 break;
718                         case 640:
719                                 for(int y1=y0+h1; y0<y1; y0+=incY)
720                                 {
721                                         if(( 0 == (y0&li) ) && (flag=!flag)) GPU_BlitWS(        src_screen16, dest_screen16, isRGB24);
722                                         dest_screen16 += VIDEO_WIDTH;
723                                         src_screen16  += h0;
724                                 }
725                                 break;
726                 }
727                 progressInterlace_flag=!flag;
728         }
729         video_flip();
730 }
731
732 ///////////////////////////////////////////////////////////////////////////////
733 void  GPU_updateLace(void)
734 {
735 #ifdef  ENABLE_GPU_LOG_SUPPORT
736         fprintf(stdout,"GPU_updateLace()\n");
737 #endif
738 #ifdef DEBUG_ANALYSIS
739         dbg_anacnt_GPU_updateLace++;
740 #endif
741         pcsx4all_prof_start_with_pause(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_COUNTERS);
742 #ifdef PROFILER_PCSX4ALL
743         pcsx4all_prof_frames++;
744 #endif
745 #ifdef DEBUG_FRAME
746         if(isdbg_frame())
747         {
748                 static int passed=0;
749                 if (!passed) dbg_enable();
750                 else pcsx4all_exit();
751                 passed++;
752         }
753 #endif
754
755         // Frame skip table
756         static const unsigned char skipTable[12][12] =
757         {
758                 { 0,0,0,0,0,0,0,0,0,0,0,0 },
759                 { 0,0,0,0,0,0,0,0,0,0,0,1 },
760                 { 0,0,0,0,0,1,0,0,0,0,0,1 },
761                 { 0,0,0,1,0,0,0,1,0,0,0,1 },
762                 { 0,0,1,0,0,1,0,0,1,0,0,1 },
763                 { 0,1,0,0,1,0,1,0,0,1,0,1 },
764                 { 0,1,0,1,0,1,0,1,0,1,0,1 },
765                 { 0,1,0,1,1,0,1,0,1,1,0,1 },
766                 { 0,1,1,0,1,1,0,1,1,0,1,1 },
767                 { 0,1,1,1,0,1,1,1,0,1,1,1 },
768                 { 0,1,1,1,1,1,0,1,1,1,1,1 },
769                 { 0,1,1,1,1,1,1,1,1,1,1,1 }
770         };
771         
772         // Interlace bit toggle
773         GPU_GP1 ^= 0x80000000;
774
775         // Update display
776         if ((!skipFrame) && (!isSkip) && (!(((GPU_GP1&0x08000000))||((GPU_GP1&0x00800000)))))
777         {
778                 gpuVideoOutput(); // Display updated
779
780                 if (DisplayArea[3] == 480)
781                 {
782                         if (linesInterlace_user) linesInterlace = 3; // 1/4 of lines
783                         else linesInterlace = 1; // if 480 we only need half of lines
784                 }
785                 else if (linesInterlace != linesInterlace_user)
786                 {
787                         linesInterlace = linesInterlace_user; // resolution changed from 480 to lower one
788                         video_clear();
789                 }
790
791                 // Limit FPS
792                 if (frameLimit)
793                 {
794                         static unsigned next=get_ticks();
795                         unsigned now=get_ticks();
796                         if (!skipFrame)
797                         {
798                                 if (now<next) wait_ticks(next-now);
799                         }
800                         next+=(isPAL?(1000000/50):((unsigned)(1000000.0/59.94)));
801                 }
802         }
803
804         // Show FPS statistics
805         if (show_fps)
806         {
807                 static u32 real_fps=0;
808                 static u32 prev=get_ticks();
809                 static char msg[24]="FPS=000/00 SPD=000%";
810                 u32 now=get_ticks();
811                 real_fps++;
812                 if ((now-prev)>=1000000)
813                 {
814                         u32 expected_fps=(isPAL?50:60);
815                         sprintf(msg,"FPS=%3d/%2d SPD=%3d%%",((real_fps*(12-skipCount))/12),((expected_fps*(12-skipCount))/12),((real_fps*100)/expected_fps));
816                         prev=now;
817                         real_fps=0;
818                 }
819                 port_printf(5,5,msg);
820         }
821
822         // Update frame-skip
823         if (!alt_fps)
824         {
825                 // Video frame-skip
826                 skipFrame=skipTable[skipCount][skCount];
827                 skCount--; if (skCount<0) skCount=11;
828                 isSkip=skipFrame;
829         }
830         else
831         {
832                 // Game frame-skip
833                 if (!isSkip)
834                 {
835                         skipFrame=skipTable[skipCount][skCount];
836                         skCount--; if (skCount<0) skCount=11;
837                         isSkip=true;
838                 }
839         }
840
841         pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_COUNTERS);
842 }
843
844 #else
845
846 #include "../../frontend/plugin_lib.h"
847
848 extern "C" {
849
850 extern void bgr555_to_rgb565(void *dst, void *src, int bytes);
851 extern void bgr888_to_rgb888(void *dst, void *src, int bytes);
852 static const struct rearmed_cbs *cbs;
853 static void *screen_buf;
854
855 static void blit(void)
856 {
857         static s16 old_res_horz, old_res_vert, old_rgb24;
858         s16 isRGB24 = (GPU_GP1 & 0x00200000) ? 1 : 0;
859         s16 h0, x0, y0, w0, h1;
860         u8  *dest = (u8 *)screen_buf;
861         u16 *srcs;
862
863         x0 = DisplayArea[0] & ~3; // alignment needed by blitter
864         y0 = DisplayArea[1];
865         srcs = &((u16*)GPU_FrameBuffer)[FRAME_OFFSET(x0,y0)];
866
867         w0 = DisplayArea[2];
868         h0 = DisplayArea[3];  // video mode
869
870         h1 = DisplayArea[5] - DisplayArea[4]; // display needed
871         if (h0 == 480) h1 = Min2(h1*2,480);
872
873         if (w0 != old_res_horz || h1 != old_res_vert || isRGB24 != old_rgb24)
874         {
875                 old_res_horz = w0;
876                 old_res_vert = h1;
877                 old_rgb24 = (s16)isRGB24;
878                 cbs->pl_fbdev_set_mode(w0, h1, isRGB24 ? 24 : 16);
879         }
880
881         if (isRGB24)
882         {
883                 for (; h1-- > 0; dest += w0 * 3, srcs += 1024)
884                 {
885                         bgr888_to_rgb888(dest, srcs, w0 * 3);
886                 }
887         }
888         else
889         {
890                 for (; h1-- > 0; dest += w0 * 2, srcs += 1024)
891                 {
892                         bgr555_to_rgb565(dest, srcs, w0 * 2);
893                 }
894         }
895
896         screen_buf = cbs->pl_fbdev_flip();
897 }
898
899 void GPU_updateLace(void)
900 {
901         // Interlace bit toggle
902         GPU_GP1 ^= 0x80000000;
903
904         if (!((GPU_GP1&0x08000000) || (GPU_GP1&0x00800000)))
905                 blit();
906 }
907
908 long GPUopen(unsigned long *, char *, char *)
909 {
910         cbs->pl_fbdev_open();
911         screen_buf = cbs->pl_fbdev_flip();
912         return 0;
913 }
914
915 long GPUclose(void)
916 {
917         cbs->pl_fbdev_close();
918         return 0;
919 }
920
921 long GPUfreeze(unsigned int ulGetFreezeData, GPUFreeze_t* p2)
922 {
923         if (ulGetFreezeData > 1)
924                 return 0;
925
926         return GPU_freeze(ulGetFreezeData, p2);
927 }
928
929 void GPUrearmedCallbacks(const struct rearmed_cbs *cbs_)
930 {
931         cbs = cbs_;
932 }
933
934 } /* extern "C" */
935
936 #endif