1 /***************************************************************************
4 begin : Sun Oct 28 2001
5 copyright : (C) 2001 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8 /***************************************************************************
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. *
16 ***************************************************************************/
20 #include "psemu_plugin_defs.h"
22 ////////////////////////////////////////////////////////////////////////
23 // memory image of the PSX vram
24 ////////////////////////////////////////////////////////////////////////
26 unsigned char *psxVSecure;
27 unsigned char *psxVub;
29 unsigned short *psxVuw;
30 unsigned short *psxVuw_eom;
35 ////////////////////////////////////////////////////////////////////////
37 ////////////////////////////////////////////////////////////////////////
39 static long lGPUdataRet;
41 uint32_t ulStatusControl[256];
43 static uint32_t gpuDataM[256];
44 static unsigned char gpuCommand = 0;
45 static long gpuDataC = 0;
46 static long gpuDataP = 0;
50 DATAREGISTERMODES DataWriteMode;
51 DATAREGISTERMODES DataReadMode;
53 BOOL bSkipNextFrame = FALSE;
54 BOOL fskip_frameReady;
55 DWORD lace_count_since_flip;
57 short sDispWidths[8] = {256,320,512,640,368,384,512,640};
58 PSXDisplay_t PSXDisplay;
59 PSXDisplay_t PreviousPSXDisplay;
61 BOOL bDoLazyUpdate=FALSE;
62 uint32_t lGPUInfoVals[16];
63 static int iFakePrimBusy=0;
64 static uint32_t vBlank=0;
65 static const int *skip_advice;
67 ////////////////////////////////////////////////////////////////////////
68 // some misc external display funcs
69 ////////////////////////////////////////////////////////////////////////
77 ////////////////////////////////////////////////////////////////////////
78 // sets all kind of act fixes
79 ////////////////////////////////////////////////////////////////////////
81 static void SetFixes(void)
83 if(dwActFixes&0x02) sDispWidths[4]=384;
84 else sDispWidths[4]=368;
87 ////////////////////////////////////////////////////////////////////////
88 // INIT, will be called after lib load... well, just do some var init...
89 ////////////////////////////////////////////////////////////////////////
91 long CALLBACK GPUinit(void) // GPU INIT
93 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
95 psxVSecure = (unsigned char *)malloc((512*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
100 psxVub=psxVSecure + 512 * 1024; // security offset into double sized psx vram!
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;
108 psxVuw_eom=psxVuw+1024*512; // pre-calc of end of vram
110 memset(psxVSecure,0x00,(512*2)*1024 + (1024*1024));
111 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
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;
130 DataWriteMode = DR_NORMAL;
132 // Reset transfer values, to prevent mis-transfer of data
133 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
134 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
136 // device initialised already !
137 lGPUstatusRet = 0x14802000;
139 GPUIsReadyForCommands;
140 bDoVSyncUpdate = TRUE;
145 ////////////////////////////////////////////////////////////////////////
146 // Here starts all...
147 ////////////////////////////////////////////////////////////////////////
150 long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
158 bDoVSyncUpdate = TRUE;
160 d=ulInitDisplay(); // setup x
163 *disp=d; // wanna x pointer? ok
170 ////////////////////////////////////////////////////////////////////////
172 ////////////////////////////////////////////////////////////////////////
174 long CALLBACK GPUclose() // GPU CLOSE
176 CloseDisplay(); // shutdown direct draw
181 ////////////////////////////////////////////////////////////////////////
182 // I shot the sheriff
183 ////////////////////////////////////////////////////////////////////////
185 long CALLBACK GPUshutdown(void) // GPU SHUTDOWN
187 CloseDisplay(); // shutdown direct draw
189 return 0; // nothinh to do
192 ////////////////////////////////////////////////////////////////////////
193 // Update display (swap buffers)
194 ////////////////////////////////////////////////////////////////////////
196 static void updateDisplay(void) // UPDATE DISPLAY
198 if(PSXDisplay.Disabled) // disable?
200 return; // -> and bye
203 if(dwActFixes&32) // pc fps calculation fix
205 if(UseFrameLimit) PCFrameCap(); // -> brake
206 if(UseFrameSkip) PCcalcfps();
209 if(UseFrameSkip) // skip ?
213 DoBufferSwap(); // -> to skip or not to skip
214 fskip_frameReady=FALSE;
215 bDoVSyncUpdate=FALSE; // vsync done
220 bSkipNextFrame = FALSE;
221 DoBufferSwap(); // -> swap
222 bDoVSyncUpdate=FALSE; // vsync done
226 static void decideSkip(void)
231 lace_count_since_flip=0;
232 fskip_frameReady=!bSkipNextFrame;
234 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
236 int skip = (skip_advice && *skip_advice) || UseFrameSkip == 1 || fps_skip < fFrameRateHz;
237 if(skip && !bSkipNextFrame) // -> skip max one in a row
238 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
239 else bSkipNextFrame = FALSE;
244 ////////////////////////////////////////////////////////////////////////
245 // roughly emulated screen centering bits... not complete !!!
246 ////////////////////////////////////////////////////////////////////////
248 void ChangeDispOffsetsX(void) // X CENTER
252 if(!PSXDisplay.Range.x1) return;
254 l=PreviousPSXDisplay.DisplayMode.x;
256 l*=(long)PSXDisplay.Range.x1;
257 l/=2560;lx=l;l&=0xfffffff8;
259 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
260 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
262 if(lx>=PreviousPSXDisplay.DisplayMode.x)
264 PreviousPSXDisplay.Range.x1=
265 (short)PreviousPSXDisplay.DisplayMode.x;
266 PreviousPSXDisplay.Range.x0=0;
270 PreviousPSXDisplay.Range.x1=(short)l;
272 PreviousPSXDisplay.Range.x0=
273 (PSXDisplay.Range.x0-500)/8;
275 if(PreviousPSXDisplay.Range.x0<0)
276 PreviousPSXDisplay.Range.x0=0;
278 if((PreviousPSXDisplay.Range.x0+lx)>
279 PreviousPSXDisplay.DisplayMode.x)
281 PreviousPSXDisplay.Range.x0=
282 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
283 PreviousPSXDisplay.Range.x0+=2; //???
285 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
287 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
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;
297 DoClearScreenBuffer();
303 ////////////////////////////////////////////////////////////////////////
305 void ChangeDispOffsetsY(void) // Y CENTER
307 int iT,iO=PreviousPSXDisplay.Range.y0;
308 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
312 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>512)
314 int dy1=512-PreviousPSXDisplay.DisplayModeNew.x;
315 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-512;
319 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
323 PSXDisplay.DisplayPosition.y=0;
324 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
327 else PreviousPSXDisplay.DisplayModeNew.y=0;
331 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
333 PSXDisplay.Height = PSXDisplay.Range.y1 -
334 PSXDisplay.Range.y0 +
335 PreviousPSXDisplay.DisplayModeNew.y;
336 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
341 if(PSXDisplay.PAL) iT=48; else iT=28;
343 if(PSXDisplay.Range.y0>=iT)
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;
353 PreviousPSXDisplay.Range.y0=0;
355 if(iO!=PreviousPSXDisplay.Range.y0)
357 DoClearScreenBuffer();
361 ////////////////////////////////////////////////////////////////////////
362 // check if update needed
363 ////////////////////////////////////////////////////////////////////////
365 static void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
367 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
368 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
370 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
371 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
374 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
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;
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;
393 ChangeDispOffsetsX();
395 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
397 if(UseFrameSkip) decideSkip(); // stupid stuff when frame skipping enabled
400 ////////////////////////////////////////////////////////////////////////
401 // update lace is called evry VSync
402 ////////////////////////////////////////////////////////////////////////
404 void CALLBACK GPUupdateLace(void) // VSYNC
406 //if(!(dwActFixes&1))
407 // lGPUstatusRet^=0x80000000; // odd/even bit
409 //pcsx-rearmed: removed, this is handled by core
410 //if(!(dwActFixes&32)) // std fps limitation?
413 if(PSXDisplay.Interlaced) // interlaced mode?
415 lGPUstatusRet^=0x80000000; // odd/even bit?
417 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
422 else // non-interlaced?
424 if(dwActFixes&64) // lazy screen update fix
432 if(bDoVSyncUpdate) // some primitives drawn?
433 updateDisplay(); // -> update display
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;
446 ////////////////////////////////////////////////////////////////////////
447 // process read request from GPU status register
448 ////////////////////////////////////////////////////////////////////////
451 uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
455 static int iNumRead=0; // odd/even hack
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)
463 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
467 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
470 GPUIsNotReadyForCommands;
475 GPUIsReadyForCommands;
478 return lGPUstatusRet | vBlank;
481 ////////////////////////////////////////////////////////////////////////
482 // processes data send to GPU status register
483 // these are always single packet commands.
484 ////////////////////////////////////////////////////////////////////////
486 void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
488 uint32_t lCommand=(gdata>>24)&0xff;
490 ulStatusControl[lCommand]=gdata; // store command for freezing
494 //--------------------------------------------------//
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;
505 GlobalTextAddrX=0;GlobalTextAddrY=0;
506 GlobalTextTP=0;GlobalTextABR=0;
507 PSXDisplay.RGB24=FALSE;
508 PSXDisplay.Interlaced=FALSE;
511 //--------------------------------------------------//
512 // dis/enable display
515 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
516 PSXDisplay.Disabled = (gdata & 1);
518 if(PSXDisplay.Disabled)
519 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
520 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
523 //--------------------------------------------------//
524 // setting transfer mode
526 gdata &= 0x03; // Only want the lower two bits
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
535 //--------------------------------------------------//
536 // setting display position
539 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
540 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
543 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
545 // store the same val in some helper var, we need it on later compares
546 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
548 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>512)
550 int dy1=512-PSXDisplay.DisplayPosition.y;
551 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-512;
555 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
559 PSXDisplay.DisplayPosition.y=0;
560 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
563 else PreviousPSXDisplay.DisplayModeNew.y=0;
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;
578 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
580 if(dwActFixes&64) bDoLazyUpdate=TRUE;
582 if(UseFrameSkip) decideSkip();
584 //--------------------------------------------------//
588 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
589 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
591 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
593 ChangeDispOffsetsX();
596 //--------------------------------------------------//
601 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
602 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
604 PreviousPSXDisplay.Height = PSXDisplay.Height;
606 PSXDisplay.Height = PSXDisplay.Range.y1 -
607 PSXDisplay.Range.y0 +
608 PreviousPSXDisplay.DisplayModeNew.y;
610 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
612 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
614 ChangeDispOffsetsY();
616 updateDisplayIfChanged();
620 //--------------------------------------------------//
621 // setting display infos
624 PSXDisplay.DisplayModeNew.x =
625 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
627 if (gdata&0x04) PSXDisplay.Double=2;
628 else PSXDisplay.Double=1;
630 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
632 ChangeDispOffsetsY();
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
638 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
640 (((gdata & 0x03) << 17) |
641 ((gdata & 0x40) << 10)); // Set the width bits
643 if(PSXDisplay.InterlacedNew)
645 if(!PSXDisplay.Interlaced)
647 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
648 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
650 lGPUstatusRet|=GPUSTATUS_INTERLACED;
652 else lGPUstatusRet&=~(GPUSTATUS_INTERLACED|0x80000000);
655 lGPUstatusRet|=GPUSTATUS_PAL;
656 else lGPUstatusRet&=~GPUSTATUS_PAL;
658 if (PSXDisplay.Double==2)
659 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
660 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
662 if (PSXDisplay.RGB24New)
663 lGPUstatusRet|=GPUSTATUS_RGB24;
664 else lGPUstatusRet&=~GPUSTATUS_RGB24;
666 updateDisplayIfChanged();
669 //--------------------------------------------------//
670 // ask about GPU version and other stuff
678 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
681 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
684 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
688 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
691 lGPUdataRet=0x02; // gpu type
694 case 0x0F: // some bios addr?
695 lGPUdataRet=0xBFC03720;
699 //--------------------------------------------------//
703 ////////////////////////////////////////////////////////////////////////
704 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
705 ////////////////////////////////////////////////////////////////////////
707 static inline void FinishedVRAMWrite(void)
709 // Set register to NORMAL operation
710 DataWriteMode = DR_NORMAL;
711 // Reset transfer values, to prevent mis-transfer of data
715 VRAMWrite.Height = 0;
716 VRAMWrite.ColsRemaining = 0;
717 VRAMWrite.RowsRemaining = 0;
720 static inline void FinishedVRAMRead(void)
722 // Set register to NORMAL operation
723 DataReadMode = DR_NORMAL;
724 // Reset transfer values, to prevent mis-transfer of data
729 VRAMRead.ColsRemaining = 0;
730 VRAMRead.RowsRemaining = 0;
732 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
733 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
736 ////////////////////////////////////////////////////////////////////////
737 // core read from vram
738 ////////////////////////////////////////////////////////////////////////
740 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
744 if(DataReadMode!=DR_VRAMTRANSFER) return;
748 // adjust read ptr, if necessary
749 while(VRAMRead.ImagePtr>=psxVuw_eom)
750 VRAMRead.ImagePtr-=512*1024;
751 while(VRAMRead.ImagePtr<psxVuw)
752 VRAMRead.ImagePtr+=512*1024;
756 // do 2 seperate 16bit reads for compatibility (wrap issues)
757 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
760 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
763 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
764 VRAMRead.RowsRemaining --;
766 if(VRAMRead.RowsRemaining<=0)
768 VRAMRead.RowsRemaining = VRAMRead.Width;
769 VRAMRead.ColsRemaining--;
770 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
771 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
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++;
778 if(VRAMRead.ColsRemaining <= 0)
779 {FinishedVRAMRead();goto ENDREAD;}
782 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
783 VRAMRead.RowsRemaining--;
784 if(VRAMRead.RowsRemaining<=0)
786 VRAMRead.RowsRemaining = VRAMRead.Width;
787 VRAMRead.ColsRemaining--;
788 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
789 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
791 if(VRAMRead.ColsRemaining <= 0)
792 {FinishedVRAMRead();goto ENDREAD;}
794 else {FinishedVRAMRead();goto ENDREAD;}
802 ////////////////////////////////////////////////////////////////////////
804 uint32_t CALLBACK GPUreadData(void)
807 GPUreadDataMem(&l,1);
811 // Software drawing function
814 // PSX drawing primitives
817 ////////////////////////////////////////////////////////////////////////
818 // processes data send to GPU data register
819 // extra table entries for fixing polyline troubles
820 ////////////////////////////////////////////////////////////////////////
822 static const unsigned char primTableCX[256] =
843 // 5,5,5,5,6,6,6,6, // FLINE
844 254,254,254,254,254,254,254,254,
848 // 7,7,7,7,9,9,9,9, // GLINE
849 255,255,255,255,255,255,255,255,
853 2,2,2,2,3,3,3,3, // 3=SPRITE1???
892 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
894 unsigned char command;
898 GPUIsNotReadyForCommands;
902 if(DataWriteMode==DR_VRAMTRANSFER)
904 BOOL bFinished=FALSE;
906 // make sure we are in vram
907 while(VRAMWrite.ImagePtr>=psxVuw_eom)
908 VRAMWrite.ImagePtr-=512*1024;
909 while(VRAMWrite.ImagePtr<psxVuw)
910 VRAMWrite.ImagePtr+=512*1024;
913 while(VRAMWrite.ColsRemaining>0)
915 while(VRAMWrite.RowsRemaining>0)
917 if(i>=iSize) {goto ENDVRAM;}
920 gdata=GETLE32(pMem); pMem++;
922 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
923 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
924 VRAMWrite.RowsRemaining --;
926 if(VRAMWrite.RowsRemaining <= 0)
928 VRAMWrite.ColsRemaining--;
929 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
931 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
936 VRAMWrite.RowsRemaining = VRAMWrite.Width;
937 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
940 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
941 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
942 VRAMWrite.RowsRemaining --;
945 VRAMWrite.RowsRemaining = VRAMWrite.Width;
946 VRAMWrite.ColsRemaining--;
947 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
952 if(bFinished) bDoVSyncUpdate=TRUE;
957 if(DataWriteMode==DR_NORMAL)
959 void (* *primFunc)(unsigned char *);
960 if(bSkipNextFrame) primFunc=primTableSkip;
961 else primFunc=primTableJ;
965 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
967 gdata=GETLE32(pMem); pMem++; i++;
971 command = (unsigned char)((gdata>>24) & 0xff);
973 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
975 if(primTableCX[command])
977 gpuDataC = primTableCX[command];
978 gpuCommand = command;
979 PUTLE32_(&gpuDataM[0], gdata);
986 PUTLE32_(&gpuDataM[gpuDataP], gdata);
989 if((gpuDataC==254 && gpuDataP>=3) ||
990 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
992 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
999 if(gpuDataP == gpuDataC)
1001 gpuDataC=gpuDataP=0;
1002 primFunc[gpuCommand]((unsigned char *)gpuDataM);
1003 if(dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1011 GPUIsReadyForCommands;
1015 ////////////////////////////////////////////////////////////////////////
1017 void CALLBACK GPUwriteData(uint32_t gdata)
1019 PUTLE32_(&gdata, gdata);
1020 GPUwriteDataMem(&gdata,1);
1023 ////////////////////////////////////////////////////////////////////////
1024 // process gpu commands
1025 ////////////////////////////////////////////////////////////////////////
1027 unsigned long lUsedAddr[3];
1029 static inline BOOL CheckForEndlessLoop(unsigned long laddr)
1031 if(laddr==lUsedAddr[1]) return TRUE;
1032 if(laddr==lUsedAddr[2]) return TRUE;
1034 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1035 else lUsedAddr[2]=laddr;
1040 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1043 unsigned char * baseAddrB;
1044 short count;unsigned int DMACommandCounter = 0;
1049 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1051 baseAddrB = (unsigned char*) baseAddrL;
1056 if(DMACommandCounter++ > 2000000) break;
1057 if(CheckForEndlessLoop(addr)) break;
1059 count = baseAddrB[addr+3];
1060 dmaWords += 1 + count;
1064 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1066 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1068 while (addr != 0xffffff);
1075 ////////////////////////////////////////////////////////////////////////
1077 ////////////////////////////////////////////////////////////////////////
1079 typedef struct GPUFREEZETAG
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)
1087 ////////////////////////////////////////////////////////////////////////
1089 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1091 //----------------------------------------------------//
1092 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1094 long lSlotNum=*((long *)pF);
1095 if(lSlotNum<0) return 0;
1096 if(lSlotNum>8) return 0;
1097 lSelectedSlot=lSlotNum+1;
1100 //----------------------------------------------------//
1101 if(!pF) return 0; // some checks
1102 if(pF->ulFreezeVersion!=1) return 0;
1104 if(ulGetFreezeData==1) // 1: get data
1106 pF->ulStatus=lGPUstatusRet;
1107 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1108 memcpy(pF->psxVRam, psxVub, 1024*512*2);
1113 if(ulGetFreezeData!=0) return 0; // 0: set data
1115 lGPUstatusRet=pF->ulStatus;
1116 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1117 memcpy(psxVub, pF->psxVRam, 1024*512*2);
1119 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1121 PreviousPSXDisplay.Height = 0;
1122 GPUwriteStatus(ulStatusControl[0]);
1123 GPUwriteStatus(ulStatusControl[1]);
1124 GPUwriteStatus(ulStatusControl[2]);
1125 GPUwriteStatus(ulStatusControl[3]);
1126 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1127 GPUwriteStatus(ulStatusControl[6]);
1128 GPUwriteStatus(ulStatusControl[7]);
1129 GPUwriteStatus(ulStatusControl[5]);
1130 GPUwriteStatus(ulStatusControl[4]);
1135 void CALLBACK GPUvBlank(int val)
1137 vBlank=val?0x80000000:0;
1141 #include "../../frontend/plugin_lib.h"
1143 const struct rearmed_cbs *rcbs;
1145 void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
1148 UseFrameSkip = cbs->frameskip;
1149 iUseDither = cbs->gpu_peops.iUseDither;
1150 dwActFixes = cbs->gpu_peops.dwActFixes;
1151 fFrameRateHz = cbs->gpu_peops.fFrameRateHz;
1152 dwFrameRateTicks = cbs->gpu_peops.dwFrameRateTicks;
1154 skip_advice = &cbs->fskip_advice;