cdrom: change pause timing again
[pcsx_rearmed.git] / plugins / dfxvideo / gpu.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 gpu.c - description
3 -------------------
4 begin : Sun Oct 28 2001
5 copyright : (C) 2001 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. See also the license.txt file for *
14 * additional informations. *
15 * *
16 ***************************************************************************/
17
ef79bbde 18#include "gpu.h"
ef79bbde
P
19#include "stdint.h"
20#include "psemu_plugin_defs.h"
ef79bbde
P
21
22////////////////////////////////////////////////////////////////////////
23// memory image of the PSX vram
24////////////////////////////////////////////////////////////////////////
25
ef79bbde 26unsigned char *psxVub;
ef79bbde
P
27unsigned short *psxVuw;
28unsigned short *psxVuw_eom;
ef79bbde
P
29
30////////////////////////////////////////////////////////////////////////
31// GPU globals
32////////////////////////////////////////////////////////////////////////
33
34static long lGPUdataRet;
35long lGPUstatusRet;
a96a5eb2 36uint32_t ulStatusControl[256];
ef79bbde
P
37
38static uint32_t gpuDataM[256];
39static unsigned char gpuCommand = 0;
40static long gpuDataC = 0;
41static long gpuDataP = 0;
42
43VRAMLoad_t VRAMWrite;
44VRAMLoad_t VRAMRead;
45DATAREGISTERMODES DataWriteMode;
46DATAREGISTERMODES DataReadMode;
47
48BOOL bSkipNextFrame = FALSE;
79f58413 49BOOL fskip_frameReady;
50DWORD lace_count_since_flip;
ef79bbde 51DWORD dwLaceCnt=0;
ef79bbde
P
52short sDispWidths[8] = {256,320,512,640,368,384,512,640};
53PSXDisplay_t PSXDisplay;
54PSXDisplay_t PreviousPSXDisplay;
55long lSelectedSlot=0;
ef79bbde
P
56BOOL bDoLazyUpdate=FALSE;
57uint32_t lGPUInfoVals[16];
58static int iFakePrimBusy=0;
e64dc4c5 59static const int *skip_advice;
ef79bbde
P
60
61////////////////////////////////////////////////////////////////////////
62// some misc external display funcs
63////////////////////////////////////////////////////////////////////////
64
65#include <time.h>
ef79bbde 66
a96a5eb2 67// FPS library
68#include "fps.c"
ef79bbde 69
ef79bbde
P
70
71////////////////////////////////////////////////////////////////////////
a96a5eb2 72// sets all kind of act fixes
ef79bbde
P
73////////////////////////////////////////////////////////////////////////
74
a96a5eb2 75static void SetFixes(void)
76 {
77 if(dwActFixes&0x02) sDispWidths[4]=384;
78 else sDispWidths[4]=368;
79 }
ef79bbde
P
80
81////////////////////////////////////////////////////////////////////////
82// INIT, will be called after lib load... well, just do some var init...
83////////////////////////////////////////////////////////////////////////
84
55b0eeea 85// one extra MB for soft drawing funcs security
86static unsigned char vram[1024*512*2 + 1024*1024] __attribute__((aligned(2048)));
87
a96a5eb2 88long CALLBACK GPUinit(void) // GPU INIT
ef79bbde
P
89{
90 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
91
ef79bbde 92 //!!! ATTENTION !!!
55b0eeea 93 psxVub=vram + 512 * 1024; // security offset into double sized psx vram!
ef79bbde 94
ef79bbde 95 psxVuw=(unsigned short *)psxVub;
a96a5eb2 96 psxVuw_eom=psxVuw+1024*512; // pre-calc of end of vram
ef79bbde 97
55b0eeea 98 memset(vram,0x00,(512*2)*1024 + (1024*1024));
ef79bbde
P
99 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
100
ef79bbde
P
101 PSXDisplay.RGB24 = FALSE; // init some stuff
102 PSXDisplay.Interlaced = FALSE;
103 PSXDisplay.DrawOffset.x = 0;
104 PSXDisplay.DrawOffset.y = 0;
105 PSXDisplay.DisplayMode.x= 320;
106 PSXDisplay.DisplayMode.y= 240;
107 PreviousPSXDisplay.DisplayMode.x= 320;
108 PreviousPSXDisplay.DisplayMode.y= 240;
109 PSXDisplay.Disabled = FALSE;
110 PreviousPSXDisplay.Range.x0 =0;
111 PreviousPSXDisplay.Range.y0 =0;
112 PSXDisplay.Range.x0=0;
113 PSXDisplay.Range.x1=0;
114 PreviousPSXDisplay.DisplayModeNew.y=0;
115 PSXDisplay.Double = 1;
116 lGPUdataRet = 0x400;
117
118 DataWriteMode = DR_NORMAL;
119
120 // Reset transfer values, to prevent mis-transfer of data
121 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
122 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
123
124 // device initialised already !
125 lGPUstatusRet = 0x14802000;
126 GPUIsIdle;
127 GPUIsReadyForCommands;
128 bDoVSyncUpdate = TRUE;
129
130 return 0;
131}
132
133////////////////////////////////////////////////////////////////////////
134// Here starts all...
135////////////////////////////////////////////////////////////////////////
136
137
138long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
139{
140 unsigned long d;
a96a5eb2 141
142 SetFixes();
ef79bbde
P
143
144 InitFPS();
145
ef79bbde
P
146 bDoVSyncUpdate = TRUE;
147
148 d=ulInitDisplay(); // setup x
149
150 if(disp)
151 *disp=d; // wanna x pointer? ok
152
153 if(d) return 0;
154 return -1;
155}
156
157
158////////////////////////////////////////////////////////////////////////
159// time to leave...
160////////////////////////////////////////////////////////////////////////
161
162long CALLBACK GPUclose() // GPU CLOSE
163{
ef79bbde
P
164 CloseDisplay(); // shutdown direct draw
165
166 return 0;
167}
168
169////////////////////////////////////////////////////////////////////////
170// I shot the sheriff
171////////////////////////////////////////////////////////////////////////
172
a96a5eb2 173long CALLBACK GPUshutdown(void) // GPU SHUTDOWN
ef79bbde 174{
a96a5eb2 175 CloseDisplay(); // shutdown direct draw
ef79bbde
P
176 return 0; // nothinh to do
177}
178
179////////////////////////////////////////////////////////////////////////
180// Update display (swap buffers)
181////////////////////////////////////////////////////////////////////////
182
a96a5eb2 183static void updateDisplay(void) // UPDATE DISPLAY
ef79bbde
P
184{
185 if(PSXDisplay.Disabled) // disable?
186 {
ef79bbde
P
187 return; // -> and bye
188 }
189
190 if(dwActFixes&32) // pc fps calculation fix
191 {
192 if(UseFrameLimit) PCFrameCap(); // -> brake
a96a5eb2 193 if(UseFrameSkip) PCcalcfps();
ef79bbde
P
194 }
195
196 if(UseFrameSkip) // skip ?
197 {
79f58413 198 if(fskip_frameReady)
ef79bbde 199 {
79f58413 200 DoBufferSwap(); // -> to skip or not to skip
201 fskip_frameReady=FALSE;
202 bDoVSyncUpdate=FALSE; // vsync done
ef79bbde 203 }
ef79bbde
P
204 }
205 else // no skip ?
206 {
0d8f5b89 207 bSkipNextFrame = FALSE;
ef79bbde 208 DoBufferSwap(); // -> swap
79f58413 209 bDoVSyncUpdate=FALSE; // vsync done
ef79bbde 210 }
79f58413 211}
212
213static void decideSkip(void)
214{
215 if(!bDoVSyncUpdate)
216 return;
217
218 lace_count_since_flip=0;
219 fskip_frameReady=!bSkipNextFrame;
f1bad6e1 220
79f58413 221 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
222 {
ea4a16e7 223 int skip = (skip_advice && *skip_advice) || UseFrameSkip == 1 || fps_skip < fFrameRateHz;
e64dc4c5 224 if(skip && !bSkipNextFrame) // -> skip max one in a row
79f58413 225 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
226 else bSkipNextFrame = FALSE;
227 }
228 else FrameSkip();
ef79bbde
P
229}
230
231////////////////////////////////////////////////////////////////////////
232// roughly emulated screen centering bits... not complete !!!
233////////////////////////////////////////////////////////////////////////
234
235void ChangeDispOffsetsX(void) // X CENTER
236{
237 long lx,l;
238
239 if(!PSXDisplay.Range.x1) return;
240
241 l=PreviousPSXDisplay.DisplayMode.x;
242
243 l*=(long)PSXDisplay.Range.x1;
244 l/=2560;lx=l;l&=0xfffffff8;
245
246 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
247 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
248
249 if(lx>=PreviousPSXDisplay.DisplayMode.x)
250 {
251 PreviousPSXDisplay.Range.x1=
252 (short)PreviousPSXDisplay.DisplayMode.x;
253 PreviousPSXDisplay.Range.x0=0;
254 }
255 else
256 {
257 PreviousPSXDisplay.Range.x1=(short)l;
258
259 PreviousPSXDisplay.Range.x0=
260 (PSXDisplay.Range.x0-500)/8;
261
262 if(PreviousPSXDisplay.Range.x0<0)
263 PreviousPSXDisplay.Range.x0=0;
264
265 if((PreviousPSXDisplay.Range.x0+lx)>
266 PreviousPSXDisplay.DisplayMode.x)
267 {
268 PreviousPSXDisplay.Range.x0=
269 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
270 PreviousPSXDisplay.Range.x0+=2; //???
271
272 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
273
274 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
275
276 }
277
ef79bbde
P
278 // some linux alignment security
279 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
280 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
281 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
282 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
283
ef79bbde
P
284 DoClearScreenBuffer();
285 }
286
287 bDoVSyncUpdate=TRUE;
288}
289
290////////////////////////////////////////////////////////////////////////
291
292void ChangeDispOffsetsY(void) // Y CENTER
293{
294 int iT,iO=PreviousPSXDisplay.Range.y0;
295 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
296
297// new
298
a96a5eb2 299 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>512)
ef79bbde 300 {
a96a5eb2 301 int dy1=512-PreviousPSXDisplay.DisplayModeNew.x;
302 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-512;
ef79bbde
P
303
304 if(dy1>=dy2)
305 {
306 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
307 }
308 else
309 {
310 PSXDisplay.DisplayPosition.y=0;
311 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
312 }
313 }
314 else PreviousPSXDisplay.DisplayModeNew.y=0;
315
316// eon
317
318 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
319 {
320 PSXDisplay.Height = PSXDisplay.Range.y1 -
321 PSXDisplay.Range.y0 +
322 PreviousPSXDisplay.DisplayModeNew.y;
323 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
324 }
325
326//
327
328 if(PSXDisplay.PAL) iT=48; else iT=28;
329
330 if(PSXDisplay.Range.y0>=iT)
331 {
332 PreviousPSXDisplay.Range.y0=
333 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
334 if(PreviousPSXDisplay.Range.y0<0)
335 PreviousPSXDisplay.Range.y0=0;
336 PSXDisplay.DisplayModeNew.y+=
337 PreviousPSXDisplay.Range.y0;
338 }
339 else
340 PreviousPSXDisplay.Range.y0=0;
341
342 if(iO!=PreviousPSXDisplay.Range.y0)
343 {
344 DoClearScreenBuffer();
345 }
346}
347
348////////////////////////////////////////////////////////////////////////
349// check if update needed
350////////////////////////////////////////////////////////////////////////
351
a96a5eb2 352static void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
ef79bbde
P
353{
354 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
355 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
356 {
357 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
358 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
359 }
360
361 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
362
363 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
364 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
365 PreviousPSXDisplay.DisplayMode.x= // previous will hold
366 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
367 PreviousPSXDisplay.DisplayMode.y= // the size of my
368 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
369 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
370
371 PSXDisplay.DisplayEnd.x= // calc end of display
372 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
373 PSXDisplay.DisplayEnd.y=
374 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
375 PreviousPSXDisplay.DisplayEnd.x=
376 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
377 PreviousPSXDisplay.DisplayEnd.y=
378 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
379
380 ChangeDispOffsetsX();
381
382 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
383
79f58413 384 if(UseFrameSkip) decideSkip(); // stupid stuff when frame skipping enabled
ef79bbde
P
385}
386
ef79bbde
P
387////////////////////////////////////////////////////////////////////////
388// update lace is called evry VSync
389////////////////////////////////////////////////////////////////////////
390
391void CALLBACK GPUupdateLace(void) // VSYNC
392{
2588a938 393 //if(!(dwActFixes&1))
394 // lGPUstatusRet^=0x80000000; // odd/even bit
ef79bbde 395
dc40e780 396 //pcsx-rearmed: removed, this is handled by core
72228559 397 //if(!(dwActFixes&32)) // std fps limitation?
398 // CheckFrameRate();
ef79bbde
P
399
400 if(PSXDisplay.Interlaced) // interlaced mode?
401 {
2588a938 402 lGPUstatusRet^=0x80000000; // odd/even bit?
403
ef79bbde
P
404 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
405 {
406 updateDisplay();
407 }
408 }
409 else // non-interlaced?
410 {
411 if(dwActFixes&64) // lazy screen update fix
412 {
79f58413 413 if(bDoLazyUpdate)
ef79bbde
P
414 updateDisplay();
415 bDoLazyUpdate=FALSE;
416 }
417 else
418 {
79f58413 419 if(bDoVSyncUpdate) // some primitives drawn?
f1bad6e1 420 updateDisplay(); // -> update display
ef79bbde
P
421 }
422 }
f1bad6e1 423
79f58413 424 if(UseFrameSkip) { // frame over-skip guard
425 lace_count_since_flip++;
426 if(lace_count_since_flip > 8) {
427 bSkipNextFrame=FALSE;
428 fskip_frameReady=TRUE;
429 }
430 }
ef79bbde
P
431}
432
433////////////////////////////////////////////////////////////////////////
434// process read request from GPU status register
435////////////////////////////////////////////////////////////////////////
436
437
438uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
439{
440 if(dwActFixes&1)
441 {
442 static int iNumRead=0; // odd/even hack
443 if((iNumRead++)==2)
444 {
445 iNumRead=0;
446 lGPUstatusRet^=0x80000000; // interlaced bit toggle... we do it on every 3 read status... needed by some games (like ChronoCross) with old epsxe versions (1.5.2 and older)
447 }
448 }
449
450 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
451 {
452 iFakePrimBusy--;
453
454 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
455 {
456 GPUIsBusy;
457 GPUIsNotReadyForCommands;
458 }
459 else
460 {
461 GPUIsIdle;
462 GPUIsReadyForCommands;
463 }
464 }
24de2dd4 465 return lGPUstatusRet;
ef79bbde
P
466}
467
468////////////////////////////////////////////////////////////////////////
469// processes data send to GPU status register
470// these are always single packet commands.
471////////////////////////////////////////////////////////////////////////
472
473void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
474{
475 uint32_t lCommand=(gdata>>24)&0xff;
476
477 ulStatusControl[lCommand]=gdata; // store command for freezing
478
479 switch(lCommand)
480 {
481 //--------------------------------------------------//
482 // reset gpu
483 case 0x00:
484 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
485 lGPUstatusRet=0x14802000;
486 PSXDisplay.Disabled=1;
487 DataWriteMode=DataReadMode=DR_NORMAL;
488 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
489 drawX=drawY=0;drawW=drawH=0;
490 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
491 usMirror=0;
492 GlobalTextAddrX=0;GlobalTextAddrY=0;
493 GlobalTextTP=0;GlobalTextABR=0;
494 PSXDisplay.RGB24=FALSE;
495 PSXDisplay.Interlaced=FALSE;
496 bUsingTWin = FALSE;
497 return;
498 //--------------------------------------------------//
499 // dis/enable display
500 case 0x03:
501
502 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
503 PSXDisplay.Disabled = (gdata & 1);
504
505 if(PSXDisplay.Disabled)
506 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
507 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
508 return;
509
510 //--------------------------------------------------//
511 // setting transfer mode
512 case 0x04:
513 gdata &= 0x03; // Only want the lower two bits
514
515 DataWriteMode=DataReadMode=DR_NORMAL;
516 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
517 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
518 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
519 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
520
521 return;
522 //--------------------------------------------------//
523 // setting display position
524 case 0x05:
525 {
526 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
527 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
528
ef79bbde 529// new
a96a5eb2 530 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
ef79bbde
P
531
532 // store the same val in some helper var, we need it on later compares
533 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
534
a96a5eb2 535 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>512)
ef79bbde 536 {
a96a5eb2 537 int dy1=512-PSXDisplay.DisplayPosition.y;
538 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-512;
ef79bbde
P
539
540 if(dy1>=dy2)
541 {
542 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
543 }
544 else
545 {
546 PSXDisplay.DisplayPosition.y=0;
547 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
548 }
549 }
550 else PreviousPSXDisplay.DisplayModeNew.y=0;
551// eon
552
553 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
554 PSXDisplay.DisplayEnd.x=
555 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
556 PSXDisplay.DisplayEnd.y=
557 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
558 PreviousPSXDisplay.DisplayEnd.x=
559 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
560 PreviousPSXDisplay.DisplayEnd.y=
561 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
562
563 bDoVSyncUpdate=TRUE;
564
565 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
566 {
ef79bbde
P
567 if(dwActFixes&64) bDoLazyUpdate=TRUE;
568 }
4215cb1f 569 if(UseFrameSkip) decideSkip();
ef79bbde
P
570 }return;
571 //--------------------------------------------------//
572 // setting width
573 case 0x06:
574
575 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
576 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
577
578 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
579
580 ChangeDispOffsetsX();
581
582 return;
583 //--------------------------------------------------//
584 // setting height
585 case 0x07:
586 {
587
588 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
589 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
590
591 PreviousPSXDisplay.Height = PSXDisplay.Height;
592
593 PSXDisplay.Height = PSXDisplay.Range.y1 -
594 PSXDisplay.Range.y0 +
595 PreviousPSXDisplay.DisplayModeNew.y;
596
597 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
598 {
599 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
600
601 ChangeDispOffsetsY();
602
603 updateDisplayIfChanged();
604 }
605 return;
606 }
607 //--------------------------------------------------//
608 // setting display infos
609 case 0x08:
610
611 PSXDisplay.DisplayModeNew.x =
612 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
613
614 if (gdata&0x04) PSXDisplay.Double=2;
615 else PSXDisplay.Double=1;
616
617 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
618
619 ChangeDispOffsetsY();
620
621 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
622 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
623 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
624
625 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
626 lGPUstatusRet|=
627 (((gdata & 0x03) << 17) |
628 ((gdata & 0x40) << 10)); // Set the width bits
629
630 if(PSXDisplay.InterlacedNew)
631 {
632 if(!PSXDisplay.Interlaced)
633 {
634 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
635 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
636 }
637 lGPUstatusRet|=GPUSTATUS_INTERLACED;
638 }
9f21ebfe 639 else lGPUstatusRet&=~(GPUSTATUS_INTERLACED|0x80000000);
ef79bbde
P
640
641 if (PSXDisplay.PAL)
642 lGPUstatusRet|=GPUSTATUS_PAL;
643 else lGPUstatusRet&=~GPUSTATUS_PAL;
644
645 if (PSXDisplay.Double==2)
646 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
647 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
648
649 if (PSXDisplay.RGB24New)
650 lGPUstatusRet|=GPUSTATUS_RGB24;
651 else lGPUstatusRet&=~GPUSTATUS_RGB24;
652
653 updateDisplayIfChanged();
654
655 return;
656 //--------------------------------------------------//
657 // ask about GPU version and other stuff
658 case 0x10:
659
660 gdata&=0xff;
661
662 switch(gdata)
663 {
664 case 0x02:
665 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
666 return;
667 case 0x03:
668 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
669 return;
670 case 0x04:
671 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
672 return;
673 case 0x05:
674 case 0x06:
675 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
676 return;
677 case 0x07:
a96a5eb2 678 lGPUdataRet=0x02; // gpu type
ef79bbde
P
679 return;
680 case 0x08:
681 case 0x0F: // some bios addr?
682 lGPUdataRet=0xBFC03720;
683 return;
684 }
685 return;
686 //--------------------------------------------------//
687 }
688}
689
690////////////////////////////////////////////////////////////////////////
691// vram read/write helpers, needed by LEWPY's optimized vram read/write :)
692////////////////////////////////////////////////////////////////////////
693
a96a5eb2 694static inline void FinishedVRAMWrite(void)
ef79bbde 695{
ef79bbde
P
696 // Set register to NORMAL operation
697 DataWriteMode = DR_NORMAL;
698 // Reset transfer values, to prevent mis-transfer of data
699 VRAMWrite.x = 0;
700 VRAMWrite.y = 0;
701 VRAMWrite.Width = 0;
702 VRAMWrite.Height = 0;
703 VRAMWrite.ColsRemaining = 0;
704 VRAMWrite.RowsRemaining = 0;
705}
706
a96a5eb2 707static inline void FinishedVRAMRead(void)
ef79bbde
P
708{
709 // Set register to NORMAL operation
710 DataReadMode = DR_NORMAL;
711 // Reset transfer values, to prevent mis-transfer of data
712 VRAMRead.x = 0;
713 VRAMRead.y = 0;
714 VRAMRead.Width = 0;
715 VRAMRead.Height = 0;
716 VRAMRead.ColsRemaining = 0;
717 VRAMRead.RowsRemaining = 0;
718
719 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
720 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
721}
722
723////////////////////////////////////////////////////////////////////////
724// core read from vram
725////////////////////////////////////////////////////////////////////////
726
727void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
728{
729 int i;
730
731 if(DataReadMode!=DR_VRAMTRANSFER) return;
732
733 GPUIsBusy;
734
735 // adjust read ptr, if necessary
736 while(VRAMRead.ImagePtr>=psxVuw_eom)
a96a5eb2 737 VRAMRead.ImagePtr-=512*1024;
ef79bbde 738 while(VRAMRead.ImagePtr<psxVuw)
a96a5eb2 739 VRAMRead.ImagePtr+=512*1024;
ef79bbde
P
740
741 for(i=0;i<iSize;i++)
742 {
743 // do 2 seperate 16bit reads for compatibility (wrap issues)
744 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
745 {
746 // lower 16 bit
747 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
748
749 VRAMRead.ImagePtr++;
a96a5eb2 750 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
751 VRAMRead.RowsRemaining --;
752
753 if(VRAMRead.RowsRemaining<=0)
754 {
755 VRAMRead.RowsRemaining = VRAMRead.Width;
756 VRAMRead.ColsRemaining--;
757 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
a96a5eb2 758 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
759 }
760
761 // higher 16 bit (always, even if it's an odd width)
762 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
763 PUTLE32(pMem, lGPUdataRet); pMem++;
764
765 if(VRAMRead.ColsRemaining <= 0)
766 {FinishedVRAMRead();goto ENDREAD;}
767
768 VRAMRead.ImagePtr++;
a96a5eb2 769 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
770 VRAMRead.RowsRemaining--;
771 if(VRAMRead.RowsRemaining<=0)
772 {
773 VRAMRead.RowsRemaining = VRAMRead.Width;
774 VRAMRead.ColsRemaining--;
775 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
a96a5eb2 776 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
777 }
778 if(VRAMRead.ColsRemaining <= 0)
779 {FinishedVRAMRead();goto ENDREAD;}
780 }
781 else {FinishedVRAMRead();goto ENDREAD;}
782 }
783
784ENDREAD:
785 GPUIsIdle;
786}
787
788
789////////////////////////////////////////////////////////////////////////
790
791uint32_t CALLBACK GPUreadData(void)
792{
793 uint32_t l;
794 GPUreadDataMem(&l,1);
795 return lGPUdataRet;
796}
797
a96a5eb2 798// Software drawing function
799#include "soft.c"
800
801// PSX drawing primitives
802#include "prim.c"
803
ef79bbde
P
804////////////////////////////////////////////////////////////////////////
805// processes data send to GPU data register
806// extra table entries for fixing polyline troubles
807////////////////////////////////////////////////////////////////////////
808
a96a5eb2 809static const unsigned char primTableCX[256] =
ef79bbde
P
810{
811 // 00
812 0,0,3,0,0,0,0,0,
813 // 08
814 0,0,0,0,0,0,0,0,
815 // 10
816 0,0,0,0,0,0,0,0,
817 // 18
818 0,0,0,0,0,0,0,0,
819 // 20
820 4,4,4,4,7,7,7,7,
821 // 28
822 5,5,5,5,9,9,9,9,
823 // 30
824 6,6,6,6,9,9,9,9,
825 // 38
826 8,8,8,8,12,12,12,12,
827 // 40
828 3,3,3,3,0,0,0,0,
829 // 48
830// 5,5,5,5,6,6,6,6, // FLINE
831 254,254,254,254,254,254,254,254,
832 // 50
833 4,4,4,4,0,0,0,0,
834 // 58
835// 7,7,7,7,9,9,9,9, // GLINE
836 255,255,255,255,255,255,255,255,
837 // 60
838 3,3,3,3,4,4,4,4,
839 // 68
840 2,2,2,2,3,3,3,3, // 3=SPRITE1???
841 // 70
842 2,2,2,2,3,3,3,3,
843 // 78
844 2,2,2,2,3,3,3,3,
845 // 80
846 4,0,0,0,0,0,0,0,
847 // 88
848 0,0,0,0,0,0,0,0,
849 // 90
850 0,0,0,0,0,0,0,0,
851 // 98
852 0,0,0,0,0,0,0,0,
853 // a0
854 3,0,0,0,0,0,0,0,
855 // a8
856 0,0,0,0,0,0,0,0,
857 // b0
858 0,0,0,0,0,0,0,0,
859 // b8
860 0,0,0,0,0,0,0,0,
861 // c0
862 3,0,0,0,0,0,0,0,
863 // c8
864 0,0,0,0,0,0,0,0,
865 // d0
866 0,0,0,0,0,0,0,0,
867 // d8
868 0,0,0,0,0,0,0,0,
869 // e0
870 0,1,1,1,1,1,1,0,
871 // e8
872 0,0,0,0,0,0,0,0,
873 // f0
874 0,0,0,0,0,0,0,0,
875 // f8
876 0,0,0,0,0,0,0,0
877};
878
879void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
880{
881 unsigned char command;
882 uint32_t gdata=0;
883 int i=0;
884 GPUIsBusy;
885 GPUIsNotReadyForCommands;
886
887STARTVRAM:
888
889 if(DataWriteMode==DR_VRAMTRANSFER)
890 {
891 BOOL bFinished=FALSE;
892
893 // make sure we are in vram
894 while(VRAMWrite.ImagePtr>=psxVuw_eom)
a96a5eb2 895 VRAMWrite.ImagePtr-=512*1024;
ef79bbde 896 while(VRAMWrite.ImagePtr<psxVuw)
a96a5eb2 897 VRAMWrite.ImagePtr+=512*1024;
ef79bbde
P
898
899 // now do the loop
900 while(VRAMWrite.ColsRemaining>0)
901 {
902 while(VRAMWrite.RowsRemaining>0)
903 {
904 if(i>=iSize) {goto ENDVRAM;}
905 i++;
906
907 gdata=GETLE32(pMem); pMem++;
908
909 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
a96a5eb2 910 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
ef79bbde
P
911 VRAMWrite.RowsRemaining --;
912
913 if(VRAMWrite.RowsRemaining <= 0)
914 {
915 VRAMWrite.ColsRemaining--;
916 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
917 {
918 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
919 FinishedVRAMWrite();
920 bDoVSyncUpdate=TRUE;
921 goto ENDVRAM;
922 }
923 VRAMWrite.RowsRemaining = VRAMWrite.Width;
924 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
925 }
926
927 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
a96a5eb2 928 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
ef79bbde
P
929 VRAMWrite.RowsRemaining --;
930 }
931
932 VRAMWrite.RowsRemaining = VRAMWrite.Width;
933 VRAMWrite.ColsRemaining--;
934 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
935 bFinished=TRUE;
936 }
937
938 FinishedVRAMWrite();
939 if(bFinished) bDoVSyncUpdate=TRUE;
940 }
941
942ENDVRAM:
943
944 if(DataWriteMode==DR_NORMAL)
945 {
946 void (* *primFunc)(unsigned char *);
947 if(bSkipNextFrame) primFunc=primTableSkip;
948 else primFunc=primTableJ;
949
950 for(;i<iSize;)
951 {
952 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
953
954 gdata=GETLE32(pMem); pMem++; i++;
955
956 if(gpuDataC == 0)
957 {
958 command = (unsigned char)((gdata>>24) & 0xff);
959
960//if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
961
962 if(primTableCX[command])
963 {
964 gpuDataC = primTableCX[command];
965 gpuCommand = command;
0d16cda2 966 PUTLE32_(&gpuDataM[0], gdata);
ef79bbde
P
967 gpuDataP = 1;
968 }
969 else continue;
970 }
971 else
972 {
0d16cda2 973 PUTLE32_(&gpuDataM[gpuDataP], gdata);
ef79bbde
P
974 if(gpuDataC>128)
975 {
976 if((gpuDataC==254 && gpuDataP>=3) ||
977 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
978 {
ae097dfb 979 if((gpuDataM[gpuDataP] & HOST2LE32(0xF000F000)) == HOST2LE32(0x50005000))
ef79bbde
P
980 gpuDataP=gpuDataC-1;
981 }
982 }
983 gpuDataP++;
984 }
985
986 if(gpuDataP == gpuDataC)
987 {
988 gpuDataC=gpuDataP=0;
989 primFunc[gpuCommand]((unsigned char *)gpuDataM);
a96a5eb2 990 if(dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
991 iFakePrimBusy=4;
992 }
ef79bbde
P
993 }
994 }
995
996 lGPUdataRet=gdata;
997
998 GPUIsReadyForCommands;
999 GPUIsIdle;
1000}
1001
1002////////////////////////////////////////////////////////////////////////
1003
1004void CALLBACK GPUwriteData(uint32_t gdata)
1005{
0d16cda2 1006 PUTLE32_(&gdata, gdata);
ef79bbde
P
1007 GPUwriteDataMem(&gdata,1);
1008}
1009
ef79bbde
P
1010////////////////////////////////////////////////////////////////////////
1011// process gpu commands
1012////////////////////////////////////////////////////////////////////////
1013
1014unsigned long lUsedAddr[3];
1015
a96a5eb2 1016static inline BOOL CheckForEndlessLoop(unsigned long laddr)
ef79bbde
P
1017{
1018 if(laddr==lUsedAddr[1]) return TRUE;
1019 if(laddr==lUsedAddr[2]) return TRUE;
1020
1021 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1022 else lUsedAddr[2]=laddr;
1023 lUsedAddr[0]=laddr;
1024 return FALSE;
1025}
1026
1027long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1028{
1029 uint32_t dmaMem;
1030 unsigned char * baseAddrB;
1031 short count;unsigned int DMACommandCounter = 0;
b03e0caf 1032 long dmaWords = 0;
ef79bbde
P
1033
1034 GPUIsBusy;
1035
1036 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1037
1038 baseAddrB = (unsigned char*) baseAddrL;
1039
1040 do
1041 {
a96a5eb2 1042 addr&=0x1FFFFC;
ef79bbde
P
1043 if(DMACommandCounter++ > 2000000) break;
1044 if(CheckForEndlessLoop(addr)) break;
1045
1046 count = baseAddrB[addr+3];
b03e0caf 1047 dmaWords += 1 + count;
ef79bbde
P
1048
1049 dmaMem=addr+4;
1050
1051 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1052
1053 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
502ea36e 1054 } while (!(addr & 0x800000)); // contrary to some documentation, the end-of-linked-list marker is not actually 0xFF'FFFF
1055 // any pointer with bit 23 set will do.
ef79bbde
P
1056
1057 GPUIsIdle;
1058
b03e0caf 1059 return dmaWords;
ef79bbde
P
1060}
1061
ef79bbde
P
1062////////////////////////////////////////////////////////////////////////
1063// Freeze
1064////////////////////////////////////////////////////////////////////////
1065
1066typedef struct GPUFREEZETAG
1067{
1068 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1069 uint32_t ulStatus; // current gpu status
1070 uint32_t ulControl[256]; // latest control register values
1071 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1072} GPUFreeze_t;
1073
1074////////////////////////////////////////////////////////////////////////
1075
1076long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1077{
1078 //----------------------------------------------------//
1079 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1080 {
1081 long lSlotNum=*((long *)pF);
1082 if(lSlotNum<0) return 0;
1083 if(lSlotNum>8) return 0;
1084 lSelectedSlot=lSlotNum+1;
ef79bbde
P
1085 return 1;
1086 }
1087 //----------------------------------------------------//
1088 if(!pF) return 0; // some checks
1089 if(pF->ulFreezeVersion!=1) return 0;
1090
1091 if(ulGetFreezeData==1) // 1: get data
1092 {
1093 pF->ulStatus=lGPUstatusRet;
1094 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
a96a5eb2 1095 memcpy(pF->psxVRam, psxVub, 1024*512*2);
ef79bbde
P
1096
1097 return 1;
1098 }
1099
1100 if(ulGetFreezeData!=0) return 0; // 0: set data
1101
1102 lGPUstatusRet=pF->ulStatus;
1103 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
a96a5eb2 1104 memcpy(psxVub, pF->psxVRam, 1024*512*2);
ef79bbde
P
1105
1106// RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1107
321ca84d 1108 PreviousPSXDisplay.Height = 0;
ef79bbde
P
1109 GPUwriteStatus(ulStatusControl[0]);
1110 GPUwriteStatus(ulStatusControl[1]);
1111 GPUwriteStatus(ulStatusControl[2]);
1112 GPUwriteStatus(ulStatusControl[3]);
1113 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1114 GPUwriteStatus(ulStatusControl[6]);
1115 GPUwriteStatus(ulStatusControl[7]);
1116 GPUwriteStatus(ulStatusControl[5]);
1117 GPUwriteStatus(ulStatusControl[4]);
1118
1119 return 1;
1120}
2588a938 1121
e64dc4c5 1122// rearmed thing
1123#include "../../frontend/plugin_lib.h"
1124
76f7048e 1125const struct rearmed_cbs *rcbs;
1126
e64dc4c5 1127void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
1128{
1129 // sync config
1130 UseFrameSkip = cbs->frameskip;
1131 iUseDither = cbs->gpu_peops.iUseDither;
1132 dwActFixes = cbs->gpu_peops.dwActFixes;
1133 fFrameRateHz = cbs->gpu_peops.fFrameRateHz;
1134 dwFrameRateTicks = cbs->gpu_peops.dwFrameRateTicks;
55b0eeea 1135 if (cbs->pl_vout_set_raw_vram)
1136 cbs->pl_vout_set_raw_vram(psxVub);
fa56d360 1137 if (cbs->pl_set_gpu_caps)
1138 cbs->pl_set_gpu_caps(0);
e64dc4c5 1139
1140 skip_advice = &cbs->fskip_advice;
1141 fps_skip = 100.0f;
76f7048e 1142 rcbs = cbs;
e64dc4c5 1143}