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