drc: invalidate RAM mirrors correctly
[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));
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);
86aad47b 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);
ad6b70be 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);
86aad47b 201 return (1);
202 }
203 return (0);
204}
205
206///////////////////////////////////////////////////////////////////////////////
207// GPU DMA comunication
208
209///////////////////////////////////////////////////////////////////////////////
210u8 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///////////////////////////////////////////////////////////////////////////////
231INLINE void gpuSendPacket()
232{
233#ifdef DEBUG_ANALYSIS
234 dbg_anacnt_GPU_sendPacket++;
235#endif
236 gpuSendPacketFunction(PacketBuffer.U4[0]>>24);
237}
238
239///////////////////////////////////////////////////////////////////////////////
240INLINE 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///////////////////////////////////////////////////////////////////////////////
257void 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;
e7267688 312 fb_dirty = true;
86aad47b 313 pcsx4all_prof_end_with_resume(PCSX4ALL_PROF_GPU,PCSX4ALL_PROF_HW_WRITE);
314 pcsx4all_prof_resume(PCSX4ALL_PROF_CPU);
315}
316
317u32 *lUsedAddr[3];
318INLINE 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///////////////////////////////////////////////////////////////////////////////
330void 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///////////////////////////////////////////////////////////////////////////////
360void 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;
e7267688 405 fb_dirty = true;
86aad47b 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///////////////////////////////////////////////////////////////////////////////
413void 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///////////////////////////////////////////////////////////////////////////////
461u32 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///////////////////////////////////////////////////////////////////////////////
506u32 GPU_readStatus(void)
507{
508#ifdef DEBUG_ANALYSIS
509 dbg_anacnt_GPU_readStatus++;
510#endif
511 return GPU_GP1;
512}
513
514///////////////////////////////////////////////////////////////////////////////
515void 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);
e7267688 545 fb_dirty = true;
86aad47b 546 break;
547 case 0x07:
548 DisplayArea[4] = data & 0x000003FF; //(short)(data & 0x3ff);
549 DisplayArea[5] = (data & 0x000FFC00) >> 10; //(short)((data>>10) & 0x3ff);
e7267688 550 fb_dirty = true;
86aad47b 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 }
e7267688 561 fb_dirty = true;
86aad47b 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
7c49c8a2 589#ifndef REARMED
590
86aad47b 591// Blitting functions
592#include "gpu_blit.h"
593
594INLINE 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///////////////////////////////////////////////////////////////////////////////
749void 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}
7c49c8a2 859
860#else
861
862#include "../../frontend/plugin_lib.h"
863
864extern "C" {
865
866extern void bgr555_to_rgb565(void *dst, void *src, int bytes);
867extern void bgr888_to_rgb888(void *dst, void *src, int bytes);
868static const struct rearmed_cbs *cbs;
869static void *screen_buf;
870
871static 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;
7c49c8a2 876 u16 *srcs;
297b3d63 877 u8 *dest;
7c49c8a2 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
297b3d63 889 if (h1 <= 0)
890 return;
891
7c49c8a2 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;
297b3d63 897 screen_buf = cbs->pl_fbdev_set_mode(w0, h1, isRGB24 ? 24 : 16);
7c49c8a2 898 }
297b3d63 899 dest = (u8 *)screen_buf;
7c49c8a2 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
919void GPU_updateLace(void)
920{
921 // Interlace bit toggle
922 GPU_GP1 ^= 0x80000000;
923
e7267688 924 if (!fb_dirty || (GPU_GP1&0x08800000))
925 return;
926
78d78c3b 927 if (!isSkip) {
928 blit();
929
930 fb_dirty = false;
931 if (*cbs->fskip_option)
932 isSkip = true;
933 }
934 else
935 isSkip = false;
7c49c8a2 936}
937
938long GPUopen(unsigned long *, char *, char *)
939{
940 cbs->pl_fbdev_open();
941 screen_buf = cbs->pl_fbdev_flip();
942 return 0;
943}
944
945long GPUclose(void)
946{
947 cbs->pl_fbdev_close();
948 return 0;
949}
950
951long GPUfreeze(unsigned int ulGetFreezeData, GPUFreeze_t* p2)
952{
953 if (ulGetFreezeData > 1)
954 return 0;
955
956 return GPU_freeze(ulGetFreezeData, p2);
957}
958
959void GPUrearmedCallbacks(const struct rearmed_cbs *cbs_)
960{
961 cbs = cbs_;
962}
963
964} /* extern "C" */
965
966#endif