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