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