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 bSkipNextFrame = FALSE;
498 DoBufferSwap(); // -> swap
502 ////////////////////////////////////////////////////////////////////////
503 // roughly emulated screen centering bits... not complete !!!
504 ////////////////////////////////////////////////////////////////////////
506 void ChangeDispOffsetsX(void) // X CENTER
510 if(!PSXDisplay.Range.x1) return;
512 l=PreviousPSXDisplay.DisplayMode.x;
514 l*=(long)PSXDisplay.Range.x1;
515 l/=2560;lx=l;l&=0xfffffff8;
517 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
518 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
520 if(lx>=PreviousPSXDisplay.DisplayMode.x)
522 PreviousPSXDisplay.Range.x1=
523 (short)PreviousPSXDisplay.DisplayMode.x;
524 PreviousPSXDisplay.Range.x0=0;
528 PreviousPSXDisplay.Range.x1=(short)l;
530 PreviousPSXDisplay.Range.x0=
531 (PSXDisplay.Range.x0-500)/8;
533 if(PreviousPSXDisplay.Range.x0<0)
534 PreviousPSXDisplay.Range.x0=0;
536 if((PreviousPSXDisplay.Range.x0+lx)>
537 PreviousPSXDisplay.DisplayMode.x)
539 PreviousPSXDisplay.Range.x0=
540 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
541 PreviousPSXDisplay.Range.x0+=2; //???
543 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
545 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
550 // some linux alignment security
551 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
552 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
553 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
554 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
557 DoClearScreenBuffer();
563 ////////////////////////////////////////////////////////////////////////
565 void ChangeDispOffsetsY(void) // Y CENTER
567 int iT,iO=PreviousPSXDisplay.Range.y0;
568 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
572 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>iGPUHeight)
574 int dy1=iGPUHeight-PreviousPSXDisplay.DisplayModeNew.x;
575 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-iGPUHeight;
579 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
583 PSXDisplay.DisplayPosition.y=0;
584 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
587 else PreviousPSXDisplay.DisplayModeNew.y=0;
591 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
593 PSXDisplay.Height = PSXDisplay.Range.y1 -
594 PSXDisplay.Range.y0 +
595 PreviousPSXDisplay.DisplayModeNew.y;
596 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
601 if(PSXDisplay.PAL) iT=48; else iT=28;
603 if(PSXDisplay.Range.y0>=iT)
605 PreviousPSXDisplay.Range.y0=
606 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
607 if(PreviousPSXDisplay.Range.y0<0)
608 PreviousPSXDisplay.Range.y0=0;
609 PSXDisplay.DisplayModeNew.y+=
610 PreviousPSXDisplay.Range.y0;
613 PreviousPSXDisplay.Range.y0=0;
615 if(iO!=PreviousPSXDisplay.Range.y0)
617 DoClearScreenBuffer();
621 ////////////////////////////////////////////////////////////////////////
622 // check if update needed
623 ////////////////////////////////////////////////////////////////////////
625 void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
627 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
628 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
630 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
631 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
634 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
636 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
637 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
638 PreviousPSXDisplay.DisplayMode.x= // previous will hold
639 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
640 PreviousPSXDisplay.DisplayMode.y= // the size of my
641 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
642 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
644 PSXDisplay.DisplayEnd.x= // calc end of display
645 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
646 PSXDisplay.DisplayEnd.y=
647 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
648 PreviousPSXDisplay.DisplayEnd.x=
649 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
650 PreviousPSXDisplay.DisplayEnd.y=
651 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
653 ChangeDispOffsetsX();
655 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
657 if(UseFrameSkip) updateDisplay(); // stupid stuff when frame skipping enabled
660 ////////////////////////////////////////////////////////////////////////
666 void ChangeWindowMode(void) // TOGGLE FULLSCREEN - WINDOW
668 extern Display *display;
669 extern Window window;
670 extern int root_window_id;
673 MotifWmHints mwmhints;
676 screen=DefaultScreenOfDisplay(display);
677 iWindowMode=!iWindowMode;
679 if(!iWindowMode) // fullscreen
681 mwmhints.flags=MWM_HINTS_DECORATIONS;
682 mwmhints.functions=0;
683 mwmhints.decorations=0;
684 mwmhints.input_mode=0;
685 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
686 XChangeProperty(display,window,mwmatom,mwmatom,32,
687 PropModeReplace,(unsigned char *)&mwmhints,5);
689 XResizeWindow(display,window,screen->width,screen->height);
691 hints.min_width = hints.max_width = hints.base_width = screen->width;
692 hints.min_height= hints.max_height = hints.base_height = screen->height;
694 XSetWMNormalHints(display,window,&hints);
699 memset(&xev, 0, sizeof(xev));
700 xev.xclient.type = ClientMessage;
701 xev.xclient.serial = 0;
702 xev.xclient.send_event = 1;
703 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
704 xev.xclient.window = window;
705 xev.xclient.format = 32;
706 xev.xclient.data.l[0] = 1;
707 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
708 xev.xclient.data.l[2] = 0;
709 xev.xclient.data.l[3] = 0;
710 xev.xclient.data.l[4] = 0;
712 XSendEvent(display, root_window_id, 0,
713 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
719 memset(&xev, 0, sizeof(xev));
720 xev.xclient.type = ClientMessage;
721 xev.xclient.serial = 0;
722 xev.xclient.send_event = 1;
723 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
724 xev.xclient.window = window;
725 xev.xclient.format = 32;
726 xev.xclient.data.l[0] = 0;
727 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
728 xev.xclient.data.l[2] = 0;
729 xev.xclient.data.l[3] = 0;
730 xev.xclient.data.l[4] = 0;
732 XSendEvent(display, root_window_id, 0,
733 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
736 mwmhints.flags=MWM_HINTS_DECORATIONS;
737 mwmhints.functions=0;
738 mwmhints.decorations=1;
739 mwmhints.input_mode=0;
740 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
742 //This shouldn't work on 64 bit longs, but it does...in fact, it breaks when I change all the mwmhints to int.
743 //I don't pretend to understand it.
744 XChangeProperty(display,window,mwmatom,mwmatom,32,
745 PropModeReplace,(unsigned char *)&mwmhints,5);
747 hints.flags=USPosition|USSize;
748 hints.base_width = iResX;
749 hints.base_height = iResY;
750 XSetWMNormalHints(display,window,&hints);
752 XResizeWindow(display,window,iResX,iResY);
755 DoClearScreenBuffer();
757 bChangeWinMode=FALSE;
763 ////////////////////////////////////////////////////////////////////////
764 // gun cursor func: player=0-7, x=0-511, y=0-255
765 ////////////////////////////////////////////////////////////////////////
767 void CALLBACK GPUcursor(int iPlayer,int x,int y)
769 if(iPlayer<0) return;
770 if(iPlayer>7) return;
772 usCursorActive|=(1<<iPlayer);
779 ptCursorPoint[iPlayer].x=x;
780 ptCursorPoint[iPlayer].y=y;
783 ////////////////////////////////////////////////////////////////////////
784 // update lace is called evry VSync
785 ////////////////////////////////////////////////////////////////////////
787 void CALLBACK GPUupdateLace(void) // VSYNC
790 lGPUstatusRet^=0x80000000; // odd/even bit
792 //if(!(dwActFixes&32)) // std fps limitation?
796 if(PSXDisplay.Interlaced) // interlaced mode?
798 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
803 else // non-interlaced?
805 if(dwActFixes&64) // lazy screen update fix
807 if(bDoLazyUpdate && !UseFrameSkip)
813 if(bDoVSyncUpdate && !UseFrameSkip) // some primitives drawn?
814 updateDisplay(); // -> update display
818 if(bChangeWinMode) ChangeWindowMode(); // toggle full - window mode
820 bDoVSyncUpdate=FALSE; // vsync done
823 ////////////////////////////////////////////////////////////////////////
824 // process read request from GPU status register
825 ////////////////////////////////////////////////////////////////////////
828 uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
832 static int iNumRead=0; // odd/even hack
836 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)
840 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
844 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
847 GPUIsNotReadyForCommands;
852 GPUIsReadyForCommands;
855 return lGPUstatusRet;
858 ////////////////////////////////////////////////////////////////////////
859 // processes data send to GPU status register
860 // these are always single packet commands.
861 ////////////////////////////////////////////////////////////////////////
863 void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
865 uint32_t lCommand=(gdata>>24)&0xff;
867 ulStatusControl[lCommand]=gdata; // store command for freezing
871 //--------------------------------------------------//
874 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
875 lGPUstatusRet=0x14802000;
876 PSXDisplay.Disabled=1;
877 DataWriteMode=DataReadMode=DR_NORMAL;
878 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
879 drawX=drawY=0;drawW=drawH=0;
880 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
882 GlobalTextAddrX=0;GlobalTextAddrY=0;
883 GlobalTextTP=0;GlobalTextABR=0;
884 PSXDisplay.RGB24=FALSE;
885 PSXDisplay.Interlaced=FALSE;
888 //--------------------------------------------------//
889 // dis/enable display
892 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
893 PSXDisplay.Disabled = (gdata & 1);
895 if(PSXDisplay.Disabled)
896 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
897 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
900 //--------------------------------------------------//
901 // setting transfer mode
903 gdata &= 0x03; // Only want the lower two bits
905 DataWriteMode=DataReadMode=DR_NORMAL;
906 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
907 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
908 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
909 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
912 //--------------------------------------------------//
913 // setting display position
916 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
917 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
921 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
922 if (PSXDisplay.DisplayPosition.y & 0x200)
923 PSXDisplay.DisplayPosition.y |= 0xfffffc00;
924 if(PSXDisplay.DisplayPosition.y<0)
926 PreviousPSXDisplay.DisplayModeNew.y=PSXDisplay.DisplayPosition.y/PSXDisplay.Double;
927 PSXDisplay.DisplayPosition.y=0;
929 else PreviousPSXDisplay.DisplayModeNew.y=0;
936 PSXDisplay.DisplayPosition.y = (short)((gdata>>12)&0x3ff);
937 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
939 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
941 // store the same val in some helper var, we need it on later compares
942 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
944 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>iGPUHeight)
946 int dy1=iGPUHeight-PSXDisplay.DisplayPosition.y;
947 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-iGPUHeight;
951 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
955 PSXDisplay.DisplayPosition.y=0;
956 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
959 else PreviousPSXDisplay.DisplayModeNew.y=0;
962 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
963 PSXDisplay.DisplayEnd.x=
964 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
965 PSXDisplay.DisplayEnd.y=
966 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
967 PreviousPSXDisplay.DisplayEnd.x=
968 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
969 PreviousPSXDisplay.DisplayEnd.y=
970 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
974 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
976 if(UseFrameSkip) updateDisplay();
977 if(dwActFixes&64) bDoLazyUpdate=TRUE;
980 //--------------------------------------------------//
984 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
985 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
987 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
989 ChangeDispOffsetsX();
992 //--------------------------------------------------//
997 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
998 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
1000 PreviousPSXDisplay.Height = PSXDisplay.Height;
1002 PSXDisplay.Height = PSXDisplay.Range.y1 -
1003 PSXDisplay.Range.y0 +
1004 PreviousPSXDisplay.DisplayModeNew.y;
1006 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
1008 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
1010 ChangeDispOffsetsY();
1012 updateDisplayIfChanged();
1016 //--------------------------------------------------//
1017 // setting display infos
1020 PSXDisplay.DisplayModeNew.x =
1021 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
1023 if (gdata&0x04) PSXDisplay.Double=2;
1024 else PSXDisplay.Double=1;
1026 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
1028 ChangeDispOffsetsY();
1030 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
1031 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
1032 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
1034 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
1036 (((gdata & 0x03) << 17) |
1037 ((gdata & 0x40) << 10)); // Set the width bits
1039 if(PSXDisplay.InterlacedNew)
1041 if(!PSXDisplay.Interlaced)
1043 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
1044 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
1046 lGPUstatusRet|=GPUSTATUS_INTERLACED;
1048 else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
1051 lGPUstatusRet|=GPUSTATUS_PAL;
1052 else lGPUstatusRet&=~GPUSTATUS_PAL;
1054 if (PSXDisplay.Double==2)
1055 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
1056 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
1058 if (PSXDisplay.RGB24New)
1059 lGPUstatusRet|=GPUSTATUS_RGB24;
1060 else lGPUstatusRet&=~GPUSTATUS_RGB24;
1062 updateDisplayIfChanged();
1065 //--------------------------------------------------//
1066 // ask about GPU version and other stuff
1074 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
1077 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
1080 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
1084 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
1089 else lGPUdataRet=0x02; // gpu type
1092 case 0x0F: // some bios addr?
1093 lGPUdataRet=0xBFC03720;
1097 //--------------------------------------------------//
1101 ////////////////////////////////////////////////////////////////////////
1102 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
1103 ////////////////////////////////////////////////////////////////////////
1105 __inline void FinishedVRAMWrite(void)
1109 if(!PSXDisplay.Interlaced && UseFrameSkip) // stupid frame skipping
1111 VRAMWrite.Width +=VRAMWrite.x;
1112 VRAMWrite.Height+=VRAMWrite.y;
1113 if(VRAMWrite.x<PSXDisplay.DisplayEnd.x &&
1114 VRAMWrite.Width >=PSXDisplay.DisplayPosition.x &&
1115 VRAMWrite.y<PSXDisplay.DisplayEnd.y &&
1116 VRAMWrite.Height>=PSXDisplay.DisplayPosition.y)
1121 // Set register to NORMAL operation
1122 DataWriteMode = DR_NORMAL;
1123 // Reset transfer values, to prevent mis-transfer of data
1126 VRAMWrite.Width = 0;
1127 VRAMWrite.Height = 0;
1128 VRAMWrite.ColsRemaining = 0;
1129 VRAMWrite.RowsRemaining = 0;
1132 __inline void FinishedVRAMRead(void)
1134 // Set register to NORMAL operation
1135 DataReadMode = DR_NORMAL;
1136 // Reset transfer values, to prevent mis-transfer of data
1140 VRAMRead.Height = 0;
1141 VRAMRead.ColsRemaining = 0;
1142 VRAMRead.RowsRemaining = 0;
1144 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
1145 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
1148 ////////////////////////////////////////////////////////////////////////
1149 // core read from vram
1150 ////////////////////////////////////////////////////////////////////////
1152 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
1156 if(DataReadMode!=DR_VRAMTRANSFER) return;
1160 // adjust read ptr, if necessary
1161 while(VRAMRead.ImagePtr>=psxVuw_eom)
1162 VRAMRead.ImagePtr-=iGPUHeight*1024;
1163 while(VRAMRead.ImagePtr<psxVuw)
1164 VRAMRead.ImagePtr+=iGPUHeight*1024;
1166 for(i=0;i<iSize;i++)
1168 // do 2 seperate 16bit reads for compatibility (wrap issues)
1169 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
1172 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
1174 VRAMRead.ImagePtr++;
1175 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1176 VRAMRead.RowsRemaining --;
1178 if(VRAMRead.RowsRemaining<=0)
1180 VRAMRead.RowsRemaining = VRAMRead.Width;
1181 VRAMRead.ColsRemaining--;
1182 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1183 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1186 // higher 16 bit (always, even if it's an odd width)
1187 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
1188 PUTLE32(pMem, lGPUdataRet); pMem++;
1190 if(VRAMRead.ColsRemaining <= 0)
1191 {FinishedVRAMRead();goto ENDREAD;}
1193 VRAMRead.ImagePtr++;
1194 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1195 VRAMRead.RowsRemaining--;
1196 if(VRAMRead.RowsRemaining<=0)
1198 VRAMRead.RowsRemaining = VRAMRead.Width;
1199 VRAMRead.ColsRemaining--;
1200 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1201 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1203 if(VRAMRead.ColsRemaining <= 0)
1204 {FinishedVRAMRead();goto ENDREAD;}
1206 else {FinishedVRAMRead();goto ENDREAD;}
1214 ////////////////////////////////////////////////////////////////////////
1216 uint32_t CALLBACK GPUreadData(void)
1219 GPUreadDataMem(&l,1);
1223 ////////////////////////////////////////////////////////////////////////
1224 // processes data send to GPU data register
1225 // extra table entries for fixing polyline troubles
1226 ////////////////////////////////////////////////////////////////////////
1228 const unsigned char primTableCX[256] =
1245 8,8,8,8,12,12,12,12,
1249 // 5,5,5,5,6,6,6,6, // FLINE
1250 254,254,254,254,254,254,254,254,
1254 // 7,7,7,7,9,9,9,9, // GLINE
1255 255,255,255,255,255,255,255,255,
1259 2,2,2,2,3,3,3,3, // 3=SPRITE1???
1298 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
1300 unsigned char command;
1304 GPUIsNotReadyForCommands;
1308 if(DataWriteMode==DR_VRAMTRANSFER)
1310 BOOL bFinished=FALSE;
1312 // make sure we are in vram
1313 while(VRAMWrite.ImagePtr>=psxVuw_eom)
1314 VRAMWrite.ImagePtr-=iGPUHeight*1024;
1315 while(VRAMWrite.ImagePtr<psxVuw)
1316 VRAMWrite.ImagePtr+=iGPUHeight*1024;
1319 while(VRAMWrite.ColsRemaining>0)
1321 while(VRAMWrite.RowsRemaining>0)
1323 if(i>=iSize) {goto ENDVRAM;}
1326 gdata=GETLE32(pMem); pMem++;
1328 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
1329 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1330 VRAMWrite.RowsRemaining --;
1332 if(VRAMWrite.RowsRemaining <= 0)
1334 VRAMWrite.ColsRemaining--;
1335 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
1337 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
1338 FinishedVRAMWrite();
1339 bDoVSyncUpdate=TRUE;
1342 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1343 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1346 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
1347 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1348 VRAMWrite.RowsRemaining --;
1351 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1352 VRAMWrite.ColsRemaining--;
1353 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1357 FinishedVRAMWrite();
1358 if(bFinished) bDoVSyncUpdate=TRUE;
1363 if(DataWriteMode==DR_NORMAL)
1365 void (* *primFunc)(unsigned char *);
1366 if(bSkipNextFrame) primFunc=primTableSkip;
1367 else primFunc=primTableJ;
1371 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
1373 gdata=GETLE32(pMem); pMem++; i++;
1377 command = (unsigned char)((gdata>>24) & 0xff);
1379 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
1381 if(primTableCX[command])
1383 gpuDataC = primTableCX[command];
1384 gpuCommand = command;
1385 PUTLE32(&gpuDataM[0], gdata);
1392 PUTLE32(&gpuDataM[gpuDataP], gdata);
1395 if((gpuDataC==254 && gpuDataP>=3) ||
1396 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
1398 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
1399 gpuDataP=gpuDataC-1;
1405 if(gpuDataP == gpuDataC)
1407 gpuDataC=gpuDataP=0;
1408 primFunc[gpuCommand]((unsigned char *)gpuDataM);
1409 if(dwEmuFixes&0x0001 || dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1410 iFakePrimBusy=4;
\r }
1416 GPUIsReadyForCommands;
1420 ////////////////////////////////////////////////////////////////////////
1422 void CALLBACK GPUwriteData(uint32_t gdata)
1424 PUTLE32(&gdata, gdata);
1425 GPUwriteDataMem(&gdata,1);
1428 ////////////////////////////////////////////////////////////////////////
1429 // this functions will be removed soon (or 'soonish')... not really needed, but some emus want them
1430 ////////////////////////////////////////////////////////////////////////
1432 void CALLBACK GPUsetMode(unsigned long gdata)
1434 // Peops does nothing here...
1435 // DataWriteMode=(gdata&1)?DR_VRAMTRANSFER:DR_NORMAL;
1436 // DataReadMode =(gdata&2)?DR_VRAMTRANSFER:DR_NORMAL;
1439 long CALLBACK GPUgetMode(void)
1443 if(DataWriteMode==DR_VRAMTRANSFER) iT|=0x1;
1444 if(DataReadMode ==DR_VRAMTRANSFER) iT|=0x2;
1448 ////////////////////////////////////////////////////////////////////////
1450 ////////////////////////////////////////////////////////////////////////
1452 long CALLBACK GPUconfigure(void)
1459 ////////////////////////////////////////////////////////////////////////
1460 // sets all kind of act fixes
1461 ////////////////////////////////////////////////////////////////////////
1465 if(dwActFixes&0x02) sDispWidths[4]=384;
1466 else sDispWidths[4]=368;
1469 ////////////////////////////////////////////////////////////////////////
1470 // process gpu commands
1471 ////////////////////////////////////////////////////////////////////////
1473 unsigned long lUsedAddr[3];
1475 __inline BOOL CheckForEndlessLoop(unsigned long laddr)
1477 if(laddr==lUsedAddr[1]) return TRUE;
1478 if(laddr==lUsedAddr[2]) return TRUE;
1480 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1481 else lUsedAddr[2]=laddr;
1486 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1489 unsigned char * baseAddrB;
1490 short count;unsigned int DMACommandCounter = 0;
1494 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1496 baseAddrB = (unsigned char*) baseAddrL;
1500 if(iGPUHeight==512) addr&=0x1FFFFC;
1501 if(DMACommandCounter++ > 2000000) break;
1502 if(CheckForEndlessLoop(addr)) break;
1504 count = baseAddrB[addr+3];
1508 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1510 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1512 while (addr != 0xffffff);
1519 ////////////////////////////////////////////////////////////////////////
1521 ////////////////////////////////////////////////////////////////////////
1524 void CALLBACK GPUabout(void) // ABOUT
1530 ////////////////////////////////////////////////////////////////////////
1531 // We are ever fine ;)
1532 ////////////////////////////////////////////////////////////////////////
1534 long CALLBACK GPUtest(void)
1536 // if test fails this function should return negative value for error (unable to continue)
1537 // and positive value for warning (can continue but output might be crappy)
1541 ////////////////////////////////////////////////////////////////////////
1543 ////////////////////////////////////////////////////////////////////////
1545 typedef struct GPUFREEZETAG
1547 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1548 uint32_t ulStatus; // current gpu status
1549 uint32_t ulControl[256]; // latest control register values
1550 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1553 ////////////////////////////////////////////////////////////////////////
1555 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1557 //----------------------------------------------------//
1558 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1560 long lSlotNum=*((long *)pF);
1561 if(lSlotNum<0) return 0;
1562 if(lSlotNum>8) return 0;
1563 lSelectedSlot=lSlotNum+1;
1567 //----------------------------------------------------//
1568 if(!pF) return 0; // some checks
1569 if(pF->ulFreezeVersion!=1) return 0;
1571 if(ulGetFreezeData==1) // 1: get data
1573 pF->ulStatus=lGPUstatusRet;
1574 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1575 memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2);
1580 if(ulGetFreezeData!=0) return 0; // 0: set data
1582 lGPUstatusRet=pF->ulStatus;
1583 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1584 memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2);
1586 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1588 GPUwriteStatus(ulStatusControl[0]);
1589 GPUwriteStatus(ulStatusControl[1]);
1590 GPUwriteStatus(ulStatusControl[2]);
1591 GPUwriteStatus(ulStatusControl[3]);
1592 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1593 GPUwriteStatus(ulStatusControl[6]);
1594 GPUwriteStatus(ulStatusControl[7]);
1595 GPUwriteStatus(ulStatusControl[5]);
1596 GPUwriteStatus(ulStatusControl[4]);
1601 ////////////////////////////////////////////////////////////////////////
1602 ////////////////////////////////////////////////////////////////////////
1603 ////////////////////////////////////////////////////////////////////////
1604 ////////////////////////////////////////////////////////////////////////
1605 ////////////////////////////////////////////////////////////////////////
1606 ////////////////////////////////////////////////////////////////////////
1608 ////////////////////////////////////////////////////////////////////////
1609 // SAVE STATE DISPLAY STUFF
1610 ////////////////////////////////////////////////////////////////////////
1612 // font 0-9, 24x20 pixels, 1 byte = 4 dots
1618 unsigned char cFont[10][120]=
1621 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1622 0x80,0x00,0x00,0x00,0x00,0x00,
1623 0x80,0x00,0x00,0x00,0x00,0x00,
1624 0x80,0x00,0x00,0x00,0x00,0x00,
1625 0x80,0x00,0x00,0x00,0x00,0x00,
1626 0x80,0x00,0x05,0x54,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,0x14,0x05,0x00,0x00,
1635 0x80,0x00,0x05,0x54,0x00,0x00,
1636 0x80,0x00,0x00,0x00,0x00,0x00,
1637 0x80,0x00,0x00,0x00,0x00,0x00,
1638 0x80,0x00,0x00,0x00,0x00,0x00,
1639 0x80,0x00,0x00,0x00,0x00,0x00,
1640 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1643 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
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,0x00,0x00,0x00,
1648 0x80,0x00,0x00,0x50,0x00,0x00,
1649 0x80,0x00,0x05,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,0x00,0x50,0x00,0x00,
1657 0x80,0x00,0x05,0x55,0x00,0x00,
1658 0x80,0x00,0x00,0x00,0x00,0x00,
1659 0x80,0x00,0x00,0x00,0x00,0x00,
1660 0x80,0x00,0x00,0x00,0x00,0x00,
1661 0x80,0x00,0x00,0x00,0x00,0x00,
1662 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1665 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1666 0x80,0x00,0x00,0x00,0x00,0x00,
1667 0x80,0x00,0x00,0x00,0x00,0x00,
1668 0x80,0x00,0x00,0x00,0x00,0x00,
1669 0x80,0x00,0x00,0x00,0x00,0x00,
1670 0x80,0x00,0x05,0x54,0x00,0x00,
1671 0x80,0x00,0x14,0x05,0x00,0x00,
1672 0x80,0x00,0x00,0x05,0x00,0x00,
1673 0x80,0x00,0x00,0x05,0x00,0x00,
1674 0x80,0x00,0x00,0x14,0x00,0x00,
1675 0x80,0x00,0x00,0x50,0x00,0x00,
1676 0x80,0x00,0x01,0x40,0x00,0x00,
1677 0x80,0x00,0x05,0x00,0x00,0x00,
1678 0x80,0x00,0x14,0x00,0x00,0x00,
1679 0x80,0x00,0x15,0x55,0x00,0x00,
1680 0x80,0x00,0x00,0x00,0x00,0x00,
1681 0x80,0x00,0x00,0x00,0x00,0x00,
1682 0x80,0x00,0x00,0x00,0x00,0x00,
1683 0x80,0x00,0x00,0x00,0x00,0x00,
1684 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1687 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1688 0x80,0x00,0x00,0x00,0x00,0x00,
1689 0x80,0x00,0x00,0x00,0x00,0x00,
1690 0x80,0x00,0x00,0x00,0x00,0x00,
1691 0x80,0x00,0x00,0x00,0x00,0x00,
1692 0x80,0x00,0x05,0x54,0x00,0x00,
1693 0x80,0x00,0x14,0x05,0x00,0x00,
1694 0x80,0x00,0x00,0x05,0x00,0x00,
1695 0x80,0x00,0x00,0x05,0x00,0x00,
1696 0x80,0x00,0x01,0x54,0x00,0x00,
1697 0x80,0x00,0x00,0x05,0x00,0x00,
1698 0x80,0x00,0x00,0x05,0x00,0x00,
1699 0x80,0x00,0x00,0x05,0x00,0x00,
1700 0x80,0x00,0x14,0x05,0x00,0x00,
1701 0x80,0x00,0x05,0x54,0x00,0x00,
1702 0x80,0x00,0x00,0x00,0x00,0x00,
1703 0x80,0x00,0x00,0x00,0x00,0x00,
1704 0x80,0x00,0x00,0x00,0x00,0x00,
1705 0x80,0x00,0x00,0x00,0x00,0x00,
1706 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1709 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
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,0x00,0x00,0x00,
1714 0x80,0x00,0x00,0x14,0x00,0x00,
1715 0x80,0x00,0x00,0x54,0x00,0x00,
1716 0x80,0x00,0x01,0x54,0x00,0x00,
1717 0x80,0x00,0x01,0x54,0x00,0x00,
1718 0x80,0x00,0x05,0x14,0x00,0x00,
1719 0x80,0x00,0x14,0x14,0x00,0x00,
1720 0x80,0x00,0x15,0x55,0x00,0x00,
1721 0x80,0x00,0x00,0x14,0x00,0x00,
1722 0x80,0x00,0x00,0x14,0x00,0x00,
1723 0x80,0x00,0x00,0x55,0x00,0x00,
1724 0x80,0x00,0x00,0x00,0x00,0x00,
1725 0x80,0x00,0x00,0x00,0x00,0x00,
1726 0x80,0x00,0x00,0x00,0x00,0x00,
1727 0x80,0x00,0x00,0x00,0x00,0x00,
1728 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1731 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1732 0x80,0x00,0x00,0x00,0x00,0x00,
1733 0x80,0x00,0x00,0x00,0x00,0x00,
1734 0x80,0x00,0x00,0x00,0x00,0x00,
1735 0x80,0x00,0x00,0x00,0x00,0x00,
1736 0x80,0x00,0x15,0x55,0x00,0x00,
1737 0x80,0x00,0x14,0x00,0x00,0x00,
1738 0x80,0x00,0x14,0x00,0x00,0x00,
1739 0x80,0x00,0x14,0x00,0x00,0x00,
1740 0x80,0x00,0x15,0x54,0x00,0x00,
1741 0x80,0x00,0x00,0x05,0x00,0x00,
1742 0x80,0x00,0x00,0x05,0x00,0x00,
1743 0x80,0x00,0x00,0x05,0x00,0x00,
1744 0x80,0x00,0x14,0x05,0x00,0x00,
1745 0x80,0x00,0x05,0x54,0x00,0x00,
1746 0x80,0x00,0x00,0x00,0x00,0x00,
1747 0x80,0x00,0x00,0x00,0x00,0x00,
1748 0x80,0x00,0x00,0x00,0x00,0x00,
1749 0x80,0x00,0x00,0x00,0x00,0x00,
1750 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1753 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1754 0x80,0x00,0x00,0x00,0x00,0x00,
1755 0x80,0x00,0x00,0x00,0x00,0x00,
1756 0x80,0x00,0x00,0x00,0x00,0x00,
1757 0x80,0x00,0x00,0x00,0x00,0x00,
1758 0x80,0x00,0x01,0x54,0x00,0x00,
1759 0x80,0x00,0x05,0x00,0x00,0x00,
1760 0x80,0x00,0x14,0x00,0x00,0x00,
1761 0x80,0x00,0x14,0x00,0x00,0x00,
1762 0x80,0x00,0x15,0x54,0x00,0x00,
1763 0x80,0x00,0x15,0x05,0x00,0x00,
1764 0x80,0x00,0x14,0x05,0x00,0x00,
1765 0x80,0x00,0x14,0x05,0x00,0x00,
1766 0x80,0x00,0x14,0x05,0x00,0x00,
1767 0x80,0x00,0x05,0x54,0x00,0x00,
1768 0x80,0x00,0x00,0x00,0x00,0x00,
1769 0x80,0x00,0x00,0x00,0x00,0x00,
1770 0x80,0x00,0x00,0x00,0x00,0x00,
1771 0x80,0x00,0x00,0x00,0x00,0x00,
1772 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1775 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1776 0x80,0x00,0x00,0x00,0x00,0x00,
1777 0x80,0x00,0x00,0x00,0x00,0x00,
1778 0x80,0x00,0x00,0x00,0x00,0x00,
1779 0x80,0x00,0x00,0x00,0x00,0x00,
1780 0x80,0x00,0x15,0x55,0x00,0x00,
1781 0x80,0x00,0x14,0x05,0x00,0x00,
1782 0x80,0x00,0x00,0x14,0x00,0x00,
1783 0x80,0x00,0x00,0x14,0x00,0x00,
1784 0x80,0x00,0x00,0x50,0x00,0x00,
1785 0x80,0x00,0x00,0x50,0x00,0x00,
1786 0x80,0x00,0x01,0x40,0x00,0x00,
1787 0x80,0x00,0x01,0x40,0x00,0x00,
1788 0x80,0x00,0x05,0x00,0x00,0x00,
1789 0x80,0x00,0x05,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 0x80,0x00,0x00,0x00,0x00,0x00,
1794 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1797 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1798 0x80,0x00,0x00,0x00,0x00,0x00,
1799 0x80,0x00,0x00,0x00,0x00,0x00,
1800 0x80,0x00,0x00,0x00,0x00,0x00,
1801 0x80,0x00,0x00,0x00,0x00,0x00,
1802 0x80,0x00,0x05,0x54,0x00,0x00,
1803 0x80,0x00,0x14,0x05,0x00,0x00,
1804 0x80,0x00,0x14,0x05,0x00,0x00,
1805 0x80,0x00,0x14,0x05,0x00,0x00,
1806 0x80,0x00,0x05,0x54,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,0x14,0x05,0x00,0x00,
1811 0x80,0x00,0x05,0x54,0x00,0x00,
1812 0x80,0x00,0x00,0x00,0x00,0x00,
1813 0x80,0x00,0x00,0x00,0x00,0x00,
1814 0x80,0x00,0x00,0x00,0x00,0x00,
1815 0x80,0x00,0x00,0x00,0x00,0x00,
1816 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1819 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1820 0x80,0x00,0x00,0x00,0x00,0x00,
1821 0x80,0x00,0x00,0x00,0x00,0x00,
1822 0x80,0x00,0x00,0x00,0x00,0x00,
1823 0x80,0x00,0x00,0x00,0x00,0x00,
1824 0x80,0x00,0x05,0x54,0x00,0x00,
1825 0x80,0x00,0x14,0x05,0x00,0x00,
1826 0x80,0x00,0x14,0x05,0x00,0x00,
1827 0x80,0x00,0x14,0x05,0x00,0x00,
1828 0x80,0x00,0x14,0x15,0x00,0x00,
1829 0x80,0x00,0x05,0x55,0x00,0x00,
1830 0x80,0x00,0x00,0x05,0x00,0x00,
1831 0x80,0x00,0x00,0x05,0x00,0x00,
1832 0x80,0x00,0x00,0x14,0x00,0x00,
1833 0x80,0x00,0x05,0x50,0x00,0x00,
1834 0x80,0x00,0x00,0x00,0x00,0x00,
1835 0x80,0x00,0x00,0x00,0x00,0x00,
1836 0x80,0x00,0x00,0x00,0x00,0x00,
1837 0x80,0x00,0x00,0x00,0x00,0x00,
1838 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1842 ////////////////////////////////////////////////////////////////////////
1844 void PaintPicDot(unsigned char * p,unsigned char c)
1847 if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black
1848 if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white
1849 if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red
1853 ////////////////////////////////////////////////////////////////////////
1854 // the main emu allocs 128x96x3 bytes, and passes a ptr
1855 // to it in pMem... the plugin has to fill it with
1856 // 8-8-8 bit BGR screen data (Win 24 bit BMP format
1858 // Beware: the func can be called at any time,
1859 // so you have to use the frontbuffer to get a fully
1864 extern char * Xpixels;
1866 void GPUgetScreenPic(unsigned char * pMem)
1869 unsigned short c;unsigned char * pf;int x,y;
1871 float XS=(float)iResX/128;
1872 float YS=(float)iResY/96;
1875 memset(pMem, 0, 128*96*3);
1879 unsigned char * ps=(unsigned char *)Xpixels;
1881 long lPitch=iResX<<2;
1888 sx=*((uint32_t *)((ps)+
1889 (((int)((float)y*YS))*lPitch)+
1890 ((int)((float)x*XS))*4));
1892 *(pf+1)=(sx&0xff00)>>8;
1893 *(pf+2)=(sx&0xff0000)>>16;
1901 /////////////////////////////////////////////////////////////////////
1902 // generic number/border painter
1904 pf=pMem+(103*3); // offset to number rect
1906 for(y=0;y<20;y++) // loop the number rect pixel
1910 c=cFont[lSelectedSlot][x+y*6]; // get 4 char dot infos at once (number depends on selected slot)
1911 PaintPicDot(pf,(c&0xc0)>>6);pf+=3; // paint the dots into the rect
1912 PaintPicDot(pf,(c&0x30)>>4);pf+=3;
1913 PaintPicDot(pf,(c&0x0c)>>2);pf+=3;
1914 PaintPicDot(pf,(c&0x03)); pf+=3;
1916 pf+=104*3; // next rect y line
1919 pf=pMem; // ptr to first pos in 128x96 pic
1920 for(x=0;x<128;x++) // loop top/bottom line
1922 *(pf+(95*128*3))=0x00;*pf++=0x00;
1923 *(pf+(95*128*3))=0x00;*pf++=0x00; // paint it red
1924 *(pf+(95*128*3))=0xff;*pf++=0xff;
1926 pf=pMem; // ptr to first pos
1927 for(y=0;y<96;y++) // loop left/right line
1929 *(pf+(127*3))=0x00;*pf++=0x00;
1930 *(pf+(127*3))=0x00;*pf++=0x00; // paint it red
1931 *(pf+(127*3))=0xff;*pf++=0xff;
1932 pf+=127*3; // offset to next line
1938 ////////////////////////////////////////////////////////////////////////
1939 // func will be called with 128x96x3 BGR data.
1940 // the plugin has to store the data and display
1941 // it in the upper right corner.
1942 // If the func is called with a NULL ptr, you can
1943 // release your picture data and stop displaying
1946 void CALLBACK GPUshowScreenPic(unsigned char * pMem)
1948 DestroyPic(); // destroy old pic data
1949 if(pMem==0) return; // done
1950 CreatePic(pMem); // create new pic... don't free pMem or something like that... just read from it
1953 void CALLBACK GPUsetfix(uint32_t dwFixBits)
1955 dwEmuFixes=dwFixBits;