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 ////////////////////////////////////////////////////////////////////////
138 char * CALLBACK PSEgetLibName(void)
140 return _(libraryName);
143 unsigned long CALLBACK PSEgetLibType(void)
148 unsigned long CALLBACK PSEgetLibVersion(void)
150 return version<<16|revision<<8|build;
153 char * GPUgetLibInfos(void)
155 return _(libraryInfo);
158 ////////////////////////////////////////////////////////////////////////
160 ////////////////////////////////////////////////////////////////////////
162 static char * pGetConfigInfos(int iCfg)
164 char szO[2][4]={"off","on "};
166 char * pB = (char *)malloc(32767);
168 if (!pB) return NULL;
170 //----------------------------------------------------//
171 sprintf(szTxt,"Plugin: %s %d.%d.%d\r\n",libraryName,version,revision,build);
173 sprintf(szTxt,"Author: %s\r\n\r\n",PluginAuthor);
175 //----------------------------------------------------//
176 if(iCfg && iWindowMode)
177 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",LOWORD(iWinSize),HIWORD(iWinSize));
179 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY);
181 if(iWindowMode && iCfg)
182 strcpy(szTxt,"Window mode\r\n");
185 sprintf(szTxt,"Window mode - [%d Bit]\r\n",iDesktopCol);
187 sprintf(szTxt,"Fullscreen - [%d Bit]\r\n",iColDepth);
190 sprintf(szTxt,"Stretch mode: %d\r\n",iUseNoStretchBlt);
192 sprintf(szTxt,"Dither mode: %d\r\n\r\n",iUseDither);
194 //----------------------------------------------------//
195 sprintf(szTxt,"Framerate:\r\n- FPS limit: %s\r\n",szO[UseFrameLimit]);
197 sprintf(szTxt,"- Frame skipping: %s",szO[UseFrameSkip]);
199 if(iFastFwd) strcat(pB," (fast forward)");
202 strcpy(szTxt,"- FPS limit: Auto\r\n\r\n");
203 else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate);
205 //----------------------------------------------------//
207 strcpy(szTxt,"Misc:\r\n- MaintainAspect: ");
208 if(iMaintainAspect == 0) strcat(szTxt,"disabled");
210 if(iMaintainAspect == 1) strcat(szTxt,"enabled");
211 strcat(szTxt,"\r\n");
214 sprintf(szTxt,"- Game fixes: %s [%08x]\r\n",szO[iUseFixes],dwCfgFixes);
216 //----------------------------------------------------//
220 static void DoTextSnapShot(int iNum)
226 sprintf(szTxt,"%s/pcsx%04d.txt",getenv("HOME"),iNum);
228 if ((txtfile = fopen(szTxt, "wb")) == NULL)
231 pB = pGetConfigInfos(0);
234 fwrite(pB, strlen(pB), 1, txtfile);
240 void CALLBACK GPUmakeSnapshot(void)
244 unsigned char header[0x36];
246 unsigned char line[1024 * 3];
248 unsigned char empty[2] = {0,0};
249 unsigned short color;
250 unsigned long snapshotnr = 0;
253 height = PreviousPSXDisplay.DisplayMode.y;
255 size = height * PreviousPSXDisplay.Range.x1 * 3 + 0x38;
257 // fill in proper values for BMP
259 // hardcoded BMP header
260 memset(header, 0, 0x36);
263 header[2] = size & 0xff;
264 header[3] = (size >> 8) & 0xff;
265 header[4] = (size >> 16) & 0xff;
266 header[5] = (size >> 24) & 0xff;
269 header[0x12] = PreviousPSXDisplay.Range.x1 % 256;
270 header[0x13] = PreviousPSXDisplay.Range.x1 / 256;
271 header[0x16] = height % 256;
272 header[0x17] = height / 256;
280 // increment snapshot value & try to get filename
284 sprintf(filename, "%s/pcsx%04ld.bmp", getenv("HOME"), snapshotnr);
286 bmpfile = fopen(filename,"rb");
294 // try opening new snapshot file
295 if ((bmpfile = fopen(filename,"wb")) == NULL)
298 fwrite(header, 0x36, 1, bmpfile);
299 for (i = height + PSXDisplay.DisplayPosition.y - 1; i >= PSXDisplay.DisplayPosition.y; i--)
301 pD = (unsigned char *)&psxVuw[i * 1024 + PSXDisplay.DisplayPosition.x];
302 for (j = 0; j < PreviousPSXDisplay.Range.x1; j++)
304 if (PSXDisplay.RGB24)
306 uint32_t lu = *(uint32_t *)pD;
307 line[j * 3 + 2] = RED(lu);
308 line[j * 3 + 1] = GREEN(lu);
309 line[j * 3 + 0] = BLUE(lu);
315 line[j * 3 + 2] = (color << 3) & 0xf1;
316 line[j * 3 + 1] = (color >> 2) & 0xf1;
317 line[j * 3 + 0] = (color >> 7) & 0xf1;
321 fwrite(line, PreviousPSXDisplay.Range.x1 * 3, 1, bmpfile);
323 fwrite(empty, 0x2, 1, bmpfile);
326 DoTextSnapShot(snapshotnr);
329 ////////////////////////////////////////////////////////////////////////
330 // INIT, will be called after lib load... well, just do some var init...
331 ////////////////////////////////////////////////////////////////////////
333 long CALLBACK GPUinit() // GPU INIT
335 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
337 szDebugText[0] = 0; // init debug text buffer
339 psxVSecure = (unsigned char *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
344 psxVub=psxVSecure + 512 * 1024; // security offset into double sized psx vram!
346 psxVsb=(signed char *)psxVub; // different ways of accessing PSX VRAM
347 psxVsw=(signed short *)psxVub;
348 psxVsl=(int32_t *)psxVub;
349 psxVuw=(unsigned short *)psxVub;
350 psxVul=(uint32_t *)psxVub;
352 psxVuw_eom=psxVuw+1024*iGPUHeight; // pre-calc of end of vram
354 memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024));
355 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
359 PSXDisplay.RGB24 = FALSE; // init some stuff
360 PSXDisplay.Interlaced = FALSE;
361 PSXDisplay.DrawOffset.x = 0;
362 PSXDisplay.DrawOffset.y = 0;
363 PSXDisplay.DisplayMode.x= 320;
364 PSXDisplay.DisplayMode.y= 240;
365 PreviousPSXDisplay.DisplayMode.x= 320;
366 PreviousPSXDisplay.DisplayMode.y= 240;
367 PSXDisplay.Disabled = FALSE;
368 PreviousPSXDisplay.Range.x0 =0;
369 PreviousPSXDisplay.Range.y0 =0;
370 PSXDisplay.Range.x0=0;
371 PSXDisplay.Range.x1=0;
372 PreviousPSXDisplay.DisplayModeNew.y=0;
373 PSXDisplay.Double = 1;
376 DataWriteMode = DR_NORMAL;
378 // Reset transfer values, to prevent mis-transfer of data
379 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
380 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
382 // device initialised already !
383 lGPUstatusRet = 0x14802000;
385 GPUIsReadyForCommands;
386 bDoVSyncUpdate = TRUE;
391 ////////////////////////////////////////////////////////////////////////
392 // Here starts all...
393 ////////////////////////////////////////////////////////////////////////
396 long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
400 pCaptionText=CapText;
403 ReadConfig(); // read registry
407 bIsFirstFrame = TRUE; // we have to init later
408 bDoVSyncUpdate = TRUE;
410 d=ulInitDisplay(); // setup x
413 *disp=d; // wanna x pointer? ok
420 ////////////////////////////////////////////////////////////////////////
422 ////////////////////////////////////////////////////////////////////////
424 long CALLBACK GPUclose() // GPU CLOSE
427 ReleaseKeyHandler(); // de-subclass window
429 CloseDisplay(); // shutdown direct draw
434 ////////////////////////////////////////////////////////////////////////
435 // I shot the sheriff
436 ////////////////////////////////////////////////////////////////////////
438 long CALLBACK GPUshutdown() // GPU SHUTDOWN
442 return 0; // nothinh to do
445 ////////////////////////////////////////////////////////////////////////
446 // Update display (swap buffers)
447 ////////////////////////////////////////////////////////////////////////
449 void updateDisplay(void) // UPDATE DISPLAY
451 if(PSXDisplay.Disabled) // disable?
453 DoClearFrontBuffer(); // -> clear frontbuffer
454 return; // -> and bye
457 if(dwActFixes&32) // pc fps calculation fix
459 if(UseFrameLimit) PCFrameCap(); // -> brake
460 if(UseFrameSkip || ulKeybits&KEY_SHOWFPS)
464 if(ulKeybits&KEY_SHOWFPS) // make fps display buf
466 sprintf(szDispBuf,"FPS %06.1f",fps_cur);
469 if(iFastFwd) // fastfwd ?
471 static int fpscount; UseFrameSkip=1;
473 if(!bSkipNextFrame) DoBufferSwap(); // -> to skip or not to skip
474 if(fpscount%6) // -> skip 6/7 frames
475 bSkipNextFrame = TRUE;
476 else bSkipNextFrame = FALSE;
478 if(fpscount >= (int)fFrameRateHz) fpscount = 0;
482 if(UseFrameSkip) // skip ?
484 if(!bSkipNextFrame) DoBufferSwap(); // -> to skip or not to skip
485 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
487 if((fps_skip < fFrameRateHz) && !(bSkipNextFrame)) // -> skip max one in a row
488 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
489 else bSkipNextFrame = FALSE;
495 DoBufferSwap(); // -> swap
499 ////////////////////////////////////////////////////////////////////////
500 // roughly emulated screen centering bits... not complete !!!
501 ////////////////////////////////////////////////////////////////////////
503 void ChangeDispOffsetsX(void) // X CENTER
507 if(!PSXDisplay.Range.x1) return;
509 l=PreviousPSXDisplay.DisplayMode.x;
511 l*=(long)PSXDisplay.Range.x1;
512 l/=2560;lx=l;l&=0xfffffff8;
514 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
515 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
517 if(lx>=PreviousPSXDisplay.DisplayMode.x)
519 PreviousPSXDisplay.Range.x1=
520 (short)PreviousPSXDisplay.DisplayMode.x;
521 PreviousPSXDisplay.Range.x0=0;
525 PreviousPSXDisplay.Range.x1=(short)l;
527 PreviousPSXDisplay.Range.x0=
528 (PSXDisplay.Range.x0-500)/8;
530 if(PreviousPSXDisplay.Range.x0<0)
531 PreviousPSXDisplay.Range.x0=0;
533 if((PreviousPSXDisplay.Range.x0+lx)>
534 PreviousPSXDisplay.DisplayMode.x)
536 PreviousPSXDisplay.Range.x0=
537 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
538 PreviousPSXDisplay.Range.x0+=2; //???
540 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
542 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
547 // some linux alignment security
548 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
549 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
550 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
551 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
554 DoClearScreenBuffer();
560 ////////////////////////////////////////////////////////////////////////
562 void ChangeDispOffsetsY(void) // Y CENTER
564 int iT,iO=PreviousPSXDisplay.Range.y0;
565 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
569 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>iGPUHeight)
571 int dy1=iGPUHeight-PreviousPSXDisplay.DisplayModeNew.x;
572 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-iGPUHeight;
576 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
580 PSXDisplay.DisplayPosition.y=0;
581 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
584 else PreviousPSXDisplay.DisplayModeNew.y=0;
588 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
590 PSXDisplay.Height = PSXDisplay.Range.y1 -
591 PSXDisplay.Range.y0 +
592 PreviousPSXDisplay.DisplayModeNew.y;
593 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
598 if(PSXDisplay.PAL) iT=48; else iT=28;
600 if(PSXDisplay.Range.y0>=iT)
602 PreviousPSXDisplay.Range.y0=
603 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
604 if(PreviousPSXDisplay.Range.y0<0)
605 PreviousPSXDisplay.Range.y0=0;
606 PSXDisplay.DisplayModeNew.y+=
607 PreviousPSXDisplay.Range.y0;
610 PreviousPSXDisplay.Range.y0=0;
612 if(iO!=PreviousPSXDisplay.Range.y0)
614 DoClearScreenBuffer();
618 ////////////////////////////////////////////////////////////////////////
619 // check if update needed
620 ////////////////////////////////////////////////////////////////////////
622 void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
624 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
625 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
627 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
628 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
631 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
633 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
634 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
635 PreviousPSXDisplay.DisplayMode.x= // previous will hold
636 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
637 PreviousPSXDisplay.DisplayMode.y= // the size of my
638 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
639 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
641 PSXDisplay.DisplayEnd.x= // calc end of display
642 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
643 PSXDisplay.DisplayEnd.y=
644 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
645 PreviousPSXDisplay.DisplayEnd.x=
646 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
647 PreviousPSXDisplay.DisplayEnd.y=
648 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
650 ChangeDispOffsetsX();
652 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
654 if(UseFrameSkip) updateDisplay(); // stupid stuff when frame skipping enabled
657 ////////////////////////////////////////////////////////////////////////
663 void ChangeWindowMode(void) // TOGGLE FULLSCREEN - WINDOW
665 extern Display *display;
666 extern Window window;
667 extern int root_window_id;
670 MotifWmHints mwmhints;
673 screen=DefaultScreenOfDisplay(display);
674 iWindowMode=!iWindowMode;
676 if(!iWindowMode) // fullscreen
678 mwmhints.flags=MWM_HINTS_DECORATIONS;
679 mwmhints.functions=0;
680 mwmhints.decorations=0;
681 mwmhints.input_mode=0;
682 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
683 XChangeProperty(display,window,mwmatom,mwmatom,32,
684 PropModeReplace,(unsigned char *)&mwmhints,5);
686 XResizeWindow(display,window,screen->width,screen->height);
688 hints.min_width = hints.max_width = hints.base_width = screen->width;
689 hints.min_height= hints.max_height = hints.base_height = screen->height;
691 XSetWMNormalHints(display,window,&hints);
696 memset(&xev, 0, sizeof(xev));
697 xev.xclient.type = ClientMessage;
698 xev.xclient.serial = 0;
699 xev.xclient.send_event = 1;
700 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
701 xev.xclient.window = window;
702 xev.xclient.format = 32;
703 xev.xclient.data.l[0] = 1;
704 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
705 xev.xclient.data.l[2] = 0;
706 xev.xclient.data.l[3] = 0;
707 xev.xclient.data.l[4] = 0;
709 XSendEvent(display, root_window_id, 0,
710 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
716 memset(&xev, 0, sizeof(xev));
717 xev.xclient.type = ClientMessage;
718 xev.xclient.serial = 0;
719 xev.xclient.send_event = 1;
720 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
721 xev.xclient.window = window;
722 xev.xclient.format = 32;
723 xev.xclient.data.l[0] = 0;
724 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
725 xev.xclient.data.l[2] = 0;
726 xev.xclient.data.l[3] = 0;
727 xev.xclient.data.l[4] = 0;
729 XSendEvent(display, root_window_id, 0,
730 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
733 mwmhints.flags=MWM_HINTS_DECORATIONS;
734 mwmhints.functions=0;
735 mwmhints.decorations=1;
736 mwmhints.input_mode=0;
737 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
739 //This shouldn't work on 64 bit longs, but it does...in fact, it breaks when I change all the mwmhints to int.
740 //I don't pretend to understand it.
741 XChangeProperty(display,window,mwmatom,mwmatom,32,
742 PropModeReplace,(unsigned char *)&mwmhints,5);
744 hints.flags=USPosition|USSize;
745 hints.base_width = iResX;
746 hints.base_height = iResY;
747 XSetWMNormalHints(display,window,&hints);
749 XResizeWindow(display,window,iResX,iResY);
752 DoClearScreenBuffer();
754 bChangeWinMode=FALSE;
760 ////////////////////////////////////////////////////////////////////////
761 // gun cursor func: player=0-7, x=0-511, y=0-255
762 ////////////////////////////////////////////////////////////////////////
764 void CALLBACK GPUcursor(int iPlayer,int x,int y)
766 if(iPlayer<0) return;
767 if(iPlayer>7) return;
769 usCursorActive|=(1<<iPlayer);
776 ptCursorPoint[iPlayer].x=x;
777 ptCursorPoint[iPlayer].y=y;
780 ////////////////////////////////////////////////////////////////////////
781 // update lace is called evry VSync
782 ////////////////////////////////////////////////////////////////////////
784 void CALLBACK GPUupdateLace(void) // VSYNC
787 lGPUstatusRet^=0x80000000; // odd/even bit
789 if(!(dwActFixes&32)) // std fps limitation?
792 if(PSXDisplay.Interlaced) // interlaced mode?
794 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
799 else // non-interlaced?
801 if(dwActFixes&64) // lazy screen update fix
803 if(bDoLazyUpdate && !UseFrameSkip)
809 if(bDoVSyncUpdate && !UseFrameSkip) // some primitives drawn?
810 updateDisplay(); // -> update display
814 if(bChangeWinMode) ChangeWindowMode(); // toggle full - window mode
816 bDoVSyncUpdate=FALSE; // vsync done
819 ////////////////////////////////////////////////////////////////////////
820 // process read request from GPU status register
821 ////////////////////////////////////////////////////////////////////////
824 uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
828 static int iNumRead=0; // odd/even hack
832 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)
836 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
840 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
843 GPUIsNotReadyForCommands;
848 GPUIsReadyForCommands;
851 return lGPUstatusRet;
854 ////////////////////////////////////////////////////////////////////////
855 // processes data send to GPU status register
856 // these are always single packet commands.
857 ////////////////////////////////////////////////////////////////////////
859 void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
861 uint32_t lCommand=(gdata>>24)&0xff;
863 ulStatusControl[lCommand]=gdata; // store command for freezing
867 //--------------------------------------------------//
870 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
871 lGPUstatusRet=0x14802000;
872 PSXDisplay.Disabled=1;
873 DataWriteMode=DataReadMode=DR_NORMAL;
874 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
875 drawX=drawY=0;drawW=drawH=0;
876 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
878 GlobalTextAddrX=0;GlobalTextAddrY=0;
879 GlobalTextTP=0;GlobalTextABR=0;
880 PSXDisplay.RGB24=FALSE;
881 PSXDisplay.Interlaced=FALSE;
884 //--------------------------------------------------//
885 // dis/enable display
888 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
889 PSXDisplay.Disabled = (gdata & 1);
891 if(PSXDisplay.Disabled)
892 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
893 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
896 //--------------------------------------------------//
897 // setting transfer mode
899 gdata &= 0x03; // Only want the lower two bits
901 DataWriteMode=DataReadMode=DR_NORMAL;
902 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
903 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
904 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
905 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
908 //--------------------------------------------------//
909 // setting display position
912 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
913 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
917 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
918 if (PSXDisplay.DisplayPosition.y & 0x200)
919 PSXDisplay.DisplayPosition.y |= 0xfffffc00;
920 if(PSXDisplay.DisplayPosition.y<0)
922 PreviousPSXDisplay.DisplayModeNew.y=PSXDisplay.DisplayPosition.y/PSXDisplay.Double;
923 PSXDisplay.DisplayPosition.y=0;
925 else PreviousPSXDisplay.DisplayModeNew.y=0;
932 PSXDisplay.DisplayPosition.y = (short)((gdata>>12)&0x3ff);
933 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x3ff);
935 else PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
937 // store the same val in some helper var, we need it on later compares
938 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
940 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>iGPUHeight)
942 int dy1=iGPUHeight-PSXDisplay.DisplayPosition.y;
943 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-iGPUHeight;
947 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
951 PSXDisplay.DisplayPosition.y=0;
952 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
955 else PreviousPSXDisplay.DisplayModeNew.y=0;
958 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
959 PSXDisplay.DisplayEnd.x=
960 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
961 PSXDisplay.DisplayEnd.y=
962 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
963 PreviousPSXDisplay.DisplayEnd.x=
964 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
965 PreviousPSXDisplay.DisplayEnd.y=
966 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
970 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
972 if(UseFrameSkip) updateDisplay();
973 if(dwActFixes&64) bDoLazyUpdate=TRUE;
976 //--------------------------------------------------//
980 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
981 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
983 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
985 ChangeDispOffsetsX();
988 //--------------------------------------------------//
993 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
994 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
996 PreviousPSXDisplay.Height = PSXDisplay.Height;
998 PSXDisplay.Height = PSXDisplay.Range.y1 -
999 PSXDisplay.Range.y0 +
1000 PreviousPSXDisplay.DisplayModeNew.y;
1002 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
1004 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
1006 ChangeDispOffsetsY();
1008 updateDisplayIfChanged();
1012 //--------------------------------------------------//
1013 // setting display infos
1016 PSXDisplay.DisplayModeNew.x =
1017 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
1019 if (gdata&0x04) PSXDisplay.Double=2;
1020 else PSXDisplay.Double=1;
1022 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
1024 ChangeDispOffsetsY();
1026 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
1027 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
1028 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
1030 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
1032 (((gdata & 0x03) << 17) |
1033 ((gdata & 0x40) << 10)); // Set the width bits
1035 if(PSXDisplay.InterlacedNew)
1037 if(!PSXDisplay.Interlaced)
1039 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
1040 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
1042 lGPUstatusRet|=GPUSTATUS_INTERLACED;
1044 else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
1047 lGPUstatusRet|=GPUSTATUS_PAL;
1048 else lGPUstatusRet&=~GPUSTATUS_PAL;
1050 if (PSXDisplay.Double==2)
1051 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
1052 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
1054 if (PSXDisplay.RGB24New)
1055 lGPUstatusRet|=GPUSTATUS_RGB24;
1056 else lGPUstatusRet&=~GPUSTATUS_RGB24;
1058 updateDisplayIfChanged();
1061 //--------------------------------------------------//
1062 // ask about GPU version and other stuff
1070 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
1073 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
1076 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
1080 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
1085 else lGPUdataRet=0x02; // gpu type
1088 case 0x0F: // some bios addr?
1089 lGPUdataRet=0xBFC03720;
1093 //--------------------------------------------------//
1097 ////////////////////////////////////////////////////////////////////////
1098 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
1099 ////////////////////////////////////////////////////////////////////////
1101 __inline void FinishedVRAMWrite(void)
1105 if(!PSXDisplay.Interlaced && UseFrameSkip) // stupid frame skipping
1107 VRAMWrite.Width +=VRAMWrite.x;
1108 VRAMWrite.Height+=VRAMWrite.y;
1109 if(VRAMWrite.x<PSXDisplay.DisplayEnd.x &&
1110 VRAMWrite.Width >=PSXDisplay.DisplayPosition.x &&
1111 VRAMWrite.y<PSXDisplay.DisplayEnd.y &&
1112 VRAMWrite.Height>=PSXDisplay.DisplayPosition.y)
1117 // Set register to NORMAL operation
1118 DataWriteMode = DR_NORMAL;
1119 // Reset transfer values, to prevent mis-transfer of data
1122 VRAMWrite.Width = 0;
1123 VRAMWrite.Height = 0;
1124 VRAMWrite.ColsRemaining = 0;
1125 VRAMWrite.RowsRemaining = 0;
1128 __inline void FinishedVRAMRead(void)
1130 // Set register to NORMAL operation
1131 DataReadMode = DR_NORMAL;
1132 // Reset transfer values, to prevent mis-transfer of data
1136 VRAMRead.Height = 0;
1137 VRAMRead.ColsRemaining = 0;
1138 VRAMRead.RowsRemaining = 0;
1140 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
1141 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
1144 ////////////////////////////////////////////////////////////////////////
1145 // core read from vram
1146 ////////////////////////////////////////////////////////////////////////
1148 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
1152 if(DataReadMode!=DR_VRAMTRANSFER) return;
1156 // adjust read ptr, if necessary
1157 while(VRAMRead.ImagePtr>=psxVuw_eom)
1158 VRAMRead.ImagePtr-=iGPUHeight*1024;
1159 while(VRAMRead.ImagePtr<psxVuw)
1160 VRAMRead.ImagePtr+=iGPUHeight*1024;
1162 for(i=0;i<iSize;i++)
1164 // do 2 seperate 16bit reads for compatibility (wrap issues)
1165 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
1168 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
1170 VRAMRead.ImagePtr++;
1171 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1172 VRAMRead.RowsRemaining --;
1174 if(VRAMRead.RowsRemaining<=0)
1176 VRAMRead.RowsRemaining = VRAMRead.Width;
1177 VRAMRead.ColsRemaining--;
1178 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1179 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1182 // higher 16 bit (always, even if it's an odd width)
1183 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
1184 PUTLE32(pMem, lGPUdataRet); pMem++;
1186 if(VRAMRead.ColsRemaining <= 0)
1187 {FinishedVRAMRead();goto ENDREAD;}
1189 VRAMRead.ImagePtr++;
1190 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1191 VRAMRead.RowsRemaining--;
1192 if(VRAMRead.RowsRemaining<=0)
1194 VRAMRead.RowsRemaining = VRAMRead.Width;
1195 VRAMRead.ColsRemaining--;
1196 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
1197 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
1199 if(VRAMRead.ColsRemaining <= 0)
1200 {FinishedVRAMRead();goto ENDREAD;}
1202 else {FinishedVRAMRead();goto ENDREAD;}
1210 ////////////////////////////////////////////////////////////////////////
1212 uint32_t CALLBACK GPUreadData(void)
1215 GPUreadDataMem(&l,1);
1219 ////////////////////////////////////////////////////////////////////////
1220 // processes data send to GPU data register
1221 // extra table entries for fixing polyline troubles
1222 ////////////////////////////////////////////////////////////////////////
1224 const unsigned char primTableCX[256] =
1241 8,8,8,8,12,12,12,12,
1245 // 5,5,5,5,6,6,6,6, // FLINE
1246 254,254,254,254,254,254,254,254,
1250 // 7,7,7,7,9,9,9,9, // GLINE
1251 255,255,255,255,255,255,255,255,
1255 2,2,2,2,3,3,3,3, // 3=SPRITE1???
1294 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
1296 unsigned char command;
1300 GPUIsNotReadyForCommands;
1304 if(DataWriteMode==DR_VRAMTRANSFER)
1306 BOOL bFinished=FALSE;
1308 // make sure we are in vram
1309 while(VRAMWrite.ImagePtr>=psxVuw_eom)
1310 VRAMWrite.ImagePtr-=iGPUHeight*1024;
1311 while(VRAMWrite.ImagePtr<psxVuw)
1312 VRAMWrite.ImagePtr+=iGPUHeight*1024;
1315 while(VRAMWrite.ColsRemaining>0)
1317 while(VRAMWrite.RowsRemaining>0)
1319 if(i>=iSize) {goto ENDVRAM;}
1322 gdata=GETLE32(pMem); pMem++;
1324 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
1325 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1326 VRAMWrite.RowsRemaining --;
1328 if(VRAMWrite.RowsRemaining <= 0)
1330 VRAMWrite.ColsRemaining--;
1331 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
1333 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
1334 FinishedVRAMWrite();
1335 bDoVSyncUpdate=TRUE;
1338 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1339 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1342 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
1343 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
1344 VRAMWrite.RowsRemaining --;
1347 VRAMWrite.RowsRemaining = VRAMWrite.Width;
1348 VRAMWrite.ColsRemaining--;
1349 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
1353 FinishedVRAMWrite();
1354 if(bFinished) bDoVSyncUpdate=TRUE;
1359 if(DataWriteMode==DR_NORMAL)
1361 void (* *primFunc)(unsigned char *);
1362 if(bSkipNextFrame) primFunc=primTableSkip;
1363 else primFunc=primTableJ;
1367 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
1369 gdata=GETLE32(pMem); pMem++; i++;
1373 command = (unsigned char)((gdata>>24) & 0xff);
1375 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
1377 if(primTableCX[command])
1379 gpuDataC = primTableCX[command];
1380 gpuCommand = command;
1381 PUTLE32(&gpuDataM[0], gdata);
1388 PUTLE32(&gpuDataM[gpuDataP], gdata);
1391 if((gpuDataC==254 && gpuDataP>=3) ||
1392 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
1394 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
1395 gpuDataP=gpuDataC-1;
1401 if(gpuDataP == gpuDataC)
1403 gpuDataC=gpuDataP=0;
1404 primFunc[gpuCommand]((unsigned char *)gpuDataM);
1405 if(dwEmuFixes&0x0001 || dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1406 iFakePrimBusy=4;
\r }
1412 GPUIsReadyForCommands;
1416 ////////////////////////////////////////////////////////////////////////
1418 void CALLBACK GPUwriteData(uint32_t gdata)
1420 PUTLE32(&gdata, gdata);
1421 GPUwriteDataMem(&gdata,1);
1424 ////////////////////////////////////////////////////////////////////////
1425 // this functions will be removed soon (or 'soonish')... not really needed, but some emus want them
1426 ////////////////////////////////////////////////////////////////////////
1428 void CALLBACK GPUsetMode(unsigned long gdata)
1430 // Peops does nothing here...
1431 // DataWriteMode=(gdata&1)?DR_VRAMTRANSFER:DR_NORMAL;
1432 // DataReadMode =(gdata&2)?DR_VRAMTRANSFER:DR_NORMAL;
1435 long CALLBACK GPUgetMode(void)
1439 if(DataWriteMode==DR_VRAMTRANSFER) iT|=0x1;
1440 if(DataReadMode ==DR_VRAMTRANSFER) iT|=0x2;
1444 ////////////////////////////////////////////////////////////////////////
1446 ////////////////////////////////////////////////////////////////////////
1448 long CALLBACK GPUconfigure(void)
1455 ////////////////////////////////////////////////////////////////////////
1456 // sets all kind of act fixes
1457 ////////////////////////////////////////////////////////////////////////
1461 if(dwActFixes&0x02) sDispWidths[4]=384;
1462 else sDispWidths[4]=368;
1465 ////////////////////////////////////////////////////////////////////////
1466 // process gpu commands
1467 ////////////////////////////////////////////////////////////////////////
1469 unsigned long lUsedAddr[3];
1471 __inline BOOL CheckForEndlessLoop(unsigned long laddr)
1473 if(laddr==lUsedAddr[1]) return TRUE;
1474 if(laddr==lUsedAddr[2]) return TRUE;
1476 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1477 else lUsedAddr[2]=laddr;
1482 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1485 unsigned char * baseAddrB;
1486 short count;unsigned int DMACommandCounter = 0;
1490 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1492 baseAddrB = (unsigned char*) baseAddrL;
1496 if(iGPUHeight==512) addr&=0x1FFFFC;
1497 if(DMACommandCounter++ > 2000000) break;
1498 if(CheckForEndlessLoop(addr)) break;
1500 count = baseAddrB[addr+3];
1504 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1506 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1508 while (addr != 0xffffff);
1515 ////////////////////////////////////////////////////////////////////////
1517 ////////////////////////////////////////////////////////////////////////
1520 void CALLBACK GPUabout(void) // ABOUT
1526 ////////////////////////////////////////////////////////////////////////
1527 // We are ever fine ;)
1528 ////////////////////////////////////////////////////////////////////////
1530 long CALLBACK GPUtest(void)
1532 // if test fails this function should return negative value for error (unable to continue)
1533 // and positive value for warning (can continue but output might be crappy)
1537 ////////////////////////////////////////////////////////////////////////
1539 ////////////////////////////////////////////////////////////////////////
1541 typedef struct GPUFREEZETAG
1543 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1544 uint32_t ulStatus; // current gpu status
1545 uint32_t ulControl[256]; // latest control register values
1546 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1549 ////////////////////////////////////////////////////////////////////////
1551 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1553 //----------------------------------------------------//
1554 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1556 long lSlotNum=*((long *)pF);
1557 if(lSlotNum<0) return 0;
1558 if(lSlotNum>8) return 0;
1559 lSelectedSlot=lSlotNum+1;
1563 //----------------------------------------------------//
1564 if(!pF) return 0; // some checks
1565 if(pF->ulFreezeVersion!=1) return 0;
1567 if(ulGetFreezeData==1) // 1: get data
1569 pF->ulStatus=lGPUstatusRet;
1570 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1571 memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2);
1576 if(ulGetFreezeData!=0) return 0; // 0: set data
1578 lGPUstatusRet=pF->ulStatus;
1579 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1580 memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2);
1582 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1584 GPUwriteStatus(ulStatusControl[0]);
1585 GPUwriteStatus(ulStatusControl[1]);
1586 GPUwriteStatus(ulStatusControl[2]);
1587 GPUwriteStatus(ulStatusControl[3]);
1588 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1589 GPUwriteStatus(ulStatusControl[6]);
1590 GPUwriteStatus(ulStatusControl[7]);
1591 GPUwriteStatus(ulStatusControl[5]);
1592 GPUwriteStatus(ulStatusControl[4]);
1597 ////////////////////////////////////////////////////////////////////////
1598 ////////////////////////////////////////////////////////////////////////
1599 ////////////////////////////////////////////////////////////////////////
1600 ////////////////////////////////////////////////////////////////////////
1601 ////////////////////////////////////////////////////////////////////////
1602 ////////////////////////////////////////////////////////////////////////
1604 ////////////////////////////////////////////////////////////////////////
1605 // SAVE STATE DISPLAY STUFF
1606 ////////////////////////////////////////////////////////////////////////
1608 // font 0-9, 24x20 pixels, 1 byte = 4 dots
1614 unsigned char cFont[10][120]=
1617 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1618 0x80,0x00,0x00,0x00,0x00,0x00,
1619 0x80,0x00,0x00,0x00,0x00,0x00,
1620 0x80,0x00,0x00,0x00,0x00,0x00,
1621 0x80,0x00,0x00,0x00,0x00,0x00,
1622 0x80,0x00,0x05,0x54,0x00,0x00,
1623 0x80,0x00,0x14,0x05,0x00,0x00,
1624 0x80,0x00,0x14,0x05,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,0x05,0x54,0x00,0x00,
1632 0x80,0x00,0x00,0x00,0x00,0x00,
1633 0x80,0x00,0x00,0x00,0x00,0x00,
1634 0x80,0x00,0x00,0x00,0x00,0x00,
1635 0x80,0x00,0x00,0x00,0x00,0x00,
1636 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1639 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1640 0x80,0x00,0x00,0x00,0x00,0x00,
1641 0x80,0x00,0x00,0x00,0x00,0x00,
1642 0x80,0x00,0x00,0x00,0x00,0x00,
1643 0x80,0x00,0x00,0x00,0x00,0x00,
1644 0x80,0x00,0x00,0x50,0x00,0x00,
1645 0x80,0x00,0x05,0x50,0x00,0x00,
1646 0x80,0x00,0x00,0x50,0x00,0x00,
1647 0x80,0x00,0x00,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,0x05,0x55,0x00,0x00,
1654 0x80,0x00,0x00,0x00,0x00,0x00,
1655 0x80,0x00,0x00,0x00,0x00,0x00,
1656 0x80,0x00,0x00,0x00,0x00,0x00,
1657 0x80,0x00,0x00,0x00,0x00,0x00,
1658 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1661 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1662 0x80,0x00,0x00,0x00,0x00,0x00,
1663 0x80,0x00,0x00,0x00,0x00,0x00,
1664 0x80,0x00,0x00,0x00,0x00,0x00,
1665 0x80,0x00,0x00,0x00,0x00,0x00,
1666 0x80,0x00,0x05,0x54,0x00,0x00,
1667 0x80,0x00,0x14,0x05,0x00,0x00,
1668 0x80,0x00,0x00,0x05,0x00,0x00,
1669 0x80,0x00,0x00,0x05,0x00,0x00,
1670 0x80,0x00,0x00,0x14,0x00,0x00,
1671 0x80,0x00,0x00,0x50,0x00,0x00,
1672 0x80,0x00,0x01,0x40,0x00,0x00,
1673 0x80,0x00,0x05,0x00,0x00,0x00,
1674 0x80,0x00,0x14,0x00,0x00,0x00,
1675 0x80,0x00,0x15,0x55,0x00,0x00,
1676 0x80,0x00,0x00,0x00,0x00,0x00,
1677 0x80,0x00,0x00,0x00,0x00,0x00,
1678 0x80,0x00,0x00,0x00,0x00,0x00,
1679 0x80,0x00,0x00,0x00,0x00,0x00,
1680 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1683 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1684 0x80,0x00,0x00,0x00,0x00,0x00,
1685 0x80,0x00,0x00,0x00,0x00,0x00,
1686 0x80,0x00,0x00,0x00,0x00,0x00,
1687 0x80,0x00,0x00,0x00,0x00,0x00,
1688 0x80,0x00,0x05,0x54,0x00,0x00,
1689 0x80,0x00,0x14,0x05,0x00,0x00,
1690 0x80,0x00,0x00,0x05,0x00,0x00,
1691 0x80,0x00,0x00,0x05,0x00,0x00,
1692 0x80,0x00,0x01,0x54,0x00,0x00,
1693 0x80,0x00,0x00,0x05,0x00,0x00,
1694 0x80,0x00,0x00,0x05,0x00,0x00,
1695 0x80,0x00,0x00,0x05,0x00,0x00,
1696 0x80,0x00,0x14,0x05,0x00,0x00,
1697 0x80,0x00,0x05,0x54,0x00,0x00,
1698 0x80,0x00,0x00,0x00,0x00,0x00,
1699 0x80,0x00,0x00,0x00,0x00,0x00,
1700 0x80,0x00,0x00,0x00,0x00,0x00,
1701 0x80,0x00,0x00,0x00,0x00,0x00,
1702 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1705 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1706 0x80,0x00,0x00,0x00,0x00,0x00,
1707 0x80,0x00,0x00,0x00,0x00,0x00,
1708 0x80,0x00,0x00,0x00,0x00,0x00,
1709 0x80,0x00,0x00,0x00,0x00,0x00,
1710 0x80,0x00,0x00,0x14,0x00,0x00,
1711 0x80,0x00,0x00,0x54,0x00,0x00,
1712 0x80,0x00,0x01,0x54,0x00,0x00,
1713 0x80,0x00,0x01,0x54,0x00,0x00,
1714 0x80,0x00,0x05,0x14,0x00,0x00,
1715 0x80,0x00,0x14,0x14,0x00,0x00,
1716 0x80,0x00,0x15,0x55,0x00,0x00,
1717 0x80,0x00,0x00,0x14,0x00,0x00,
1718 0x80,0x00,0x00,0x14,0x00,0x00,
1719 0x80,0x00,0x00,0x55,0x00,0x00,
1720 0x80,0x00,0x00,0x00,0x00,0x00,
1721 0x80,0x00,0x00,0x00,0x00,0x00,
1722 0x80,0x00,0x00,0x00,0x00,0x00,
1723 0x80,0x00,0x00,0x00,0x00,0x00,
1724 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1727 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1728 0x80,0x00,0x00,0x00,0x00,0x00,
1729 0x80,0x00,0x00,0x00,0x00,0x00,
1730 0x80,0x00,0x00,0x00,0x00,0x00,
1731 0x80,0x00,0x00,0x00,0x00,0x00,
1732 0x80,0x00,0x15,0x55,0x00,0x00,
1733 0x80,0x00,0x14,0x00,0x00,0x00,
1734 0x80,0x00,0x14,0x00,0x00,0x00,
1735 0x80,0x00,0x14,0x00,0x00,0x00,
1736 0x80,0x00,0x15,0x54,0x00,0x00,
1737 0x80,0x00,0x00,0x05,0x00,0x00,
1738 0x80,0x00,0x00,0x05,0x00,0x00,
1739 0x80,0x00,0x00,0x05,0x00,0x00,
1740 0x80,0x00,0x14,0x05,0x00,0x00,
1741 0x80,0x00,0x05,0x54,0x00,0x00,
1742 0x80,0x00,0x00,0x00,0x00,0x00,
1743 0x80,0x00,0x00,0x00,0x00,0x00,
1744 0x80,0x00,0x00,0x00,0x00,0x00,
1745 0x80,0x00,0x00,0x00,0x00,0x00,
1746 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1749 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1750 0x80,0x00,0x00,0x00,0x00,0x00,
1751 0x80,0x00,0x00,0x00,0x00,0x00,
1752 0x80,0x00,0x00,0x00,0x00,0x00,
1753 0x80,0x00,0x00,0x00,0x00,0x00,
1754 0x80,0x00,0x01,0x54,0x00,0x00,
1755 0x80,0x00,0x05,0x00,0x00,0x00,
1756 0x80,0x00,0x14,0x00,0x00,0x00,
1757 0x80,0x00,0x14,0x00,0x00,0x00,
1758 0x80,0x00,0x15,0x54,0x00,0x00,
1759 0x80,0x00,0x15,0x05,0x00,0x00,
1760 0x80,0x00,0x14,0x05,0x00,0x00,
1761 0x80,0x00,0x14,0x05,0x00,0x00,
1762 0x80,0x00,0x14,0x05,0x00,0x00,
1763 0x80,0x00,0x05,0x54,0x00,0x00,
1764 0x80,0x00,0x00,0x00,0x00,0x00,
1765 0x80,0x00,0x00,0x00,0x00,0x00,
1766 0x80,0x00,0x00,0x00,0x00,0x00,
1767 0x80,0x00,0x00,0x00,0x00,0x00,
1768 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1771 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1772 0x80,0x00,0x00,0x00,0x00,0x00,
1773 0x80,0x00,0x00,0x00,0x00,0x00,
1774 0x80,0x00,0x00,0x00,0x00,0x00,
1775 0x80,0x00,0x00,0x00,0x00,0x00,
1776 0x80,0x00,0x15,0x55,0x00,0x00,
1777 0x80,0x00,0x14,0x05,0x00,0x00,
1778 0x80,0x00,0x00,0x14,0x00,0x00,
1779 0x80,0x00,0x00,0x14,0x00,0x00,
1780 0x80,0x00,0x00,0x50,0x00,0x00,
1781 0x80,0x00,0x00,0x50,0x00,0x00,
1782 0x80,0x00,0x01,0x40,0x00,0x00,
1783 0x80,0x00,0x01,0x40,0x00,0x00,
1784 0x80,0x00,0x05,0x00,0x00,0x00,
1785 0x80,0x00,0x05,0x00,0x00,0x00,
1786 0x80,0x00,0x00,0x00,0x00,0x00,
1787 0x80,0x00,0x00,0x00,0x00,0x00,
1788 0x80,0x00,0x00,0x00,0x00,0x00,
1789 0x80,0x00,0x00,0x00,0x00,0x00,
1790 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1793 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1794 0x80,0x00,0x00,0x00,0x00,0x00,
1795 0x80,0x00,0x00,0x00,0x00,0x00,
1796 0x80,0x00,0x00,0x00,0x00,0x00,
1797 0x80,0x00,0x00,0x00,0x00,0x00,
1798 0x80,0x00,0x05,0x54,0x00,0x00,
1799 0x80,0x00,0x14,0x05,0x00,0x00,
1800 0x80,0x00,0x14,0x05,0x00,0x00,
1801 0x80,0x00,0x14,0x05,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,0x14,0x05,0x00,0x00,
1807 0x80,0x00,0x05,0x54,0x00,0x00,
1808 0x80,0x00,0x00,0x00,0x00,0x00,
1809 0x80,0x00,0x00,0x00,0x00,0x00,
1810 0x80,0x00,0x00,0x00,0x00,0x00,
1811 0x80,0x00,0x00,0x00,0x00,0x00,
1812 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1815 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
1816 0x80,0x00,0x00,0x00,0x00,0x00,
1817 0x80,0x00,0x00,0x00,0x00,0x00,
1818 0x80,0x00,0x00,0x00,0x00,0x00,
1819 0x80,0x00,0x00,0x00,0x00,0x00,
1820 0x80,0x00,0x05,0x54,0x00,0x00,
1821 0x80,0x00,0x14,0x05,0x00,0x00,
1822 0x80,0x00,0x14,0x05,0x00,0x00,
1823 0x80,0x00,0x14,0x05,0x00,0x00,
1824 0x80,0x00,0x14,0x15,0x00,0x00,
1825 0x80,0x00,0x05,0x55,0x00,0x00,
1826 0x80,0x00,0x00,0x05,0x00,0x00,
1827 0x80,0x00,0x00,0x05,0x00,0x00,
1828 0x80,0x00,0x00,0x14,0x00,0x00,
1829 0x80,0x00,0x05,0x50,0x00,0x00,
1830 0x80,0x00,0x00,0x00,0x00,0x00,
1831 0x80,0x00,0x00,0x00,0x00,0x00,
1832 0x80,0x00,0x00,0x00,0x00,0x00,
1833 0x80,0x00,0x00,0x00,0x00,0x00,
1834 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
1838 ////////////////////////////////////////////////////////////////////////
1840 void PaintPicDot(unsigned char * p,unsigned char c)
1843 if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;} // black
1844 if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;} // white
1845 if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;} // red
1849 ////////////////////////////////////////////////////////////////////////
1850 // the main emu allocs 128x96x3 bytes, and passes a ptr
1851 // to it in pMem... the plugin has to fill it with
1852 // 8-8-8 bit BGR screen data (Win 24 bit BMP format
1854 // Beware: the func can be called at any time,
1855 // so you have to use the frontbuffer to get a fully
1860 extern char * Xpixels;
1862 void GPUgetScreenPic(unsigned char * pMem)
1865 unsigned short c;unsigned char * pf;int x,y;
1867 float XS=(float)iResX/128;
1868 float YS=(float)iResY/96;
1871 memset(pMem, 0, 128*96*3);
1875 unsigned char * ps=(unsigned char *)Xpixels;
1877 long lPitch=iResX<<2;
1884 sx=*((uint32_t *)((ps)+
1885 (((int)((float)y*YS))*lPitch)+
1886 ((int)((float)x*XS))*4));
1888 *(pf+1)=(sx&0xff00)>>8;
1889 *(pf+2)=(sx&0xff0000)>>16;
1897 /////////////////////////////////////////////////////////////////////
1898 // generic number/border painter
1900 pf=pMem+(103*3); // offset to number rect
1902 for(y=0;y<20;y++) // loop the number rect pixel
1906 c=cFont[lSelectedSlot][x+y*6]; // get 4 char dot infos at once (number depends on selected slot)
1907 PaintPicDot(pf,(c&0xc0)>>6);pf+=3; // paint the dots into the rect
1908 PaintPicDot(pf,(c&0x30)>>4);pf+=3;
1909 PaintPicDot(pf,(c&0x0c)>>2);pf+=3;
1910 PaintPicDot(pf,(c&0x03)); pf+=3;
1912 pf+=104*3; // next rect y line
1915 pf=pMem; // ptr to first pos in 128x96 pic
1916 for(x=0;x<128;x++) // loop top/bottom line
1918 *(pf+(95*128*3))=0x00;*pf++=0x00;
1919 *(pf+(95*128*3))=0x00;*pf++=0x00; // paint it red
1920 *(pf+(95*128*3))=0xff;*pf++=0xff;
1922 pf=pMem; // ptr to first pos
1923 for(y=0;y<96;y++) // loop left/right line
1925 *(pf+(127*3))=0x00;*pf++=0x00;
1926 *(pf+(127*3))=0x00;*pf++=0x00; // paint it red
1927 *(pf+(127*3))=0xff;*pf++=0xff;
1928 pf+=127*3; // offset to next line
1934 ////////////////////////////////////////////////////////////////////////
1935 // func will be called with 128x96x3 BGR data.
1936 // the plugin has to store the data and display
1937 // it in the upper right corner.
1938 // If the func is called with a NULL ptr, you can
1939 // release your picture data and stop displaying
1942 void CALLBACK GPUshowScreenPic(unsigned char * pMem)
1944 DestroyPic(); // destroy old pic data
1945 if(pMem==0) return; // done
1946 CreatePic(pMem); // create new pic... don't free pMem or something like that... just read from it
1949 void CALLBACK GPUsetfix(uint32_t dwFixBits)
1951 dwEmuFixes=dwFixBits;