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