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