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