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 *psxVub;
28 unsigned short *psxVuw;
29 unsigned short *psxVuw_eom;
34 ////////////////////////////////////////////////////////////////////////
36 ////////////////////////////////////////////////////////////////////////
38 static long lGPUdataRet;
40 uint32_t ulStatusControl[256];
42 static uint32_t gpuDataM[256];
43 static unsigned char gpuCommand = 0;
44 static long gpuDataC = 0;
45 static long gpuDataP = 0;
49 DATAREGISTERMODES DataWriteMode;
50 DATAREGISTERMODES DataReadMode;
52 BOOL bSkipNextFrame = FALSE;
53 BOOL fskip_frameReady;
54 DWORD lace_count_since_flip;
56 short sDispWidths[8] = {256,320,512,640,368,384,512,640};
57 PSXDisplay_t PSXDisplay;
58 PSXDisplay_t PreviousPSXDisplay;
60 BOOL bDoLazyUpdate=FALSE;
61 uint32_t lGPUInfoVals[16];
62 static int iFakePrimBusy=0;
63 static uint32_t vBlank=0;
64 static const int *skip_advice;
66 ////////////////////////////////////////////////////////////////////////
67 // some misc external display funcs
68 ////////////////////////////////////////////////////////////////////////
76 ////////////////////////////////////////////////////////////////////////
77 // sets all kind of act fixes
78 ////////////////////////////////////////////////////////////////////////
80 static void SetFixes(void)
82 if(dwActFixes&0x02) sDispWidths[4]=384;
83 else sDispWidths[4]=368;
86 ////////////////////////////////////////////////////////////////////////
87 // INIT, will be called after lib load... well, just do some var init...
88 ////////////////////////////////////////////////////////////////////////
90 // one extra MB for soft drawing funcs security
91 static unsigned char vram[1024*512*2 + 1024*1024] __attribute__((aligned(2048)));
93 long CALLBACK GPUinit(void) // GPU INIT
95 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
98 psxVub=vram + 512 * 1024; // security offset into double sized psx vram!
100 psxVsb=(signed char *)psxVub; // different ways of accessing PSX VRAM
101 psxVsw=(signed short *)psxVub;
102 psxVsl=(int32_t *)psxVub;
103 psxVuw=(unsigned short *)psxVub;
104 psxVul=(uint32_t *)psxVub;
106 psxVuw_eom=psxVuw+1024*512; // pre-calc of end of vram
108 memset(vram,0x00,(512*2)*1024 + (1024*1024));
109 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
111 PSXDisplay.RGB24 = FALSE; // init some stuff
112 PSXDisplay.Interlaced = FALSE;
113 PSXDisplay.DrawOffset.x = 0;
114 PSXDisplay.DrawOffset.y = 0;
115 PSXDisplay.DisplayMode.x= 320;
116 PSXDisplay.DisplayMode.y= 240;
117 PreviousPSXDisplay.DisplayMode.x= 320;
118 PreviousPSXDisplay.DisplayMode.y= 240;
119 PSXDisplay.Disabled = FALSE;
120 PreviousPSXDisplay.Range.x0 =0;
121 PreviousPSXDisplay.Range.y0 =0;
122 PSXDisplay.Range.x0=0;
123 PSXDisplay.Range.x1=0;
124 PreviousPSXDisplay.DisplayModeNew.y=0;
125 PSXDisplay.Double = 1;
128 DataWriteMode = DR_NORMAL;
130 // Reset transfer values, to prevent mis-transfer of data
131 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
132 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
134 // device initialised already !
135 lGPUstatusRet = 0x14802000;
137 GPUIsReadyForCommands;
138 bDoVSyncUpdate = TRUE;
143 ////////////////////////////////////////////////////////////////////////
144 // Here starts all...
145 ////////////////////////////////////////////////////////////////////////
148 long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
156 bDoVSyncUpdate = TRUE;
158 d=ulInitDisplay(); // setup x
161 *disp=d; // wanna x pointer? ok
168 ////////////////////////////////////////////////////////////////////////
170 ////////////////////////////////////////////////////////////////////////
172 long CALLBACK GPUclose() // GPU CLOSE
174 CloseDisplay(); // shutdown direct draw
179 ////////////////////////////////////////////////////////////////////////
180 // I shot the sheriff
181 ////////////////////////////////////////////////////////////////////////
183 long CALLBACK GPUshutdown(void) // GPU SHUTDOWN
185 CloseDisplay(); // shutdown direct draw
186 return 0; // nothinh to do
189 ////////////////////////////////////////////////////////////////////////
190 // Update display (swap buffers)
191 ////////////////////////////////////////////////////////////////////////
193 static void updateDisplay(void) // UPDATE DISPLAY
195 if(PSXDisplay.Disabled) // disable?
197 return; // -> and bye
200 if(dwActFixes&32) // pc fps calculation fix
202 if(UseFrameLimit) PCFrameCap(); // -> brake
203 if(UseFrameSkip) PCcalcfps();
206 if(UseFrameSkip) // skip ?
210 DoBufferSwap(); // -> to skip or not to skip
211 fskip_frameReady=FALSE;
212 bDoVSyncUpdate=FALSE; // vsync done
217 bSkipNextFrame = FALSE;
218 DoBufferSwap(); // -> swap
219 bDoVSyncUpdate=FALSE; // vsync done
223 static void decideSkip(void)
228 lace_count_since_flip=0;
229 fskip_frameReady=!bSkipNextFrame;
231 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
233 int skip = (skip_advice && *skip_advice) || UseFrameSkip == 1 || fps_skip < fFrameRateHz;
234 if(skip && !bSkipNextFrame) // -> skip max one in a row
235 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
236 else bSkipNextFrame = FALSE;
241 ////////////////////////////////////////////////////////////////////////
242 // roughly emulated screen centering bits... not complete !!!
243 ////////////////////////////////////////////////////////////////////////
245 void ChangeDispOffsetsX(void) // X CENTER
249 if(!PSXDisplay.Range.x1) return;
251 l=PreviousPSXDisplay.DisplayMode.x;
253 l*=(long)PSXDisplay.Range.x1;
254 l/=2560;lx=l;l&=0xfffffff8;
256 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
257 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
259 if(lx>=PreviousPSXDisplay.DisplayMode.x)
261 PreviousPSXDisplay.Range.x1=
262 (short)PreviousPSXDisplay.DisplayMode.x;
263 PreviousPSXDisplay.Range.x0=0;
267 PreviousPSXDisplay.Range.x1=(short)l;
269 PreviousPSXDisplay.Range.x0=
270 (PSXDisplay.Range.x0-500)/8;
272 if(PreviousPSXDisplay.Range.x0<0)
273 PreviousPSXDisplay.Range.x0=0;
275 if((PreviousPSXDisplay.Range.x0+lx)>
276 PreviousPSXDisplay.DisplayMode.x)
278 PreviousPSXDisplay.Range.x0=
279 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
280 PreviousPSXDisplay.Range.x0+=2; //???
282 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
284 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
288 // some linux alignment security
289 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
290 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
291 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
292 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
294 DoClearScreenBuffer();
300 ////////////////////////////////////////////////////////////////////////
302 void ChangeDispOffsetsY(void) // Y CENTER
304 int iT,iO=PreviousPSXDisplay.Range.y0;
305 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
309 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>512)
311 int dy1=512-PreviousPSXDisplay.DisplayModeNew.x;
312 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-512;
316 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
320 PSXDisplay.DisplayPosition.y=0;
321 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
324 else PreviousPSXDisplay.DisplayModeNew.y=0;
328 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
330 PSXDisplay.Height = PSXDisplay.Range.y1 -
331 PSXDisplay.Range.y0 +
332 PreviousPSXDisplay.DisplayModeNew.y;
333 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
338 if(PSXDisplay.PAL) iT=48; else iT=28;
340 if(PSXDisplay.Range.y0>=iT)
342 PreviousPSXDisplay.Range.y0=
343 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
344 if(PreviousPSXDisplay.Range.y0<0)
345 PreviousPSXDisplay.Range.y0=0;
346 PSXDisplay.DisplayModeNew.y+=
347 PreviousPSXDisplay.Range.y0;
350 PreviousPSXDisplay.Range.y0=0;
352 if(iO!=PreviousPSXDisplay.Range.y0)
354 DoClearScreenBuffer();
358 ////////////////////////////////////////////////////////////////////////
359 // check if update needed
360 ////////////////////////////////////////////////////////////////////////
362 static void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
364 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
365 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
367 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
368 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
371 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
373 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
374 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
375 PreviousPSXDisplay.DisplayMode.x= // previous will hold
376 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
377 PreviousPSXDisplay.DisplayMode.y= // the size of my
378 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
379 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
381 PSXDisplay.DisplayEnd.x= // calc end of display
382 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
383 PSXDisplay.DisplayEnd.y=
384 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
385 PreviousPSXDisplay.DisplayEnd.x=
386 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
387 PreviousPSXDisplay.DisplayEnd.y=
388 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
390 ChangeDispOffsetsX();
392 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
394 if(UseFrameSkip) decideSkip(); // stupid stuff when frame skipping enabled
397 ////////////////////////////////////////////////////////////////////////
398 // update lace is called evry VSync
399 ////////////////////////////////////////////////////////////////////////
401 void CALLBACK GPUupdateLace(void) // VSYNC
403 //if(!(dwActFixes&1))
404 // lGPUstatusRet^=0x80000000; // odd/even bit
406 //pcsx-rearmed: removed, this is handled by core
407 //if(!(dwActFixes&32)) // std fps limitation?
410 if(PSXDisplay.Interlaced) // interlaced mode?
412 lGPUstatusRet^=0x80000000; // odd/even bit?
414 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
419 else // non-interlaced?
421 if(dwActFixes&64) // lazy screen update fix
429 if(bDoVSyncUpdate) // some primitives drawn?
430 updateDisplay(); // -> update display
434 if(UseFrameSkip) { // frame over-skip guard
435 lace_count_since_flip++;
436 if(lace_count_since_flip > 8) {
437 bSkipNextFrame=FALSE;
438 fskip_frameReady=TRUE;
443 ////////////////////////////////////////////////////////////////////////
444 // process read request from GPU status register
445 ////////////////////////////////////////////////////////////////////////
448 uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
452 static int iNumRead=0; // odd/even hack
456 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 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
464 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
467 GPUIsNotReadyForCommands;
472 GPUIsReadyForCommands;
475 return lGPUstatusRet | vBlank;
478 ////////////////////////////////////////////////////////////////////////
479 // processes data send to GPU status register
480 // these are always single packet commands.
481 ////////////////////////////////////////////////////////////////////////
483 void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
485 uint32_t lCommand=(gdata>>24)&0xff;
487 ulStatusControl[lCommand]=gdata; // store command for freezing
491 //--------------------------------------------------//
494 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
495 lGPUstatusRet=0x14802000;
496 PSXDisplay.Disabled=1;
497 DataWriteMode=DataReadMode=DR_NORMAL;
498 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
499 drawX=drawY=0;drawW=drawH=0;
500 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
502 GlobalTextAddrX=0;GlobalTextAddrY=0;
503 GlobalTextTP=0;GlobalTextABR=0;
504 PSXDisplay.RGB24=FALSE;
505 PSXDisplay.Interlaced=FALSE;
508 //--------------------------------------------------//
509 // dis/enable display
512 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
513 PSXDisplay.Disabled = (gdata & 1);
515 if(PSXDisplay.Disabled)
516 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
517 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
520 //--------------------------------------------------//
521 // setting transfer mode
523 gdata &= 0x03; // Only want the lower two bits
525 DataWriteMode=DataReadMode=DR_NORMAL;
526 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
527 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
528 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
529 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
532 //--------------------------------------------------//
533 // setting display position
536 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
537 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
540 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
542 // store the same val in some helper var, we need it on later compares
543 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
545 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>512)
547 int dy1=512-PSXDisplay.DisplayPosition.y;
548 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-512;
552 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
556 PSXDisplay.DisplayPosition.y=0;
557 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
560 else PreviousPSXDisplay.DisplayModeNew.y=0;
563 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
564 PSXDisplay.DisplayEnd.x=
565 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
566 PSXDisplay.DisplayEnd.y=
567 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
568 PreviousPSXDisplay.DisplayEnd.x=
569 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
570 PreviousPSXDisplay.DisplayEnd.y=
571 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
575 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
577 if(dwActFixes&64) bDoLazyUpdate=TRUE;
579 if(UseFrameSkip) decideSkip();
581 //--------------------------------------------------//
585 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
586 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
588 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
590 ChangeDispOffsetsX();
593 //--------------------------------------------------//
598 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
599 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
601 PreviousPSXDisplay.Height = PSXDisplay.Height;
603 PSXDisplay.Height = PSXDisplay.Range.y1 -
604 PSXDisplay.Range.y0 +
605 PreviousPSXDisplay.DisplayModeNew.y;
607 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
609 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
611 ChangeDispOffsetsY();
613 updateDisplayIfChanged();
617 //--------------------------------------------------//
618 // setting display infos
621 PSXDisplay.DisplayModeNew.x =
622 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
624 if (gdata&0x04) PSXDisplay.Double=2;
625 else PSXDisplay.Double=1;
627 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
629 ChangeDispOffsetsY();
631 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
632 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
633 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
635 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
637 (((gdata & 0x03) << 17) |
638 ((gdata & 0x40) << 10)); // Set the width bits
640 if(PSXDisplay.InterlacedNew)
642 if(!PSXDisplay.Interlaced)
644 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
645 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
647 lGPUstatusRet|=GPUSTATUS_INTERLACED;
649 else lGPUstatusRet&=~(GPUSTATUS_INTERLACED|0x80000000);
652 lGPUstatusRet|=GPUSTATUS_PAL;
653 else lGPUstatusRet&=~GPUSTATUS_PAL;
655 if (PSXDisplay.Double==2)
656 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
657 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
659 if (PSXDisplay.RGB24New)
660 lGPUstatusRet|=GPUSTATUS_RGB24;
661 else lGPUstatusRet&=~GPUSTATUS_RGB24;
663 updateDisplayIfChanged();
666 //--------------------------------------------------//
667 // ask about GPU version and other stuff
675 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
678 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
681 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
685 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
688 lGPUdataRet=0x02; // gpu type
691 case 0x0F: // some bios addr?
692 lGPUdataRet=0xBFC03720;
696 //--------------------------------------------------//
700 ////////////////////////////////////////////////////////////////////////
701 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
702 ////////////////////////////////////////////////////////////////////////
704 static inline void FinishedVRAMWrite(void)
706 // Set register to NORMAL operation
707 DataWriteMode = DR_NORMAL;
708 // Reset transfer values, to prevent mis-transfer of data
712 VRAMWrite.Height = 0;
713 VRAMWrite.ColsRemaining = 0;
714 VRAMWrite.RowsRemaining = 0;
717 static inline void FinishedVRAMRead(void)
719 // Set register to NORMAL operation
720 DataReadMode = DR_NORMAL;
721 // Reset transfer values, to prevent mis-transfer of data
726 VRAMRead.ColsRemaining = 0;
727 VRAMRead.RowsRemaining = 0;
729 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
730 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
733 ////////////////////////////////////////////////////////////////////////
734 // core read from vram
735 ////////////////////////////////////////////////////////////////////////
737 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
741 if(DataReadMode!=DR_VRAMTRANSFER) return;
745 // adjust read ptr, if necessary
746 while(VRAMRead.ImagePtr>=psxVuw_eom)
747 VRAMRead.ImagePtr-=512*1024;
748 while(VRAMRead.ImagePtr<psxVuw)
749 VRAMRead.ImagePtr+=512*1024;
753 // do 2 seperate 16bit reads for compatibility (wrap issues)
754 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
757 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
760 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
761 VRAMRead.RowsRemaining --;
763 if(VRAMRead.RowsRemaining<=0)
765 VRAMRead.RowsRemaining = VRAMRead.Width;
766 VRAMRead.ColsRemaining--;
767 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
768 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
771 // higher 16 bit (always, even if it's an odd width)
772 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
773 PUTLE32(pMem, lGPUdataRet); pMem++;
775 if(VRAMRead.ColsRemaining <= 0)
776 {FinishedVRAMRead();goto ENDREAD;}
779 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
780 VRAMRead.RowsRemaining--;
781 if(VRAMRead.RowsRemaining<=0)
783 VRAMRead.RowsRemaining = VRAMRead.Width;
784 VRAMRead.ColsRemaining--;
785 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
786 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
788 if(VRAMRead.ColsRemaining <= 0)
789 {FinishedVRAMRead();goto ENDREAD;}
791 else {FinishedVRAMRead();goto ENDREAD;}
799 ////////////////////////////////////////////////////////////////////////
801 uint32_t CALLBACK GPUreadData(void)
804 GPUreadDataMem(&l,1);
808 // Software drawing function
811 // PSX drawing primitives
814 ////////////////////////////////////////////////////////////////////////
815 // processes data send to GPU data register
816 // extra table entries for fixing polyline troubles
817 ////////////////////////////////////////////////////////////////////////
819 static const unsigned char primTableCX[256] =
840 // 5,5,5,5,6,6,6,6, // FLINE
841 254,254,254,254,254,254,254,254,
845 // 7,7,7,7,9,9,9,9, // GLINE
846 255,255,255,255,255,255,255,255,
850 2,2,2,2,3,3,3,3, // 3=SPRITE1???
889 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
891 unsigned char command;
895 GPUIsNotReadyForCommands;
899 if(DataWriteMode==DR_VRAMTRANSFER)
901 BOOL bFinished=FALSE;
903 // make sure we are in vram
904 while(VRAMWrite.ImagePtr>=psxVuw_eom)
905 VRAMWrite.ImagePtr-=512*1024;
906 while(VRAMWrite.ImagePtr<psxVuw)
907 VRAMWrite.ImagePtr+=512*1024;
910 while(VRAMWrite.ColsRemaining>0)
912 while(VRAMWrite.RowsRemaining>0)
914 if(i>=iSize) {goto ENDVRAM;}
917 gdata=GETLE32(pMem); pMem++;
919 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
920 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
921 VRAMWrite.RowsRemaining --;
923 if(VRAMWrite.RowsRemaining <= 0)
925 VRAMWrite.ColsRemaining--;
926 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
928 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
933 VRAMWrite.RowsRemaining = VRAMWrite.Width;
934 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
937 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
938 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
939 VRAMWrite.RowsRemaining --;
942 VRAMWrite.RowsRemaining = VRAMWrite.Width;
943 VRAMWrite.ColsRemaining--;
944 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
949 if(bFinished) bDoVSyncUpdate=TRUE;
954 if(DataWriteMode==DR_NORMAL)
956 void (* *primFunc)(unsigned char *);
957 if(bSkipNextFrame) primFunc=primTableSkip;
958 else primFunc=primTableJ;
962 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
964 gdata=GETLE32(pMem); pMem++; i++;
968 command = (unsigned char)((gdata>>24) & 0xff);
970 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
972 if(primTableCX[command])
974 gpuDataC = primTableCX[command];
975 gpuCommand = command;
976 PUTLE32_(&gpuDataM[0], gdata);
983 PUTLE32_(&gpuDataM[gpuDataP], gdata);
986 if((gpuDataC==254 && gpuDataP>=3) ||
987 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
989 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
996 if(gpuDataP == gpuDataC)
999 primFunc[gpuCommand]((unsigned char *)gpuDataM);
1000 if(dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1008 GPUIsReadyForCommands;
1012 ////////////////////////////////////////////////////////////////////////
1014 void CALLBACK GPUwriteData(uint32_t gdata)
1016 PUTLE32_(&gdata, gdata);
1017 GPUwriteDataMem(&gdata,1);
1020 ////////////////////////////////////////////////////////////////////////
1021 // process gpu commands
1022 ////////////////////////////////////////////////////////////////////////
1024 unsigned long lUsedAddr[3];
1026 static inline BOOL CheckForEndlessLoop(unsigned long laddr)
1028 if(laddr==lUsedAddr[1]) return TRUE;
1029 if(laddr==lUsedAddr[2]) return TRUE;
1031 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1032 else lUsedAddr[2]=laddr;
1037 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1040 unsigned char * baseAddrB;
1041 short count;unsigned int DMACommandCounter = 0;
1046 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1048 baseAddrB = (unsigned char*) baseAddrL;
1053 if(DMACommandCounter++ > 2000000) break;
1054 if(CheckForEndlessLoop(addr)) break;
1056 count = baseAddrB[addr+3];
1057 dmaWords += 1 + count;
1061 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1063 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1065 while (addr != 0xffffff);
1072 ////////////////////////////////////////////////////////////////////////
1074 ////////////////////////////////////////////////////////////////////////
1076 typedef struct GPUFREEZETAG
1078 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1079 uint32_t ulStatus; // current gpu status
1080 uint32_t ulControl[256]; // latest control register values
1081 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1084 ////////////////////////////////////////////////////////////////////////
1086 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1088 //----------------------------------------------------//
1089 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1091 long lSlotNum=*((long *)pF);
1092 if(lSlotNum<0) return 0;
1093 if(lSlotNum>8) return 0;
1094 lSelectedSlot=lSlotNum+1;
1097 //----------------------------------------------------//
1098 if(!pF) return 0; // some checks
1099 if(pF->ulFreezeVersion!=1) return 0;
1101 if(ulGetFreezeData==1) // 1: get data
1103 pF->ulStatus=lGPUstatusRet;
1104 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1105 memcpy(pF->psxVRam, psxVub, 1024*512*2);
1110 if(ulGetFreezeData!=0) return 0; // 0: set data
1112 lGPUstatusRet=pF->ulStatus;
1113 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1114 memcpy(psxVub, pF->psxVRam, 1024*512*2);
1116 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1118 PreviousPSXDisplay.Height = 0;
1119 GPUwriteStatus(ulStatusControl[0]);
1120 GPUwriteStatus(ulStatusControl[1]);
1121 GPUwriteStatus(ulStatusControl[2]);
1122 GPUwriteStatus(ulStatusControl[3]);
1123 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1124 GPUwriteStatus(ulStatusControl[6]);
1125 GPUwriteStatus(ulStatusControl[7]);
1126 GPUwriteStatus(ulStatusControl[5]);
1127 GPUwriteStatus(ulStatusControl[4]);
1132 void CALLBACK GPUvBlank(int val)
1134 vBlank=val?0x80000000:0;
1138 #include "../../frontend/plugin_lib.h"
1140 const struct rearmed_cbs *rcbs;
1142 void GPUrearmedCallbacks(const struct rearmed_cbs *cbs)
1145 UseFrameSkip = cbs->frameskip;
1146 iUseDither = cbs->gpu_peops.iUseDither;
1147 dwActFixes = cbs->gpu_peops.dwActFixes;
1148 fFrameRateHz = cbs->gpu_peops.fFrameRateHz;
1149 dwFrameRateTicks = cbs->gpu_peops.dwFrameRateTicks;
1150 if (cbs->pl_vout_set_raw_vram)
1151 cbs->pl_vout_set_raw_vram(psxVub);
1153 skip_advice = &cbs->fskip_advice;