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