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