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