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 ***************************************************************************/
24 #include "externals.h"
30 #include "psemu_plugin_defs.h"
39 #define _(x) gettext(x)
46 ////////////////////////////////////////////////////////////////////////
47 // PPDK developer must change libraryName field and can change revision and build
48 ////////////////////////////////////////////////////////////////////////
50 const unsigned char version = 1; // do not touch - library for PSEmu 1.x
51 const unsigned char revision = 1;
52 const unsigned char build = 17; // increase that with each version
55 static char *libraryName = N_("SoftGL Driver");
56 static char *libraryInfo = N_("P.E.Op.S. SoftGL Driver V1.17\nCoded by Pete Bernert and the P.E.Op.S. team\n");
58 static char *libraryName = N_("XVideo Driver");
59 static char *libraryInfo = N_("P.E.Op.S. Xvideo Driver V1.17\nCoded by Pete Bernert and the P.E.Op.S. team\n");
62 static char *PluginAuthor = N_("Pete Bernert and the P.E.Op.S. team");
64 ////////////////////////////////////////////////////////////////////////
65 // memory image of the PSX vram
66 ////////////////////////////////////////////////////////////////////////
68 unsigned char *psxVSecure;
69 unsigned char *psxVub;
71 unsigned short *psxVuw;
72 unsigned short *psxVuw_eom;
77 ////////////////////////////////////////////////////////////////////////
79 ////////////////////////////////////////////////////////////////////////
81 static long lGPUdataRet;
85 char szDebugText[512];
86 uint32_t ulStatusControl[256];
88 static uint32_t gpuDataM[256];
89 static unsigned char gpuCommand = 0;
90 static long gpuDataC = 0;
91 static long gpuDataP = 0;
95 DATAREGISTERMODES DataWriteMode;
96 DATAREGISTERMODES DataReadMode;
98 BOOL bSkipNextFrame = FALSE;
102 short sDispWidths[8] = {256,320,512,640,368,384,512,640};
103 PSXDisplay_t PSXDisplay;
104 PSXDisplay_t PreviousPSXDisplay;
105 long lSelectedSlot=0;
106 BOOL bChangeWinMode=FALSE;
107 BOOL bDoLazyUpdate=FALSE;
108 uint32_t lGPUInfoVals[16];
109 static int iFakePrimBusy=0;
111 ////////////////////////////////////////////////////////////////////////
112 // some misc external display funcs
113 ////////////////////////////////////////////////////////////////////////
118 void CALLBACK GPUdisplayText(char * pText) // some debug func
120 if(!pText) {szDebugText[0]=0;return;}
121 if(strlen(pText)>511) return;
123 strcpy(szDebugText,pText);
126 ////////////////////////////////////////////////////////////////////////
128 void CALLBACK GPUdisplayFlags(unsigned long dwFlags) // some info func
134 ////////////////////////////////////////////////////////////////////////
135 // stuff to make this a true PDK module
136 ////////////////////////////////////////////////////////////////////////
139 char * CALLBACK PSEgetLibName(void)
141 return _(libraryName);
144 unsigned long CALLBACK PSEgetLibType(void)
149 unsigned long CALLBACK PSEgetLibVersion(void)
151 return version<<16|revision<<8|build;
154 char * GPUgetLibInfos(void)
156 return _(libraryInfo);
160 ////////////////////////////////////////////////////////////////////////
162 ////////////////////////////////////////////////////////////////////////
164 static char * pGetConfigInfos(int iCfg)
166 char szO[2][4]={"off","on "};
168 char * pB = (char *)malloc(32767);
170 if (!pB) return NULL;
172 //----------------------------------------------------//
173 sprintf(szTxt,"Plugin: %s %d.%d.%d\r\n",libraryName,version,revision,build);
175 sprintf(szTxt,"Author: %s\r\n\r\n",PluginAuthor);
177 //----------------------------------------------------//
178 if(iCfg && iWindowMode)
179 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",LOWORD(iWinSize),HIWORD(iWinSize));
181 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY);
183 if(iWindowMode && iCfg)
184 strcpy(szTxt,"Window mode\r\n");
187 sprintf(szTxt,"Window mode - [%d Bit]\r\n",iDesktopCol);
189 sprintf(szTxt,"Fullscreen - [%d Bit]\r\n",iColDepth);
192 sprintf(szTxt,"Stretch mode: %d\r\n",iUseNoStretchBlt);
194 sprintf(szTxt,"Dither mode: %d\r\n\r\n",iUseDither);
196 //----------------------------------------------------//
197 sprintf(szTxt,"Framerate:\r\n- FPS limit: %s\r\n",szO[UseFrameLimit]);
199 sprintf(szTxt,"- Frame skipping: %s",szO[UseFrameSkip]);
201 if(iFastFwd) strcat(pB," (fast forward)");
204 strcpy(szTxt,"- FPS limit: Auto\r\n\r\n");
205 else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate);
207 //----------------------------------------------------//
209 strcpy(szTxt,"Misc:\r\n- MaintainAspect: ");
210 if(iMaintainAspect == 0) strcat(szTxt,"disabled");
212 if(iMaintainAspect == 1) strcat(szTxt,"enabled");
213 strcat(szTxt,"\r\n");
216 sprintf(szTxt,"- Game fixes: %s [%08x]\r\n",szO[iUseFixes],dwCfgFixes);
218 //----------------------------------------------------//
222 static void DoTextSnapShot(int iNum)
228 sprintf(szTxt,"%s/pcsx%04d.txt",getenv("HOME"),iNum);
230 if ((txtfile = fopen(szTxt, "wb")) == NULL)
233 pB = pGetConfigInfos(0);
236 fwrite(pB, strlen(pB), 1, txtfile);
242 void CALLBACK GPUmakeSnapshot(void)
246 unsigned char header[0x36];
248 unsigned char line[1024 * 3];
250 unsigned char empty[2] = {0,0};
251 unsigned short color;
252 unsigned long snapshotnr = 0;
255 height = PreviousPSXDisplay.DisplayMode.y;
257 size = height * PreviousPSXDisplay.Range.x1 * 3 + 0x38;
259 // fill in proper values for BMP
261 // hardcoded BMP header
262 memset(header, 0, 0x36);
265 header[2] = size & 0xff;
266 header[3] = (size >> 8) & 0xff;
267 header[4] = (size >> 16) & 0xff;
268 header[5] = (size >> 24) & 0xff;
271 header[0x12] = PreviousPSXDisplay.Range.x1 % 256;
272 header[0x13] = PreviousPSXDisplay.Range.x1 / 256;
273 header[0x16] = height % 256;
274 header[0x17] = height / 256;
282 // increment snapshot value & try to get filename
286 sprintf(filename, "%s/pcsx%04ld.bmp", getenv("HOME"), snapshotnr);
288 bmpfile = fopen(filename,"rb");
296 // try opening new snapshot file
297 if ((bmpfile = fopen(filename,"wb")) == NULL)
300 fwrite(header, 0x36, 1, bmpfile);
301 for (i = height + PSXDisplay.DisplayPosition.y - 1; i >= PSXDisplay.DisplayPosition.y; i--)
303 pD = (unsigned char *)&psxVuw[i * 1024 + PSXDisplay.DisplayPosition.x];
304 for (j = 0; j < PreviousPSXDisplay.Range.x1; j++)
306 if (PSXDisplay.RGB24)
308 uint32_t lu = *(uint32_t *)pD;
309 line[j * 3 + 2] = RED(lu);
310 line[j * 3 + 1] = GREEN(lu);
311 line[j * 3 + 0] = BLUE(lu);
317 line[j * 3 + 2] = (color << 3) & 0xf1;
318 line[j * 3 + 1] = (color >> 2) & 0xf1;
319 line[j * 3 + 0] = (color >> 7) & 0xf1;
323 fwrite(line, PreviousPSXDisplay.Range.x1 * 3, 1, bmpfile);
325 fwrite(empty, 0x2, 1, bmpfile);
328 DoTextSnapShot(snapshotnr);
331 ////////////////////////////////////////////////////////////////////////
332 // INIT, will be called after lib load... well, just do some var init...
333 ////////////////////////////////////////////////////////////////////////
335 long CALLBACK GPUinit() // GPU INIT
337 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
339 szDebugText[0] = 0; // init debug text buffer
341 psxVSecure = (unsigned char *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
346 psxVub=psxVSecure + 512 * 1024; // security offset into double sized psx vram!
348 psxVsb=(signed char *)psxVub; // different ways of accessing PSX VRAM
349 psxVsw=(signed short *)psxVub;
350 psxVsl=(int32_t *)psxVub;
351 psxVuw=(unsigned short *)psxVub;
352 psxVul=(uint32_t *)psxVub;
354 psxVuw_eom=psxVuw+1024*iGPUHeight; // pre-calc of end of vram
356 memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024));
357 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
361 PSXDisplay.RGB24 = FALSE; // init some stuff
362 PSXDisplay.Interlaced = FALSE;
363 PSXDisplay.DrawOffset.x = 0;
364 PSXDisplay.DrawOffset.y = 0;
365 PSXDisplay.DisplayMode.x= 320;
366 PSXDisplay.DisplayMode.y= 240;
367 PreviousPSXDisplay.DisplayMode.x= 320;
368 PreviousPSXDisplay.DisplayMode.y= 240;
369 PSXDisplay.Disabled = FALSE;
370 PreviousPSXDisplay.Range.x0 =0;
371 PreviousPSXDisplay.Range.y0 =0;
372 PSXDisplay.Range.x0=0;
373 PSXDisplay.Range.x1=0;
374 PreviousPSXDisplay.DisplayModeNew.y=0;
375 PSXDisplay.Double = 1;
378 DataWriteMode = DR_NORMAL;
380 // Reset transfer values, to prevent mis-transfer of data
381 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
382 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
384 // device initialised already !
385 lGPUstatusRet = 0x14802000;
387 GPUIsReadyForCommands;
388 bDoVSyncUpdate = TRUE;
393 ////////////////////////////////////////////////////////////////////////
394 // Here starts all...
395 ////////////////////////////////////////////////////////////////////////
398 long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
402 pCaptionText=CapText;
405 ReadConfigGPU(); // read registry
409 bIsFirstFrame = TRUE; // we have to init later
410 bDoVSyncUpdate = TRUE;
412 d=ulInitDisplay(); // setup x
415 *disp=d; // wanna x pointer? ok
422 ////////////////////////////////////////////////////////////////////////
424 ////////////////////////////////////////////////////////////////////////
426 long CALLBACK GPUclose() // GPU CLOSE
429 ReleaseKeyHandler(); // de-subclass window
431 CloseDisplay(); // shutdown direct draw
436 ////////////////////////////////////////////////////////////////////////
437 // I shot the sheriff
438 ////////////////////////////////////////////////////////////////////////
440 long CALLBACK GPUshutdown() // GPU SHUTDOWN
444 return 0; // nothinh to do
447 ////////////////////////////////////////////////////////////////////////
448 // Update display (swap buffers)
449 ////////////////////////////////////////////////////////////////////////
451 void updateDisplay(void) // UPDATE DISPLAY
453 if(PSXDisplay.Disabled) // disable?
455 DoClearFrontBuffer(); // -> clear frontbuffer
456 return; // -> and bye
459 if(dwActFixes&32) // pc fps calculation fix
461 if(UseFrameLimit) PCFrameCap(); // -> brake
462 if(UseFrameSkip || ulKeybits&KEY_SHOWFPS)
466 if(ulKeybits&KEY_SHOWFPS) // make fps display buf
468 sprintf(szDispBuf,"FPS %06.1f",fps_cur);
471 if(iFastFwd) // fastfwd ?
473 static int fpscount; UseFrameSkip=1;
475 if(!bSkipNextFrame) DoBufferSwap(); // -> to skip or not to skip
476 if(fpscount%6) // -> skip 6/7 frames
477 bSkipNextFrame = TRUE;
478 else bSkipNextFrame = FALSE;
480 if(fpscount >= (int)fFrameRateHz) fpscount = 0;
484 if(UseFrameSkip) // skip ?
486 if(!bSkipNextFrame) DoBufferSwap(); // -> to skip or not to skip
487 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
489 if((fps_skip < fFrameRateHz) && !(bSkipNextFrame)) // -> skip max one in a row
490 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
491 else bSkipNextFrame = FALSE;
497 DoBufferSwap(); // -> swap
501 ////////////////////////////////////////////////////////////////////////
502 // roughly emulated screen centering bits... not complete !!!
503 ////////////////////////////////////////////////////////////////////////
505 void ChangeDispOffsetsX(void) // X CENTER
509 if(!PSXDisplay.Range.x1) return;
511 l=PreviousPSXDisplay.DisplayMode.x;
513 l*=(long)PSXDisplay.Range.x1;
514 l/=2560;lx=l;l&=0xfffffff8;
516 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
517 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
519 if(lx>=PreviousPSXDisplay.DisplayMode.x)
521 PreviousPSXDisplay.Range.x1=
522 (short)PreviousPSXDisplay.DisplayMode.x;
523 PreviousPSXDisplay.Range.x0=0;
527 PreviousPSXDisplay.Range.x1=(short)l;
529 PreviousPSXDisplay.Range.x0=
530 (PSXDisplay.Range.x0-500)/8;
532 if(PreviousPSXDisplay.Range.x0<0)
533 PreviousPSXDisplay.Range.x0=0;
535 if((PreviousPSXDisplay.Range.x0+lx)>
536 PreviousPSXDisplay.DisplayMode.x)
538 PreviousPSXDisplay.Range.x0=
539 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
540 PreviousPSXDisplay.Range.x0+=2; //???
542 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
544 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
549 // some linux alignment security
550 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
551 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
552 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
553 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
556 DoClearScreenBuffer();
562 ////////////////////////////////////////////////////////////////////////
564 void ChangeDispOffsetsY(void) // Y CENTER
566 int iT,iO=PreviousPSXDisplay.Range.y0;
567 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
571 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>iGPUHeight)
573 int dy1=iGPUHeight-PreviousPSXDisplay.DisplayModeNew.x;
574 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-iGPUHeight;
578 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
582 PSXDisplay.DisplayPosition.y=0;
583 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
586 else PreviousPSXDisplay.DisplayModeNew.y=0;
590 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
592 PSXDisplay.Height = PSXDisplay.Range.y1 -
593 PSXDisplay.Range.y0 +
594 PreviousPSXDisplay.DisplayModeNew.y;
595 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
600 if(PSXDisplay.PAL) iT=48; else iT=28;
602 if(PSXDisplay.Range.y0>=iT)
604 PreviousPSXDisplay.Range.y0=
605 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
606 if(PreviousPSXDisplay.Range.y0<0)
607 PreviousPSXDisplay.Range.y0=0;
608 PSXDisplay.DisplayModeNew.y+=
609 PreviousPSXDisplay.Range.y0;
612 PreviousPSXDisplay.Range.y0=0;
614 if(iO!=PreviousPSXDisplay.Range.y0)
616 DoClearScreenBuffer();
620 ////////////////////////////////////////////////////////////////////////
621 // check if update needed
622 ////////////////////////////////////////////////////////////////////////
624 void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
626 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
627 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
629 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
630 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
633 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
635 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
636 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
637 PreviousPSXDisplay.DisplayMode.x= // previous will hold
638 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
639 PreviousPSXDisplay.DisplayMode.y= // the size of my
640 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
641 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
643 PSXDisplay.DisplayEnd.x= // calc end of display
644 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
645 PSXDisplay.DisplayEnd.y=
646 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
647 PreviousPSXDisplay.DisplayEnd.x=
648 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
649 PreviousPSXDisplay.DisplayEnd.y=
650 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
652 ChangeDispOffsetsX();
654 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
656 if(UseFrameSkip) updateDisplay(); // stupid stuff when frame skipping enabled
659 ////////////////////////////////////////////////////////////////////////
665 void ChangeWindowMode(void) // TOGGLE FULLSCREEN - WINDOW
667 extern Display *display;
668 extern Window window;
669 extern int root_window_id;
672 MotifWmHints mwmhints;
675 screen=DefaultScreenOfDisplay(display);
676 iWindowMode=!iWindowMode;
678 if(!iWindowMode) // fullscreen
680 mwmhints.flags=MWM_HINTS_DECORATIONS;
681 mwmhints.functions=0;
682 mwmhints.decorations=0;
683 mwmhints.input_mode=0;
684 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
685 XChangeProperty(display,window,mwmatom,mwmatom,32,
686 PropModeReplace,(unsigned char *)&mwmhints,5);
688 XResizeWindow(display,window,screen->width,screen->height);
690 hints.min_width = hints.max_width = hints.base_width = screen->width;
691 hints.min_height= hints.max_height = hints.base_height = screen->height;
693 XSetWMNormalHints(display,window,&hints);
698 memset(&xev, 0, sizeof(xev));
699 xev.xclient.type = ClientMessage;
700 xev.xclient.serial = 0;
701 xev.xclient.send_event = 1;
702 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
703 xev.xclient.window = window;
704 xev.xclient.format = 32;
705 xev.xclient.data.l[0] = 1;
706 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
707 xev.xclient.data.l[2] = 0;
708 xev.xclient.data.l[3] = 0;
709 xev.xclient.data.l[4] = 0;
711 XSendEvent(display, root_window_id, 0,
712 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
718 memset(&xev, 0, sizeof(xev));
719 xev.xclient.type = ClientMessage;
720 xev.xclient.serial = 0;
721 xev.xclient.send_event = 1;
722 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
723 xev.xclient.window = window;
724 xev.xclient.format = 32;
725 xev.xclient.data.l[0] = 0;
726 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
727 xev.xclient.data.l[2] = 0;
728 xev.xclient.data.l[3] = 0;
729 xev.xclient.data.l[4] = 0;
731 XSendEvent(display, root_window_id, 0,
732 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
735 mwmhints.flags=MWM_HINTS_DECORATIONS;
736 mwmhints.functions=0;
737 mwmhints.decorations=1;
738 mwmhints.input_mode=0;
739 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
741 //This shouldn't work on 64 bit longs, but it does...in fact, it breaks when I change all the mwmhints to int.
742 //I don't pretend to understand it.
743 XChangeProperty(display,window,mwmatom,mwmatom,32,
744 PropModeReplace,(unsigned char *)&mwmhints,5);
746 hints.flags=USPosition|USSize;
747 hints.base_width = iResX;
748 hints.base_height = iResY;
749 XSetWMNormalHints(display,window,&hints);
751 XResizeWindow(display,window,iResX,iResY);
754 DoClearScreenBuffer();
756 bChangeWinMode=FALSE;
762 ////////////////////////////////////////////////////////////////////////
763 // gun cursor func: player=0-7, x=0-511, y=0-255
764 ////////////////////////////////////////////////////////////////////////
766 void CALLBACK GPUcursor(int iPlayer,int x,int y)
768 if(iPlayer<0) return;
769 if(iPlayer>7) return;
771 usCursorActive|=(1<<iPlayer);
778 ptCursorPoint[iPlayer].x=x;
779 ptCursorPoint[iPlayer].y=y;
782 ////////////////////////////////////////////////////////////////////////
783 // update lace is called evry VSync
784 ////////////////////////////////////////////////////////////////////////
786 void CALLBACK GPUupdateLace(void) // VSYNC
789 lGPUstatusRet^=0x80000000; // odd/even bit
791 //if(!(dwActFixes&32)) // std fps limitation?
795 if(PSXDisplay.Interlaced) // interlaced mode?
797 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
802 else // non-interlaced?
804 if(dwActFixes&64) // lazy screen update fix
806 if(bDoLazyUpdate && !UseFrameSkip)
812 if(bDoVSyncUpdate && !UseFrameSkip) // some primitives drawn?
813 updateDisplay(); // -> update display
817 if(bChangeWinMode) ChangeWindowMode(); // toggle full - window mode
819 bDoVSyncUpdate=FALSE; // vsync done
822 ////////////////////////////////////////////////////////////////////////
823 // process read request from GPU status register
824 ////////////////////////////////////////////////////////////////////////
827 uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
831 static int iNumRead=0; // odd/even hack
835 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)
839 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
843 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
846 GPUIsNotReadyForCommands;
851 GPUIsReadyForCommands;
854 return lGPUstatusRet;
857 ////////////////////////////////////////////////////////////////////////
858 // processes data send to GPU status register
859 // these are always single packet commands.
860 ////////////////////////////////////////////////////////////////////////
862 void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
864 uint32_t lCommand=(gdata>>24)&0xff;
866 ulStatusControl[lCommand]=gdata; // store command for freezing
870 //--------------------------------------------------//
873 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
874 lGPUstatusRet=0x14802000;
875 PSXDisplay.Disabled=1;
876 DataWriteMode=DataReadMode=DR_NORMAL;
877 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
878 drawX=drawY=0;drawW=drawH=0;
879 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
881 GlobalTextAddrX=0;GlobalTextAddrY=0;
882 GlobalTextTP=0;GlobalTextABR=0;
883 PSXDisplay.RGB24=FALSE;
884 PSXDisplay.Interlaced=FALSE;
887 //--------------------------------------------------//
888 // dis/enable display
891 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
892 PSXDisplay.Disabled = (gdata & 1);
894 if(PSXDisplay.Disabled)
895 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
896 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
899 //--------------------------------------------------//
900 // setting transfer mode
902 gdata &= 0x03; // Only want the lower two bits
904 DataWriteMode=DataReadMode=DR_NORMAL;
905 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
906 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
907 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
908 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
911 //--------------------------------------------------//
912 // setting display position
915 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
916 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
920 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
921 if (PSXDisplay.DisplayPosition.y & 0x200)
922 PSXDisplay.DisplayPosition.y |= 0xfffffc00;
923 if(PSXDisplay.DisplayPosition.y<0)
925 PreviousPSXDisplay.DisplayModeNew.y=PSXDisplay.DisplayPosition.y/PSXDisplay.Double;
926 PSXDisplay.DisplayPosition.y=0;
928 else PreviousPSXDisplay.DisplayModeNew.y=0;
935 PSXDisplay.DisplayPosition.y = (short)((gdata>>12)&0x3ff);
936 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
938 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
940 // store the same val in some helper var, we need it on later compares
941 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
943 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>iGPUHeight)
945 int dy1=iGPUHeight-PSXDisplay.DisplayPosition.y;
946 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-iGPUHeight;
950 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
954 PSXDisplay.DisplayPosition.y=0;
955 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
958 else PreviousPSXDisplay.DisplayModeNew.y=0;
961 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
962 PSXDisplay.DisplayEnd.x=
963 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
964 PSXDisplay.DisplayEnd.y=
965 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
966 PreviousPSXDisplay.DisplayEnd.x=
967 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
968 PreviousPSXDisplay.DisplayEnd.y=
969 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
973 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
975 if(UseFrameSkip) updateDisplay();
976 if(dwActFixes&64) bDoLazyUpdate=TRUE;
979 //--------------------------------------------------//
983 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
984 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
986 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
988 ChangeDispOffsetsX();
991 //--------------------------------------------------//
996 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
997 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
999 PreviousPSXDisplay.Height = PSXDisplay.Height;
1001 PSXDisplay.Height = PSXDisplay.Range.y1 -
1002 PSXDisplay.Range.y0 +
1003 PreviousPSXDisplay.DisplayModeNew.y;
1005 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
1007 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
1009 ChangeDispOffsetsY();
1011 updateDisplayIfChanged();
1015 //--------------------------------------------------//
1016 // setting display infos
1019 PSXDisplay.DisplayModeNew.x =
1020 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
1022 if (gdata&0x04) PSXDisplay.Double=2;
1023 else PSXDisplay.Double=1;
1025 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
1027 ChangeDispOffsetsY();
1029 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
1030 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
1031 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
1033 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
1035 (((gdata & 0x03) << 17) |
1036 ((gdata & 0x40) << 10)); // Set the width bits
1038 if(PSXDisplay.InterlacedNew)
1040 if(!PSXDisplay.Interlaced)
1042 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
1043 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
1045 lGPUstatusRet|=GPUSTATUS_INTERLACED;
1047 else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
1050 lGPUstatusRet|=GPUSTATUS_PAL;
1051 else lGPUstatusRet&=~GPUSTATUS_PAL;
1053 if (PSXDisplay.Double==2)
1054 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
1055 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
1057 if (PSXDisplay.RGB24New)
1058 lGPUstatusRet|=GPUSTATUS_RGB24;
1059 else lGPUstatusRet&=~GPUSTATUS_RGB24;
1061 updateDisplayIfChanged();
1064 //--------------------------------------------------//
1065 // ask about GPU version and other stuff
1073 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
1076 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
1079 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
1083 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
1088 else lGPUdataRet=0x02; // gpu type
1091 case 0x0F: // some bios addr?
1092 lGPUdataRet=0xBFC03720;
1096 //--------------------------------------------------//
1100 ////////////////////////////////////////////////////////////////////////
1101 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
1102 ////////////////////////////////////////////////////////////////////////
1104 __inline void FinishedVRAMWrite(void)
1108 if(!PSXDisplay.Interlaced && UseFrameSkip) // stupid frame skipping
1110 VRAMWrite.Width +=VRAMWrite.x;
1111 VRAMWrite.Height+=VRAMWrite.y;
1112 if(VRAMWrite.x<PSXDisplay.DisplayEnd.x &&
1113 VRAMWrite.Width >=PSXDisplay.DisplayPosition.x &&
1114 VRAMWrite.y<PSXDisplay.DisplayEnd.y &&
1115 VRAMWrite.Height>=PSXDisplay.DisplayPosition.y)
1120 // Set register to NORMAL operation
1121 DataWriteMode = DR_NORMAL;
1122 // Reset transfer values, to prevent mis-transfer of data
1125 VRAMWrite.Width = 0;
1126 VRAMWrite.Height = 0;
1127 VRAMWrite.ColsRemaining = 0;
1128 VRAMWrite.RowsRemaining = 0;
1131 __inline void FinishedVRAMRead(void)
1133 // Set register to NORMAL operation
1134 DataReadMode = DR_NORMAL;
1135 // Reset transfer values, to prevent mis-transfer of data
1139 VRAMRead.Height = 0;
1140 VRAMRead.ColsRemaining = 0;
1141 VRAMRead.RowsRemaining = 0;
1143 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
1144 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
1147 ////////////////////////////////////////////////////////////////////////
1148 // core read from vram
1149 ////////////////////////////////////////////////////////////////////////
1151 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
1155 if(DataReadMode!=DR_VRAMTRANSFER) return;
1159 // adjust read ptr, if necessary
1160 while(VRAMRead.ImagePtr>=psxVuw_eom)
1161 VRAMRead.ImagePtr-=iGPUHeight*1024;
1162 while(VRAMRead.ImagePtr<psxVuw)
1163 VRAMRead.ImagePtr+=iGPUHeight*1024;
1165 for(i=0;i<iSize;i++)
1167 // do 2 seperate 16bit reads for compatibility (wrap issues)
1168 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
1171 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
1173 VRAMRead.ImagePtr++;
1174 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1175 VRAMRead.RowsRemaining --;
1177 if(VRAMRead.RowsRemaining<=0)
1179 VRAMRead.RowsRemaining = VRAMRead.Width;
1180 VRAMRead.ColsRemaining--;
1181 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1182 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1185 // higher 16 bit (always, even if it's an odd width)
1186 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
1187 PUTLE32(pMem, lGPUdataRet); pMem++;
1189 if(VRAMRead.ColsRemaining <= 0)
1190 {FinishedVRAMRead();goto ENDREAD;}
1192 VRAMRead.ImagePtr++;
1193 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1194 VRAMRead.RowsRemaining--;
1195 if(VRAMRead.RowsRemaining<=0)
1197 VRAMRead.RowsRemaining = VRAMRead.Width;
1198 VRAMRead.ColsRemaining--;
1199 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1200 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1202 if(VRAMRead.ColsRemaining <= 0)
1203 {FinishedVRAMRead();goto ENDREAD;}
1205 else {FinishedVRAMRead();goto ENDREAD;}
1213 ////////////////////////////////////////////////////////////////////////
1215 uint32_t CALLBACK GPUreadData(void)
1218 GPUreadDataMem(&l,1);
1222 ////////////////////////////////////////////////////////////////////////
1223 // processes data send to GPU data register
1224 // extra table entries for fixing polyline troubles
1225 ////////////////////////////////////////////////////////////////////////
1227 const unsigned char primTableCX[256] =
1244 8,8,8,8,12,12,12,12,
1248 // 5,5,5,5,6,6,6,6, // FLINE
1249 254,254,254,254,254,254,254,254,
1253 // 7,7,7,7,9,9,9,9, // GLINE
1254 255,255,255,255,255,255,255,255,
1258 2,2,2,2,3,3,3,3, // 3=SPRITE1???
1297 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
1299 unsigned char command;
1303 GPUIsNotReadyForCommands;
1307 if(DataWriteMode==DR_VRAMTRANSFER)
1309 BOOL bFinished=FALSE;
1311 // make sure we are in vram
1312 while(VRAMWrite.ImagePtr>=psxVuw_eom)
1313 VRAMWrite.ImagePtr-=iGPUHeight*1024;
1314 while(VRAMWrite.ImagePtr<psxVuw)
1315 VRAMWrite.ImagePtr+=iGPUHeight*1024;
1318 while(VRAMWrite.ColsRemaining>0)
1320 while(VRAMWrite.RowsRemaining>0)
1322 if(i>=iSize) {goto ENDVRAM;}
1325 gdata=GETLE32(pMem); pMem++;
1327 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
1328 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1329 VRAMWrite.RowsRemaining --;
1331 if(VRAMWrite.RowsRemaining <= 0)
1333 VRAMWrite.ColsRemaining--;
1334 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
1336 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
1337 FinishedVRAMWrite();
1338 bDoVSyncUpdate=TRUE;
1341 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1342 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1345 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
1346 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1347 VRAMWrite.RowsRemaining --;
1350 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1351 VRAMWrite.ColsRemaining--;
1352 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1356 FinishedVRAMWrite();
1357 if(bFinished) bDoVSyncUpdate=TRUE;
1362 if(DataWriteMode==DR_NORMAL)
1364 void (* *primFunc)(unsigned char *);
1365 if(bSkipNextFrame) primFunc=primTableSkip;
1366 else primFunc=primTableJ;
1370 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
1372 gdata=GETLE32(pMem); pMem++; i++;
1376 command = (unsigned char)((gdata>>24) & 0xff);
1378 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
1380 if(primTableCX[command])
1382 gpuDataC = primTableCX[command];
1383 gpuCommand = command;
1384 PUTLE32(&gpuDataM[0], gdata);
1391 PUTLE32(&gpuDataM[gpuDataP], gdata);
1394 if((gpuDataC==254 && gpuDataP>=3) ||
1395 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
1397 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
1398 gpuDataP=gpuDataC-1;
1404 if(gpuDataP == gpuDataC)
1406 gpuDataC=gpuDataP=0;
1407 primFunc[gpuCommand]((unsigned char *)gpuDataM);
1408 if(dwEmuFixes&0x0001 || dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1409 iFakePrimBusy=4;
\r }
1415 GPUIsReadyForCommands;
1419 ////////////////////////////////////////////////////////////////////////
1421 void CALLBACK GPUwriteData(uint32_t gdata)
1423 PUTLE32(&gdata, gdata);
1424 GPUwriteDataMem(&gdata,1);
1427 ////////////////////////////////////////////////////////////////////////
1428 // this functions will be removed soon (or 'soonish')... not really needed, but some emus want them
1429 ////////////////////////////////////////////////////////////////////////
1431 void CALLBACK GPUsetMode(unsigned long gdata)
1433 // Peops does nothing here...
1434 // DataWriteMode=(gdata&1)?DR_VRAMTRANSFER:DR_NORMAL;
1435 // DataReadMode =(gdata&2)?DR_VRAMTRANSFER:DR_NORMAL;
1438 long CALLBACK GPUgetMode(void)
1442 if(DataWriteMode==DR_VRAMTRANSFER) iT|=0x1;
1443 if(DataReadMode ==DR_VRAMTRANSFER) iT|=0x2;
1447 ////////////////////////////////////////////////////////////////////////
1449 ////////////////////////////////////////////////////////////////////////
1451 long CALLBACK GPUconfigure(void)
1458 ////////////////////////////////////////////////////////////////////////
1459 // sets all kind of act fixes
1460 ////////////////////////////////////////////////////////////////////////
1464 if(dwActFixes&0x02) sDispWidths[4]=384;
1465 else sDispWidths[4]=368;
1468 ////////////////////////////////////////////////////////////////////////
1469 // process gpu commands
1470 ////////////////////////////////////////////////////////////////////////
1472 unsigned long lUsedAddr[3];
1474 __inline BOOL CheckForEndlessLoop(unsigned long laddr)
1476 if(laddr==lUsedAddr[1]) return TRUE;
1477 if(laddr==lUsedAddr[2]) return TRUE;
1479 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1480 else lUsedAddr[2]=laddr;
1485 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1488 unsigned char * baseAddrB;
1489 short count;unsigned int DMACommandCounter = 0;
1493 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1495 baseAddrB = (unsigned char*) baseAddrL;
1499 if(iGPUHeight==512) addr&=0x1FFFFC;
1500 if(DMACommandCounter++ > 2000000) break;
1501 if(CheckForEndlessLoop(addr)) break;
1503 count = baseAddrB[addr+3];
1507 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1509 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1511 while (addr != 0xffffff);
1518 ////////////////////////////////////////////////////////////////////////
1520 ////////////////////////////////////////////////////////////////////////
1523 void CALLBACK GPUabout(void) // ABOUT
1529 ////////////////////////////////////////////////////////////////////////
1530 // We are ever fine ;)
1531 ////////////////////////////////////////////////////////////////////////
1533 long CALLBACK GPUtest(void)
1535 // if test fails this function should return negative value for error (unable to continue)
1536 // and positive value for warning (can continue but output might be crappy)
1540 ////////////////////////////////////////////////////////////////////////
1542 ////////////////////////////////////////////////////////////////////////
1544 typedef struct GPUFREEZETAG
1546 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1547 uint32_t ulStatus; // current gpu status
1548 uint32_t ulControl[256]; // latest control register values
1549 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1552 ////////////////////////////////////////////////////////////////////////
1554 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1556 //----------------------------------------------------//
1557 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1559 long lSlotNum=*((long *)pF);
1560 if(lSlotNum<0) return 0;
1561 if(lSlotNum>8) return 0;
1562 lSelectedSlot=lSlotNum+1;
1566 //----------------------------------------------------//
1567 if(!pF) return 0; // some checks
1568 if(pF->ulFreezeVersion!=1) return 0;
1570 if(ulGetFreezeData==1) // 1: get data
1572 pF->ulStatus=lGPUstatusRet;
1573 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1574 memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2);
1579 if(ulGetFreezeData!=0) return 0; // 0: set data
1581 lGPUstatusRet=pF->ulStatus;
1582 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1583 memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2);
1585 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1587 GPUwriteStatus(ulStatusControl[0]);
1588 GPUwriteStatus(ulStatusControl[1]);
1589 GPUwriteStatus(ulStatusControl[2]);
1590 GPUwriteStatus(ulStatusControl[3]);
1591 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1592 GPUwriteStatus(ulStatusControl[6]);
1593 GPUwriteStatus(ulStatusControl[7]);
1594 GPUwriteStatus(ulStatusControl[5]);
1595 GPUwriteStatus(ulStatusControl[4]);
1600 ////////////////////////////////////////////////////////////////////////
1601 ////////////////////////////////////////////////////////////////////////
1602 ////////////////////////////////////////////////////////////////////////
1603 ////////////////////////////////////////////////////////////////////////
1604 ////////////////////////////////////////////////////////////////////////
1605 ////////////////////////////////////////////////////////////////////////
1607 ////////////////////////////////////////////////////////////////////////
1608 // SAVE STATE DISPLAY STUFF
1609 ////////////////////////////////////////////////////////////////////////
1611 // font 0-9, 24x20 pixels, 1 byte = 4 dots
1617 unsigned char cFont[10][120]=
1620 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1621 0x80,0x00,0x00,0x00,0x00,0x00,
1622 0x80,0x00,0x00,0x00,0x00,0x00,
1623 0x80,0x00,0x00,0x00,0x00,0x00,
1624 0x80,0x00,0x00,0x00,0x00,0x00,
1625 0x80,0x00,0x05,0x54,0x00,0x00,
1626 0x80,0x00,0x14,0x05,0x00,0x00,
1627 0x80,0x00,0x14,0x05,0x00,0x00,
1628 0x80,0x00,0x14,0x05,0x00,0x00,
1629 0x80,0x00,0x14,0x05,0x00,0x00,
1630 0x80,0x00,0x14,0x05,0x00,0x00,
1631 0x80,0x00,0x14,0x05,0x00,0x00,
1632 0x80,0x00,0x14,0x05,0x00,0x00,
1633 0x80,0x00,0x14,0x05,0x00,0x00,
1634 0x80,0x00,0x05,0x54,0x00,0x00,
1635 0x80,0x00,0x00,0x00,0x00,0x00,
1636 0x80,0x00,0x00,0x00,0x00,0x00,
1637 0x80,0x00,0x00,0x00,0x00,0x00,
1638 0x80,0x00,0x00,0x00,0x00,0x00,
1639 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1642 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1643 0x80,0x00,0x00,0x00,0x00,0x00,
1644 0x80,0x00,0x00,0x00,0x00,0x00,
1645 0x80,0x00,0x00,0x00,0x00,0x00,
1646 0x80,0x00,0x00,0x00,0x00,0x00,
1647 0x80,0x00,0x00,0x50,0x00,0x00,
1648 0x80,0x00,0x05,0x50,0x00,0x00,
1649 0x80,0x00,0x00,0x50,0x00,0x00,
1650 0x80,0x00,0x00,0x50,0x00,0x00,
1651 0x80,0x00,0x00,0x50,0x00,0x00,
1652 0x80,0x00,0x00,0x50,0x00,0x00,
1653 0x80,0x00,0x00,0x50,0x00,0x00,
1654 0x80,0x00,0x00,0x50,0x00,0x00,
1655 0x80,0x00,0x00,0x50,0x00,0x00,
1656 0x80,0x00,0x05,0x55,0x00,0x00,
1657 0x80,0x00,0x00,0x00,0x00,0x00,
1658 0x80,0x00,0x00,0x00,0x00,0x00,
1659 0x80,0x00,0x00,0x00,0x00,0x00,
1660 0x80,0x00,0x00,0x00,0x00,0x00,
1661 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1664 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1665 0x80,0x00,0x00,0x00,0x00,0x00,
1666 0x80,0x00,0x00,0x00,0x00,0x00,
1667 0x80,0x00,0x00,0x00,0x00,0x00,
1668 0x80,0x00,0x00,0x00,0x00,0x00,
1669 0x80,0x00,0x05,0x54,0x00,0x00,
1670 0x80,0x00,0x14,0x05,0x00,0x00,
1671 0x80,0x00,0x00,0x05,0x00,0x00,
1672 0x80,0x00,0x00,0x05,0x00,0x00,
1673 0x80,0x00,0x00,0x14,0x00,0x00,
1674 0x80,0x00,0x00,0x50,0x00,0x00,
1675 0x80,0x00,0x01,0x40,0x00,0x00,
1676 0x80,0x00,0x05,0x00,0x00,0x00,
1677 0x80,0x00,0x14,0x00,0x00,0x00,
1678 0x80,0x00,0x15,0x55,0x00,0x00,
1679 0x80,0x00,0x00,0x00,0x00,0x00,
1680 0x80,0x00,0x00,0x00,0x00,0x00,
1681 0x80,0x00,0x00,0x00,0x00,0x00,
1682 0x80,0x00,0x00,0x00,0x00,0x00,
1683 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1686 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1687 0x80,0x00,0x00,0x00,0x00,0x00,
1688 0x80,0x00,0x00,0x00,0x00,0x00,
1689 0x80,0x00,0x00,0x00,0x00,0x00,
1690 0x80,0x00,0x00,0x00,0x00,0x00,
1691 0x80,0x00,0x05,0x54,0x00,0x00,
1692 0x80,0x00,0x14,0x05,0x00,0x00,
1693 0x80,0x00,0x00,0x05,0x00,0x00,
1694 0x80,0x00,0x00,0x05,0x00,0x00,
1695 0x80,0x00,0x01,0x54,0x00,0x00,
1696 0x80,0x00,0x00,0x05,0x00,0x00,
1697 0x80,0x00,0x00,0x05,0x00,0x00,
1698 0x80,0x00,0x00,0x05,0x00,0x00,
1699 0x80,0x00,0x14,0x05,0x00,0x00,
1700 0x80,0x00,0x05,0x54,0x00,0x00,
1701 0x80,0x00,0x00,0x00,0x00,0x00,
1702 0x80,0x00,0x00,0x00,0x00,0x00,
1703 0x80,0x00,0x00,0x00,0x00,0x00,
1704 0x80,0x00,0x00,0x00,0x00,0x00,
1705 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1708 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1709 0x80,0x00,0x00,0x00,0x00,0x00,
1710 0x80,0x00,0x00,0x00,0x00,0x00,
1711 0x80,0x00,0x00,0x00,0x00,0x00,
1712 0x80,0x00,0x00,0x00,0x00,0x00,
1713 0x80,0x00,0x00,0x14,0x00,0x00,
1714 0x80,0x00,0x00,0x54,0x00,0x00,
1715 0x80,0x00,0x01,0x54,0x00,0x00,
1716 0x80,0x00,0x01,0x54,0x00,0x00,
1717 0x80,0x00,0x05,0x14,0x00,0x00,
1718 0x80,0x00,0x14,0x14,0x00,0x00,
1719 0x80,0x00,0x15,0x55,0x00,0x00,
1720 0x80,0x00,0x00,0x14,0x00,0x00,
1721 0x80,0x00,0x00,0x14,0x00,0x00,
1722 0x80,0x00,0x00,0x55,0x00,0x00,
1723 0x80,0x00,0x00,0x00,0x00,0x00,
1724 0x80,0x00,0x00,0x00,0x00,0x00,
1725 0x80,0x00,0x00,0x00,0x00,0x00,
1726 0x80,0x00,0x00,0x00,0x00,0x00,
1727 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1730 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1731 0x80,0x00,0x00,0x00,0x00,0x00,
1732 0x80,0x00,0x00,0x00,0x00,0x00,
1733 0x80,0x00,0x00,0x00,0x00,0x00,
1734 0x80,0x00,0x00,0x00,0x00,0x00,
1735 0x80,0x00,0x15,0x55,0x00,0x00,
1736 0x80,0x00,0x14,0x00,0x00,0x00,
1737 0x80,0x00,0x14,0x00,0x00,0x00,
1738 0x80,0x00,0x14,0x00,0x00,0x00,
1739 0x80,0x00,0x15,0x54,0x00,0x00,
1740 0x80,0x00,0x00,0x05,0x00,0x00,
1741 0x80,0x00,0x00,0x05,0x00,0x00,
1742 0x80,0x00,0x00,0x05,0x00,0x00,
1743 0x80,0x00,0x14,0x05,0x00,0x00,
1744 0x80,0x00,0x05,0x54,0x00,0x00,
1745 0x80,0x00,0x00,0x00,0x00,0x00,
1746 0x80,0x00,0x00,0x00,0x00,0x00,
1747 0x80,0x00,0x00,0x00,0x00,0x00,
1748 0x80,0x00,0x00,0x00,0x00,0x00,
1749 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1752 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1753 0x80,0x00,0x00,0x00,0x00,0x00,
1754 0x80,0x00,0x00,0x00,0x00,0x00,
1755 0x80,0x00,0x00,0x00,0x00,0x00,
1756 0x80,0x00,0x00,0x00,0x00,0x00,
1757 0x80,0x00,0x01,0x54,0x00,0x00,
1758 0x80,0x00,0x05,0x00,0x00,0x00,
1759 0x80,0x00,0x14,0x00,0x00,0x00,
1760 0x80,0x00,0x14,0x00,0x00,0x00,
1761 0x80,0x00,0x15,0x54,0x00,0x00,
1762 0x80,0x00,0x15,0x05,0x00,0x00,
1763 0x80,0x00,0x14,0x05,0x00,0x00,
1764 0x80,0x00,0x14,0x05,0x00,0x00,
1765 0x80,0x00,0x14,0x05,0x00,0x00,
1766 0x80,0x00,0x05,0x54,0x00,0x00,
1767 0x80,0x00,0x00,0x00,0x00,0x00,
1768 0x80,0x00,0x00,0x00,0x00,0x00,
1769 0x80,0x00,0x00,0x00,0x00,0x00,
1770 0x80,0x00,0x00,0x00,0x00,0x00,
1771 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1774 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1775 0x80,0x00,0x00,0x00,0x00,0x00,
1776 0x80,0x00,0x00,0x00,0x00,0x00,
1777 0x80,0x00,0x00,0x00,0x00,0x00,
1778 0x80,0x00,0x00,0x00,0x00,0x00,
1779 0x80,0x00,0x15,0x55,0x00,0x00,
1780 0x80,0x00,0x14,0x05,0x00,0x00,
1781 0x80,0x00,0x00,0x14,0x00,0x00,
1782 0x80,0x00,0x00,0x14,0x00,0x00,
1783 0x80,0x00,0x00,0x50,0x00,0x00,
1784 0x80,0x00,0x00,0x50,0x00,0x00,
1785 0x80,0x00,0x01,0x40,0x00,0x00,
1786 0x80,0x00,0x01,0x40,0x00,0x00,
1787 0x80,0x00,0x05,0x00,0x00,0x00,
1788 0x80,0x00,0x05,0x00,0x00,0x00,
1789 0x80,0x00,0x00,0x00,0x00,0x00,
1790 0x80,0x00,0x00,0x00,0x00,0x00,
1791 0x80,0x00,0x00,0x00,0x00,0x00,
1792 0x80,0x00,0x00,0x00,0x00,0x00,
1793 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1796 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1797 0x80,0x00,0x00,0x00,0x00,0x00,
1798 0x80,0x00,0x00,0x00,0x00,0x00,
1799 0x80,0x00,0x00,0x00,0x00,0x00,
1800 0x80,0x00,0x00,0x00,0x00,0x00,
1801 0x80,0x00,0x05,0x54,0x00,0x00,
1802 0x80,0x00,0x14,0x05,0x00,0x00,
1803 0x80,0x00,0x14,0x05,0x00,0x00,
1804 0x80,0x00,0x14,0x05,0x00,0x00,
1805 0x80,0x00,0x05,0x54,0x00,0x00,
1806 0x80,0x00,0x14,0x05,0x00,0x00,
1807 0x80,0x00,0x14,0x05,0x00,0x00,
1808 0x80,0x00,0x14,0x05,0x00,0x00,
1809 0x80,0x00,0x14,0x05,0x00,0x00,
1810 0x80,0x00,0x05,0x54,0x00,0x00,
1811 0x80,0x00,0x00,0x00,0x00,0x00,
1812 0x80,0x00,0x00,0x00,0x00,0x00,
1813 0x80,0x00,0x00,0x00,0x00,0x00,
1814 0x80,0x00,0x00,0x00,0x00,0x00,
1815 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1818 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1819 0x80,0x00,0x00,0x00,0x00,0x00,
1820 0x80,0x00,0x00,0x00,0x00,0x00,
1821 0x80,0x00,0x00,0x00,0x00,0x00,
1822 0x80,0x00,0x00,0x00,0x00,0x00,
1823 0x80,0x00,0x05,0x54,0x00,0x00,
1824 0x80,0x00,0x14,0x05,0x00,0x00,
1825 0x80,0x00,0x14,0x05,0x00,0x00,
1826 0x80,0x00,0x14,0x05,0x00,0x00,
1827 0x80,0x00,0x14,0x15,0x00,0x00,
1828 0x80,0x00,0x05,0x55,0x00,0x00,
1829 0x80,0x00,0x00,0x05,0x00,0x00,
1830 0x80,0x00,0x00,0x05,0x00,0x00,
1831 0x80,0x00,0x00,0x14,0x00,0x00,
1832 0x80,0x00,0x05,0x50,0x00,0x00,
1833 0x80,0x00,0x00,0x00,0x00,0x00,
1834 0x80,0x00,0x00,0x00,0x00,0x00,
1835 0x80,0x00,0x00,0x00,0x00,0x00,
1836 0x80,0x00,0x00,0x00,0x00,0x00,
1837 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1841 ////////////////////////////////////////////////////////////////////////
1843 void PaintPicDot(unsigned char * p,unsigned char c)
1846 if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black
1847 if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white
1848 if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red
1852 ////////////////////////////////////////////////////////////////////////
1853 // the main emu allocs 128x96x3 bytes, and passes a ptr
1854 // to it in pMem... the plugin has to fill it with
1855 // 8-8-8 bit BGR screen data (Win 24 bit BMP format
1857 // Beware: the func can be called at any time,
1858 // so you have to use the frontbuffer to get a fully
1863 extern char * Xpixels;
1865 void GPUgetScreenPic(unsigned char * pMem)
1868 unsigned short c;unsigned char * pf;int x,y;
1870 float XS=(float)iResX/128;
1871 float YS=(float)iResY/96;
1874 memset(pMem, 0, 128*96*3);
1878 unsigned char * ps=(unsigned char *)Xpixels;
1880 long lPitch=iResX<<2;
1887 sx=*((uint32_t *)((ps)+
1888 (((int)((float)y*YS))*lPitch)+
1889 ((int)((float)x*XS))*4));
1891 *(pf+1)=(sx&0xff00)>>8;
1892 *(pf+2)=(sx&0xff0000)>>16;
1900 /////////////////////////////////////////////////////////////////////
1901 // generic number/border painter
1903 pf=pMem+(103*3); // offset to number rect
1905 for(y=0;y<20;y++) // loop the number rect pixel
1909 c=cFont[lSelectedSlot][x+y*6]; // get 4 char dot infos at once (number depends on selected slot)
1910 PaintPicDot(pf,(c&0xc0)>>6);pf+=3; // paint the dots into the rect
1911 PaintPicDot(pf,(c&0x30)>>4);pf+=3;
1912 PaintPicDot(pf,(c&0x0c)>>2);pf+=3;
1913 PaintPicDot(pf,(c&0x03)); pf+=3;
1915 pf+=104*3; // next rect y line
1918 pf=pMem; // ptr to first pos in 128x96 pic
1919 for(x=0;x<128;x++) // loop top/bottom line
1921 *(pf+(95*128*3))=0x00;*pf++=0x00;
1922 *(pf+(95*128*3))=0x00;*pf++=0x00; // paint it red
1923 *(pf+(95*128*3))=0xff;*pf++=0xff;
1925 pf=pMem; // ptr to first pos
1926 for(y=0;y<96;y++) // loop left/right line
1928 *(pf+(127*3))=0x00;*pf++=0x00;
1929 *(pf+(127*3))=0x00;*pf++=0x00; // paint it red
1930 *(pf+(127*3))=0xff;*pf++=0xff;
1931 pf+=127*3; // offset to next line
1937 ////////////////////////////////////////////////////////////////////////
1938 // func will be called with 128x96x3 BGR data.
1939 // the plugin has to store the data and display
1940 // it in the upper right corner.
1941 // If the func is called with a NULL ptr, you can
1942 // release your picture data and stop displaying
1945 void CALLBACK GPUshowScreenPic(unsigned char * pMem)
1947 DestroyPic(); // destroy old pic data
1948 if(pMem==0) return; // done
1949 CreatePic(pMem); // create new pic... don't free pMem or something like that... just read from it
1952 void CALLBACK GPUsetfix(uint32_t dwFixBits)
1954 dwEmuFixes=dwFixBits;