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