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