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?
794 if(PSXDisplay.Interlaced) // interlaced mode?
796 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
801 else // non-interlaced?
803 if(dwActFixes&64) // lazy screen update fix
805 if(bDoLazyUpdate && !UseFrameSkip)
811 if(bDoVSyncUpdate && !UseFrameSkip) // some primitives drawn?
812 updateDisplay(); // -> update display
816 if(bChangeWinMode) ChangeWindowMode(); // toggle full - window mode
818 bDoVSyncUpdate=FALSE; // vsync done
821 ////////////////////////////////////////////////////////////////////////
822 // process read request from GPU status register
823 ////////////////////////////////////////////////////////////////////////
826 uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
830 static int iNumRead=0; // odd/even hack
834 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)
838 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
842 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
845 GPUIsNotReadyForCommands;
850 GPUIsReadyForCommands;
853 return lGPUstatusRet;
856 ////////////////////////////////////////////////////////////////////////
857 // processes data send to GPU status register
858 // these are always single packet commands.
859 ////////////////////////////////////////////////////////////////////////
861 void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
863 uint32_t lCommand=(gdata>>24)&0xff;
865 ulStatusControl[lCommand]=gdata; // store command for freezing
869 //--------------------------------------------------//
872 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
873 lGPUstatusRet=0x14802000;
874 PSXDisplay.Disabled=1;
875 DataWriteMode=DataReadMode=DR_NORMAL;
876 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
877 drawX=drawY=0;drawW=drawH=0;
878 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
880 GlobalTextAddrX=0;GlobalTextAddrY=0;
881 GlobalTextTP=0;GlobalTextABR=0;
882 PSXDisplay.RGB24=FALSE;
883 PSXDisplay.Interlaced=FALSE;
886 //--------------------------------------------------//
887 // dis/enable display
890 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
891 PSXDisplay.Disabled = (gdata & 1);
893 if(PSXDisplay.Disabled)
894 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
895 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
898 //--------------------------------------------------//
899 // setting transfer mode
901 gdata &= 0x03; // Only want the lower two bits
903 DataWriteMode=DataReadMode=DR_NORMAL;
904 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
905 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
906 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
907 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
910 //--------------------------------------------------//
911 // setting display position
914 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
915 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
919 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
920 if (PSXDisplay.DisplayPosition.y & 0x200)
921 PSXDisplay.DisplayPosition.y |= 0xfffffc00;
922 if(PSXDisplay.DisplayPosition.y<0)
924 PreviousPSXDisplay.DisplayModeNew.y=PSXDisplay.DisplayPosition.y/PSXDisplay.Double;
925 PSXDisplay.DisplayPosition.y=0;
927 else PreviousPSXDisplay.DisplayModeNew.y=0;
934 PSXDisplay.DisplayPosition.y = (short)((gdata>>12)&0x3ff);
935 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
937 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
939 // store the same val in some helper var, we need it on later compares
940 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
942 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>iGPUHeight)
944 int dy1=iGPUHeight-PSXDisplay.DisplayPosition.y;
945 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-iGPUHeight;
949 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
953 PSXDisplay.DisplayPosition.y=0;
954 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
957 else PreviousPSXDisplay.DisplayModeNew.y=0;
960 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
961 PSXDisplay.DisplayEnd.x=
962 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
963 PSXDisplay.DisplayEnd.y=
964 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
965 PreviousPSXDisplay.DisplayEnd.x=
966 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
967 PreviousPSXDisplay.DisplayEnd.y=
968 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
972 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
974 if(UseFrameSkip) updateDisplay();
975 if(dwActFixes&64) bDoLazyUpdate=TRUE;
978 //--------------------------------------------------//
982 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
983 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
985 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
987 ChangeDispOffsetsX();
990 //--------------------------------------------------//
995 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
996 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
998 PreviousPSXDisplay.Height = PSXDisplay.Height;
1000 PSXDisplay.Height = PSXDisplay.Range.y1 -
1001 PSXDisplay.Range.y0 +
1002 PreviousPSXDisplay.DisplayModeNew.y;
1004 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
1006 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
1008 ChangeDispOffsetsY();
1010 updateDisplayIfChanged();
1014 //--------------------------------------------------//
1015 // setting display infos
1018 PSXDisplay.DisplayModeNew.x =
1019 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
1021 if (gdata&0x04) PSXDisplay.Double=2;
1022 else PSXDisplay.Double=1;
1024 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
1026 ChangeDispOffsetsY();
1028 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
1029 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
1030 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
1032 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
1034 (((gdata & 0x03) << 17) |
1035 ((gdata & 0x40) << 10)); // Set the width bits
1037 if(PSXDisplay.InterlacedNew)
1039 if(!PSXDisplay.Interlaced)
1041 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
1042 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
1044 lGPUstatusRet|=GPUSTATUS_INTERLACED;
1046 else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
1049 lGPUstatusRet|=GPUSTATUS_PAL;
1050 else lGPUstatusRet&=~GPUSTATUS_PAL;
1052 if (PSXDisplay.Double==2)
1053 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
1054 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
1056 if (PSXDisplay.RGB24New)
1057 lGPUstatusRet|=GPUSTATUS_RGB24;
1058 else lGPUstatusRet&=~GPUSTATUS_RGB24;
1060 updateDisplayIfChanged();
1063 //--------------------------------------------------//
1064 // ask about GPU version and other stuff
1072 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
1075 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
1078 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
1082 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
1087 else lGPUdataRet=0x02; // gpu type
1090 case 0x0F: // some bios addr?
1091 lGPUdataRet=0xBFC03720;
1095 //--------------------------------------------------//
1099 ////////////////////////////////////////////////////////////////////////
1100 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
1101 ////////////////////////////////////////////////////////////////////////
1103 __inline void FinishedVRAMWrite(void)
1107 if(!PSXDisplay.Interlaced && UseFrameSkip) // stupid frame skipping
1109 VRAMWrite.Width +=VRAMWrite.x;
1110 VRAMWrite.Height+=VRAMWrite.y;
1111 if(VRAMWrite.x<PSXDisplay.DisplayEnd.x &&
1112 VRAMWrite.Width >=PSXDisplay.DisplayPosition.x &&
1113 VRAMWrite.y<PSXDisplay.DisplayEnd.y &&
1114 VRAMWrite.Height>=PSXDisplay.DisplayPosition.y)
1119 // Set register to NORMAL operation
1120 DataWriteMode = DR_NORMAL;
1121 // Reset transfer values, to prevent mis-transfer of data
1124 VRAMWrite.Width = 0;
1125 VRAMWrite.Height = 0;
1126 VRAMWrite.ColsRemaining = 0;
1127 VRAMWrite.RowsRemaining = 0;
1130 __inline void FinishedVRAMRead(void)
1132 // Set register to NORMAL operation
1133 DataReadMode = DR_NORMAL;
1134 // Reset transfer values, to prevent mis-transfer of data
1138 VRAMRead.Height = 0;
1139 VRAMRead.ColsRemaining = 0;
1140 VRAMRead.RowsRemaining = 0;
1142 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
1143 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
1146 ////////////////////////////////////////////////////////////////////////
1147 // core read from vram
1148 ////////////////////////////////////////////////////////////////////////
1150 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
1154 if(DataReadMode!=DR_VRAMTRANSFER) return;
1158 // adjust read ptr, if necessary
1159 while(VRAMRead.ImagePtr>=psxVuw_eom)
1160 VRAMRead.ImagePtr-=iGPUHeight*1024;
1161 while(VRAMRead.ImagePtr<psxVuw)
1162 VRAMRead.ImagePtr+=iGPUHeight*1024;
1164 for(i=0;i<iSize;i++)
1166 // do 2 seperate 16bit reads for compatibility (wrap issues)
1167 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
1170 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
1172 VRAMRead.ImagePtr++;
1173 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1174 VRAMRead.RowsRemaining --;
1176 if(VRAMRead.RowsRemaining<=0)
1178 VRAMRead.RowsRemaining = VRAMRead.Width;
1179 VRAMRead.ColsRemaining--;
1180 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1181 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1184 // higher 16 bit (always, even if it's an odd width)
1185 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
1186 PUTLE32(pMem, lGPUdataRet); pMem++;
1188 if(VRAMRead.ColsRemaining <= 0)
1189 {FinishedVRAMRead();goto ENDREAD;}
1191 VRAMRead.ImagePtr++;
1192 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1193 VRAMRead.RowsRemaining--;
1194 if(VRAMRead.RowsRemaining<=0)
1196 VRAMRead.RowsRemaining = VRAMRead.Width;
1197 VRAMRead.ColsRemaining--;
1198 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1199 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1201 if(VRAMRead.ColsRemaining <= 0)
1202 {FinishedVRAMRead();goto ENDREAD;}
1204 else {FinishedVRAMRead();goto ENDREAD;}
1212 ////////////////////////////////////////////////////////////////////////
1214 uint32_t CALLBACK GPUreadData(void)
1217 GPUreadDataMem(&l,1);
1221 ////////////////////////////////////////////////////////////////////////
1222 // processes data send to GPU data register
1223 // extra table entries for fixing polyline troubles
1224 ////////////////////////////////////////////////////////////////////////
1226 const unsigned char primTableCX[256] =
1243 8,8,8,8,12,12,12,12,
1247 // 5,5,5,5,6,6,6,6, // FLINE
1248 254,254,254,254,254,254,254,254,
1252 // 7,7,7,7,9,9,9,9, // GLINE
1253 255,255,255,255,255,255,255,255,
1257 2,2,2,2,3,3,3,3, // 3=SPRITE1???
1296 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
1298 unsigned char command;
1302 GPUIsNotReadyForCommands;
1306 if(DataWriteMode==DR_VRAMTRANSFER)
1308 BOOL bFinished=FALSE;
1310 // make sure we are in vram
1311 while(VRAMWrite.ImagePtr>=psxVuw_eom)
1312 VRAMWrite.ImagePtr-=iGPUHeight*1024;
1313 while(VRAMWrite.ImagePtr<psxVuw)
1314 VRAMWrite.ImagePtr+=iGPUHeight*1024;
1317 while(VRAMWrite.ColsRemaining>0)
1319 while(VRAMWrite.RowsRemaining>0)
1321 if(i>=iSize) {goto ENDVRAM;}
1324 gdata=GETLE32(pMem); pMem++;
1326 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
1327 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1328 VRAMWrite.RowsRemaining --;
1330 if(VRAMWrite.RowsRemaining <= 0)
1332 VRAMWrite.ColsRemaining--;
1333 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
1335 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
1336 FinishedVRAMWrite();
1337 bDoVSyncUpdate=TRUE;
1340 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1341 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1344 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
1345 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1346 VRAMWrite.RowsRemaining --;
1349 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1350 VRAMWrite.ColsRemaining--;
1351 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1355 FinishedVRAMWrite();
1356 if(bFinished) bDoVSyncUpdate=TRUE;
1361 if(DataWriteMode==DR_NORMAL)
1363 void (* *primFunc)(unsigned char *);
1364 if(bSkipNextFrame) primFunc=primTableSkip;
1365 else primFunc=primTableJ;
1369 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
1371 gdata=GETLE32(pMem); pMem++; i++;
1375 command = (unsigned char)((gdata>>24) & 0xff);
1377 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
1379 if(primTableCX[command])
1381 gpuDataC = primTableCX[command];
1382 gpuCommand = command;
1383 PUTLE32(&gpuDataM[0], gdata);
1390 PUTLE32(&gpuDataM[gpuDataP], gdata);
1393 if((gpuDataC==254 && gpuDataP>=3) ||
1394 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
1396 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
1397 gpuDataP=gpuDataC-1;
1403 if(gpuDataP == gpuDataC)
1405 gpuDataC=gpuDataP=0;
1406 primFunc[gpuCommand]((unsigned char *)gpuDataM);
1407 if(dwEmuFixes&0x0001 || dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1408 iFakePrimBusy=4;
\r }
1414 GPUIsReadyForCommands;
1418 ////////////////////////////////////////////////////////////////////////
1420 void CALLBACK GPUwriteData(uint32_t gdata)
1422 PUTLE32(&gdata, gdata);
1423 GPUwriteDataMem(&gdata,1);
1426 ////////////////////////////////////////////////////////////////////////
1427 // this functions will be removed soon (or 'soonish')... not really needed, but some emus want them
1428 ////////////////////////////////////////////////////////////////////////
1430 void CALLBACK GPUsetMode(unsigned long gdata)
1432 // Peops does nothing here...
1433 // DataWriteMode=(gdata&1)?DR_VRAMTRANSFER:DR_NORMAL;
1434 // DataReadMode =(gdata&2)?DR_VRAMTRANSFER:DR_NORMAL;
1437 long CALLBACK GPUgetMode(void)
1441 if(DataWriteMode==DR_VRAMTRANSFER) iT|=0x1;
1442 if(DataReadMode ==DR_VRAMTRANSFER) iT|=0x2;
1446 ////////////////////////////////////////////////////////////////////////
1448 ////////////////////////////////////////////////////////////////////////
1450 long CALLBACK GPUconfigure(void)
1457 ////////////////////////////////////////////////////////////////////////
1458 // sets all kind of act fixes
1459 ////////////////////////////////////////////////////////////////////////
1463 if(dwActFixes&0x02) sDispWidths[4]=384;
1464 else sDispWidths[4]=368;
1467 ////////////////////////////////////////////////////////////////////////
1468 // process gpu commands
1469 ////////////////////////////////////////////////////////////////////////
1471 unsigned long lUsedAddr[3];
1473 __inline BOOL CheckForEndlessLoop(unsigned long laddr)
1475 if(laddr==lUsedAddr[1]) return TRUE;
1476 if(laddr==lUsedAddr[2]) return TRUE;
1478 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1479 else lUsedAddr[2]=laddr;
1484 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1487 unsigned char * baseAddrB;
1488 short count;unsigned int DMACommandCounter = 0;
1492 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1494 baseAddrB = (unsigned char*) baseAddrL;
1498 if(iGPUHeight==512) addr&=0x1FFFFC;
1499 if(DMACommandCounter++ > 2000000) break;
1500 if(CheckForEndlessLoop(addr)) break;
1502 count = baseAddrB[addr+3];
1506 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1508 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1510 while (addr != 0xffffff);
1517 ////////////////////////////////////////////////////////////////////////
1519 ////////////////////////////////////////////////////////////////////////
1522 void CALLBACK GPUabout(void) // ABOUT
1528 ////////////////////////////////////////////////////////////////////////
1529 // We are ever fine ;)
1530 ////////////////////////////////////////////////////////////////////////
1532 long CALLBACK GPUtest(void)
1534 // if test fails this function should return negative value for error (unable to continue)
1535 // and positive value for warning (can continue but output might be crappy)
1539 ////////////////////////////////////////////////////////////////////////
1541 ////////////////////////////////////////////////////////////////////////
1543 typedef struct GPUFREEZETAG
1545 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1546 uint32_t ulStatus; // current gpu status
1547 uint32_t ulControl[256]; // latest control register values
1548 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1551 ////////////////////////////////////////////////////////////////////////
1553 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1555 //----------------------------------------------------//
1556 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1558 long lSlotNum=*((long *)pF);
1559 if(lSlotNum<0) return 0;
1560 if(lSlotNum>8) return 0;
1561 lSelectedSlot=lSlotNum+1;
1565 //----------------------------------------------------//
1566 if(!pF) return 0; // some checks
1567 if(pF->ulFreezeVersion!=1) return 0;
1569 if(ulGetFreezeData==1) // 1: get data
1571 pF->ulStatus=lGPUstatusRet;
1572 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1573 memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2);
1578 if(ulGetFreezeData!=0) return 0; // 0: set data
1580 lGPUstatusRet=pF->ulStatus;
1581 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1582 memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2);
1584 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1586 GPUwriteStatus(ulStatusControl[0]);
1587 GPUwriteStatus(ulStatusControl[1]);
1588 GPUwriteStatus(ulStatusControl[2]);
1589 GPUwriteStatus(ulStatusControl[3]);
1590 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1591 GPUwriteStatus(ulStatusControl[6]);
1592 GPUwriteStatus(ulStatusControl[7]);
1593 GPUwriteStatus(ulStatusControl[5]);
1594 GPUwriteStatus(ulStatusControl[4]);
1599 ////////////////////////////////////////////////////////////////////////
1600 ////////////////////////////////////////////////////////////////////////
1601 ////////////////////////////////////////////////////////////////////////
1602 ////////////////////////////////////////////////////////////////////////
1603 ////////////////////////////////////////////////////////////////////////
1604 ////////////////////////////////////////////////////////////////////////
1606 ////////////////////////////////////////////////////////////////////////
1607 // SAVE STATE DISPLAY STUFF
1608 ////////////////////////////////////////////////////////////////////////
1610 // font 0-9, 24x20 pixels, 1 byte = 4 dots
1616 unsigned char cFont[10][120]=
1619 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1620 0x80,0x00,0x00,0x00,0x00,0x00,
1621 0x80,0x00,0x00,0x00,0x00,0x00,
1622 0x80,0x00,0x00,0x00,0x00,0x00,
1623 0x80,0x00,0x00,0x00,0x00,0x00,
1624 0x80,0x00,0x05,0x54,0x00,0x00,
1625 0x80,0x00,0x14,0x05,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,0x05,0x54,0x00,0x00,
1634 0x80,0x00,0x00,0x00,0x00,0x00,
1635 0x80,0x00,0x00,0x00,0x00,0x00,
1636 0x80,0x00,0x00,0x00,0x00,0x00,
1637 0x80,0x00,0x00,0x00,0x00,0x00,
1638 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1641 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1642 0x80,0x00,0x00,0x00,0x00,0x00,
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,0x50,0x00,0x00,
1647 0x80,0x00,0x05,0x50,0x00,0x00,
1648 0x80,0x00,0x00,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,0x05,0x55,0x00,0x00,
1656 0x80,0x00,0x00,0x00,0x00,0x00,
1657 0x80,0x00,0x00,0x00,0x00,0x00,
1658 0x80,0x00,0x00,0x00,0x00,0x00,
1659 0x80,0x00,0x00,0x00,0x00,0x00,
1660 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1663 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1664 0x80,0x00,0x00,0x00,0x00,0x00,
1665 0x80,0x00,0x00,0x00,0x00,0x00,
1666 0x80,0x00,0x00,0x00,0x00,0x00,
1667 0x80,0x00,0x00,0x00,0x00,0x00,
1668 0x80,0x00,0x05,0x54,0x00,0x00,
1669 0x80,0x00,0x14,0x05,0x00,0x00,
1670 0x80,0x00,0x00,0x05,0x00,0x00,
1671 0x80,0x00,0x00,0x05,0x00,0x00,
1672 0x80,0x00,0x00,0x14,0x00,0x00,
1673 0x80,0x00,0x00,0x50,0x00,0x00,
1674 0x80,0x00,0x01,0x40,0x00,0x00,
1675 0x80,0x00,0x05,0x00,0x00,0x00,
1676 0x80,0x00,0x14,0x00,0x00,0x00,
1677 0x80,0x00,0x15,0x55,0x00,0x00,
1678 0x80,0x00,0x00,0x00,0x00,0x00,
1679 0x80,0x00,0x00,0x00,0x00,0x00,
1680 0x80,0x00,0x00,0x00,0x00,0x00,
1681 0x80,0x00,0x00,0x00,0x00,0x00,
1682 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1685 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1686 0x80,0x00,0x00,0x00,0x00,0x00,
1687 0x80,0x00,0x00,0x00,0x00,0x00,
1688 0x80,0x00,0x00,0x00,0x00,0x00,
1689 0x80,0x00,0x00,0x00,0x00,0x00,
1690 0x80,0x00,0x05,0x54,0x00,0x00,
1691 0x80,0x00,0x14,0x05,0x00,0x00,
1692 0x80,0x00,0x00,0x05,0x00,0x00,
1693 0x80,0x00,0x00,0x05,0x00,0x00,
1694 0x80,0x00,0x01,0x54,0x00,0x00,
1695 0x80,0x00,0x00,0x05,0x00,0x00,
1696 0x80,0x00,0x00,0x05,0x00,0x00,
1697 0x80,0x00,0x00,0x05,0x00,0x00,
1698 0x80,0x00,0x14,0x05,0x00,0x00,
1699 0x80,0x00,0x05,0x54,0x00,0x00,
1700 0x80,0x00,0x00,0x00,0x00,0x00,
1701 0x80,0x00,0x00,0x00,0x00,0x00,
1702 0x80,0x00,0x00,0x00,0x00,0x00,
1703 0x80,0x00,0x00,0x00,0x00,0x00,
1704 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1707 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1708 0x80,0x00,0x00,0x00,0x00,0x00,
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,0x14,0x00,0x00,
1713 0x80,0x00,0x00,0x54,0x00,0x00,
1714 0x80,0x00,0x01,0x54,0x00,0x00,
1715 0x80,0x00,0x01,0x54,0x00,0x00,
1716 0x80,0x00,0x05,0x14,0x00,0x00,
1717 0x80,0x00,0x14,0x14,0x00,0x00,
1718 0x80,0x00,0x15,0x55,0x00,0x00,
1719 0x80,0x00,0x00,0x14,0x00,0x00,
1720 0x80,0x00,0x00,0x14,0x00,0x00,
1721 0x80,0x00,0x00,0x55,0x00,0x00,
1722 0x80,0x00,0x00,0x00,0x00,0x00,
1723 0x80,0x00,0x00,0x00,0x00,0x00,
1724 0x80,0x00,0x00,0x00,0x00,0x00,
1725 0x80,0x00,0x00,0x00,0x00,0x00,
1726 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1729 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1730 0x80,0x00,0x00,0x00,0x00,0x00,
1731 0x80,0x00,0x00,0x00,0x00,0x00,
1732 0x80,0x00,0x00,0x00,0x00,0x00,
1733 0x80,0x00,0x00,0x00,0x00,0x00,
1734 0x80,0x00,0x15,0x55,0x00,0x00,
1735 0x80,0x00,0x14,0x00,0x00,0x00,
1736 0x80,0x00,0x14,0x00,0x00,0x00,
1737 0x80,0x00,0x14,0x00,0x00,0x00,
1738 0x80,0x00,0x15,0x54,0x00,0x00,
1739 0x80,0x00,0x00,0x05,0x00,0x00,
1740 0x80,0x00,0x00,0x05,0x00,0x00,
1741 0x80,0x00,0x00,0x05,0x00,0x00,
1742 0x80,0x00,0x14,0x05,0x00,0x00,
1743 0x80,0x00,0x05,0x54,0x00,0x00,
1744 0x80,0x00,0x00,0x00,0x00,0x00,
1745 0x80,0x00,0x00,0x00,0x00,0x00,
1746 0x80,0x00,0x00,0x00,0x00,0x00,
1747 0x80,0x00,0x00,0x00,0x00,0x00,
1748 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1751 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1752 0x80,0x00,0x00,0x00,0x00,0x00,
1753 0x80,0x00,0x00,0x00,0x00,0x00,
1754 0x80,0x00,0x00,0x00,0x00,0x00,
1755 0x80,0x00,0x00,0x00,0x00,0x00,
1756 0x80,0x00,0x01,0x54,0x00,0x00,
1757 0x80,0x00,0x05,0x00,0x00,0x00,
1758 0x80,0x00,0x14,0x00,0x00,0x00,
1759 0x80,0x00,0x14,0x00,0x00,0x00,
1760 0x80,0x00,0x15,0x54,0x00,0x00,
1761 0x80,0x00,0x15,0x05,0x00,0x00,
1762 0x80,0x00,0x14,0x05,0x00,0x00,
1763 0x80,0x00,0x14,0x05,0x00,0x00,
1764 0x80,0x00,0x14,0x05,0x00,0x00,
1765 0x80,0x00,0x05,0x54,0x00,0x00,
1766 0x80,0x00,0x00,0x00,0x00,0x00,
1767 0x80,0x00,0x00,0x00,0x00,0x00,
1768 0x80,0x00,0x00,0x00,0x00,0x00,
1769 0x80,0x00,0x00,0x00,0x00,0x00,
1770 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1773 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1774 0x80,0x00,0x00,0x00,0x00,0x00,
1775 0x80,0x00,0x00,0x00,0x00,0x00,
1776 0x80,0x00,0x00,0x00,0x00,0x00,
1777 0x80,0x00,0x00,0x00,0x00,0x00,
1778 0x80,0x00,0x15,0x55,0x00,0x00,
1779 0x80,0x00,0x14,0x05,0x00,0x00,
1780 0x80,0x00,0x00,0x14,0x00,0x00,
1781 0x80,0x00,0x00,0x14,0x00,0x00,
1782 0x80,0x00,0x00,0x50,0x00,0x00,
1783 0x80,0x00,0x00,0x50,0x00,0x00,
1784 0x80,0x00,0x01,0x40,0x00,0x00,
1785 0x80,0x00,0x01,0x40,0x00,0x00,
1786 0x80,0x00,0x05,0x00,0x00,0x00,
1787 0x80,0x00,0x05,0x00,0x00,0x00,
1788 0x80,0x00,0x00,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 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1795 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1796 0x80,0x00,0x00,0x00,0x00,0x00,
1797 0x80,0x00,0x00,0x00,0x00,0x00,
1798 0x80,0x00,0x00,0x00,0x00,0x00,
1799 0x80,0x00,0x00,0x00,0x00,0x00,
1800 0x80,0x00,0x05,0x54,0x00,0x00,
1801 0x80,0x00,0x14,0x05,0x00,0x00,
1802 0x80,0x00,0x14,0x05,0x00,0x00,
1803 0x80,0x00,0x14,0x05,0x00,0x00,
1804 0x80,0x00,0x05,0x54,0x00,0x00,
1805 0x80,0x00,0x14,0x05,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,0x05,0x54,0x00,0x00,
1810 0x80,0x00,0x00,0x00,0x00,0x00,
1811 0x80,0x00,0x00,0x00,0x00,0x00,
1812 0x80,0x00,0x00,0x00,0x00,0x00,
1813 0x80,0x00,0x00,0x00,0x00,0x00,
1814 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1817 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1818 0x80,0x00,0x00,0x00,0x00,0x00,
1819 0x80,0x00,0x00,0x00,0x00,0x00,
1820 0x80,0x00,0x00,0x00,0x00,0x00,
1821 0x80,0x00,0x00,0x00,0x00,0x00,
1822 0x80,0x00,0x05,0x54,0x00,0x00,
1823 0x80,0x00,0x14,0x05,0x00,0x00,
1824 0x80,0x00,0x14,0x05,0x00,0x00,
1825 0x80,0x00,0x14,0x05,0x00,0x00,
1826 0x80,0x00,0x14,0x15,0x00,0x00,
1827 0x80,0x00,0x05,0x55,0x00,0x00,
1828 0x80,0x00,0x00,0x05,0x00,0x00,
1829 0x80,0x00,0x00,0x05,0x00,0x00,
1830 0x80,0x00,0x00,0x14,0x00,0x00,
1831 0x80,0x00,0x05,0x50,0x00,0x00,
1832 0x80,0x00,0x00,0x00,0x00,0x00,
1833 0x80,0x00,0x00,0x00,0x00,0x00,
1834 0x80,0x00,0x00,0x00,0x00,0x00,
1835 0x80,0x00,0x00,0x00,0x00,0x00,
1836 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1840 ////////////////////////////////////////////////////////////////////////
1842 void PaintPicDot(unsigned char * p,unsigned char c)
1845 if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black
1846 if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white
1847 if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red
1851 ////////////////////////////////////////////////////////////////////////
1852 // the main emu allocs 128x96x3 bytes, and passes a ptr
1853 // to it in pMem... the plugin has to fill it with
1854 // 8-8-8 bit BGR screen data (Win 24 bit BMP format
1856 // Beware: the func can be called at any time,
1857 // so you have to use the frontbuffer to get a fully
1862 extern char * Xpixels;
1864 void GPUgetScreenPic(unsigned char * pMem)
1867 unsigned short c;unsigned char * pf;int x,y;
1869 float XS=(float)iResX/128;
1870 float YS=(float)iResY/96;
1873 memset(pMem, 0, 128*96*3);
1877 unsigned char * ps=(unsigned char *)Xpixels;
1879 long lPitch=iResX<<2;
1886 sx=*((uint32_t *)((ps)+
1887 (((int)((float)y*YS))*lPitch)+
1888 ((int)((float)x*XS))*4));
1890 *(pf+1)=(sx&0xff00)>>8;
1891 *(pf+2)=(sx&0xff0000)>>16;
1899 /////////////////////////////////////////////////////////////////////
1900 // generic number/border painter
1902 pf=pMem+(103*3); // offset to number rect
1904 for(y=0;y<20;y++) // loop the number rect pixel
1908 c=cFont[lSelectedSlot][x+y*6]; // get 4 char dot infos at once (number depends on selected slot)
1909 PaintPicDot(pf,(c&0xc0)>>6);pf+=3; // paint the dots into the rect
1910 PaintPicDot(pf,(c&0x30)>>4);pf+=3;
1911 PaintPicDot(pf,(c&0x0c)>>2);pf+=3;
1912 PaintPicDot(pf,(c&0x03)); pf+=3;
1914 pf+=104*3; // next rect y line
1917 pf=pMem; // ptr to first pos in 128x96 pic
1918 for(x=0;x<128;x++) // loop top/bottom line
1920 *(pf+(95*128*3))=0x00;*pf++=0x00;
1921 *(pf+(95*128*3))=0x00;*pf++=0x00; // paint it red
1922 *(pf+(95*128*3))=0xff;*pf++=0xff;
1924 pf=pMem; // ptr to first pos
1925 for(y=0;y<96;y++) // loop left/right line
1927 *(pf+(127*3))=0x00;*pf++=0x00;
1928 *(pf+(127*3))=0x00;*pf++=0x00; // paint it red
1929 *(pf+(127*3))=0xff;*pf++=0xff;
1930 pf+=127*3; // offset to next line
1936 ////////////////////////////////////////////////////////////////////////
1937 // func will be called with 128x96x3 BGR data.
1938 // the plugin has to store the data and display
1939 // it in the upper right corner.
1940 // If the func is called with a NULL ptr, you can
1941 // release your picture data and stop displaying
1944 void CALLBACK GPUshowScreenPic(unsigned char * pMem)
1946 DestroyPic(); // destroy old pic data
1947 if(pMem==0) return; // done
1948 CreatePic(pMem); // create new pic... don't free pMem or something like that... just read from it
1951 void CALLBACK GPUsetfix(uint32_t dwFixBits)
1953 dwEmuFixes=dwFixBits;