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