1 /***************************************************************************
\r
4 begin : Sun Mar 08 2009
\r
5 copyright : (C) 1999-2009 by Pete Bernert
\r
6 email : BlackDove@addcom.de
\r
7 ***************************************************************************/
\r
9 /***************************************************************************
\r
11 * This program is free software; you can redistribute it and/or modify *
\r
12 * it under the terms of the GNU General Public License as published by *
\r
13 * the Free Software Foundation; either version 2 of the License, or *
\r
14 * (at your option) any later version. See also the license.txt file for *
\r
15 * additional informations. *
\r
17 ***************************************************************************/
\r
19 // !!! enable this, if Linux XF86VidMode is not supported:
\r
26 #include <X11/extensions/xf86vmode.h>
\r
27 static XF86VidModeModeInfo **modes=0;
\r
28 static int iOldMode=0;
\r
33 #include "externals.h"
\r
38 #include "psemu_plugin_defs.h"
\r
39 #include "texture.h"
\r
44 #include <libintl.h>
\r
46 #define _(x) gettext(x)
\r
53 ////////////////////////////////////////////////////////////////////////
\r
54 // PPDK developer must change libraryName field and can change revision and build
\r
55 ////////////////////////////////////////////////////////////////////////
\r
57 const unsigned char version = 1; // do not touch - library for PSEmu 1.x
\r
58 const unsigned char revision = 1;
\r
59 const unsigned char build = 78;
\r
61 static char *libraryName = N_("OpenGL Driver");
\r
63 static char *PluginAuthor = N_("Pete Bernert");
\r
64 static char *libraryInfo = N_("Based on P.E.Op.S. MesaGL Driver V1.78\nCoded by Pete Bernert\n");
\r
66 ////////////////////////////////////////////////////////////////////////
\r
67 // memory image of the PSX vram
\r
68 ////////////////////////////////////////////////////////////////////////
\r
70 unsigned char *psxVSecure;
\r
71 unsigned char *psxVub;
\r
72 signed char *psxVsb;
\r
73 unsigned short *psxVuw;
\r
74 unsigned short *psxVuw_eom;
\r
75 signed short *psxVsw;
\r
79 // macro for easy access to packet information
\r
80 #define GPUCOMMAND(x) ((x>>24) & 0xff)
\r
83 BOOL bNeedInterlaceUpdate=FALSE;
\r
84 BOOL bNeedRGB24Update=FALSE;
\r
85 BOOL bChangeWinMode=FALSE;
\r
87 uint32_t ulStatusControl[256];
\r
89 ////////////////////////////////////////////////////////////////////////
\r
91 ////////////////////////////////////////////////////////////////////////
\r
93 static int GPUdataRet;
\r
97 uint32_t dwGPUVersion = 0;
\r
98 int iGPUHeight = 512;
\r
99 int iGPUHeightMask = 511;
\r
100 int GlobalTextIL = 0;
\r
101 int iTileCheat = 0;
\r
103 static uint32_t gpuDataM[256];
\r
104 static unsigned char gpuCommand = 0;
\r
105 static int gpuDataC = 0;
\r
106 static int gpuDataP = 0;
\r
108 VRAMLoad_t VRAMWrite;
\r
109 VRAMLoad_t VRAMRead;
\r
110 int iDataWriteMode;
\r
114 int lClearOnSwapColor;
\r
115 BOOL bSkipNextFrame = FALSE;
\r
121 // possible psx display widths
\r
122 short dispWidths[8] = {256,320,512,640,368,384,512,640};
\r
124 PSXDisplay_t PSXDisplay;
\r
125 PSXDisplay_t PreviousPSXDisplay;
\r
127 short imageX0,imageX1;
\r
128 short imageY0,imageY1;
\r
129 BOOL bDisplayNotSet = TRUE;
\r
130 GLuint uiScanLine=0;
\r
131 int iUseScanLines=0;
\r
132 int lSelectedSlot=0;
\r
133 unsigned char * pGfxCardScreen=0;
\r
137 int iNoScreenSaver=0;
\r
138 uint32_t ulGPUInfoVals[16];
\r
139 int iFakePrimBusy = 0;
\r
140 int iRumbleVal = 0;
\r
141 int iRumbleTime = 0;
\r
143 ////////////////////////////////////////////////////////////////////////
\r
144 // stuff to make this a true PDK module
\r
145 ////////////////////////////////////////////////////////////////////////
\r
147 char * CALLBACK PSEgetLibName(void)
\r
149 return _(libraryName);
\r
152 unsigned long CALLBACK PSEgetLibType(void)
\r
157 unsigned long CALLBACK PSEgetLibVersion(void)
\r
159 return version<<16|revision<<8|build;
\r
162 char * GPUgetLibInfos(void)
\r
164 return _(libraryInfo);
\r
167 ////////////////////////////////////////////////////////////////////////
\r
168 // snapshot funcs (saves screen to bitmap / text infos into file)
\r
169 ////////////////////////////////////////////////////////////////////////
\r
171 char * GetConfigInfos(int hW)
\r
173 char szO[2][4]={"off","on "};
\r
175 char * pB=(char *)malloc(32767);
\r
177 if(!pB) return NULL;
\r
179 //----------------------------------------------------//
\r
180 sprintf(szTxt,"Plugin: %s %d.%d.%d\r\n",libraryName,version,revision,build);
\r
182 sprintf(szTxt,"Author: %s\r\n",PluginAuthor);
\r
185 sprintf(szTxt,"Card vendor: %s\r\n",(char *)glGetString(GL_VENDOR));
\r
187 sprintf(szTxt,"GFX card: %s\r\n",(char *)glGetString(GL_RENDERER));
\r
189 sprintf(szTxt,"OGL version: %s\r\n\r\n",(char *)glGetString(GL_VERSION));
\r
191 //strcat(pB,(char *)glGetString(GL_EXTENSIONS));
\r
192 //strcat(pB,"\r\n\r\n");
\r
194 if(hW && bWindowMode)
\r
195 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",LOWORD(iWinSize),HIWORD(iWinSize));
\r
197 sprintf(szTxt,"Resolution/Color:\r\n- %dx%d ",iResX,iResY);
\r
199 if(bWindowMode) sprintf(szTxt,"Window mode\r\n");
\r
202 sprintf(szTxt,"Fullscreen ");
\r
204 if(bChangeRes) sprintf(szTxt,"- Desktop changing [%d Bit]\r\n",iColDepth);
\r
205 else sprintf(szTxt,"- NO desktop changing\r\n");
\r
209 if(iForceVSync>=0) sprintf(szTxt,"- V-Sync: %s\r\n",szO[iForceVSync]);
\r
210 else strcpy(szTxt,"- V-Sync: Driver\r\n");
\r
212 sprintf(szTxt,"- Keep psx aspect ratio: %s\r\n\r\n",szO[bKeepRatio]);
\r
214 //----------------------------------------------------//
\r
215 strcpy(szTxt,"Textures:\r\n- ");
\r
216 if(iTexQuality==0) strcat(szTxt,"Default");
\r
217 else if(iTexQuality==1) strcat(szTxt,"R4G4B4A4");
\r
218 else if(iTexQuality==2) strcat(szTxt,"R5G5B5A1");
\r
219 else if(iTexQuality==3) strcat(szTxt,"R8G8A8A8");
\r
220 else if(iTexQuality==4) strcat(szTxt,"B8G8R8A8");
\r
221 if(!hW && bGLExt) strcat(szTxt," (packed pixels)\r\n");
\r
222 else strcat(szTxt,"\r\n");
\r
226 sprintf(szTxt,"- Filtering: %d - edge clamping ",iFilterType);
\r
227 if(iClampType==GL_TO_EDGE_CLAMP) strcat(szTxt,"supported\r\n");
\r
228 else strcat(szTxt,"NOT supported\r\n");
\r
230 else sprintf(szTxt,"- iFiltering: %d\r\n",iFilterType);
\r
232 sprintf(szTxt,"- Hi-Res textures: %d\r\n",iHiResTextures);
\r
236 sprintf(szTxt,"- Palettized tex windows: %s\r\n",szO[iUsePalTextures]);
\r
239 sprintf(szTxt,"- VRam size: %d MBytes",iVRamSize);
\r
241 sprintf(szTxt+strlen(szTxt)," - %d textures usable\r\n\r\n",iSortTexCnt);
\r
242 else strcat(szTxt,"\r\n\r\n");
\r
244 //----------------------------------------------------//
\r
245 sprintf(szTxt,"Framerate:\r\n- FPS limitation: %s\r\n",szO[bUseFrameLimit]);
\r
247 sprintf(szTxt,"- Frame skipping: %s\r\n",szO[bUseFrameSkip]);
\r
250 strcpy(szTxt,"- FPS limit: Auto\r\n\r\n");
\r
251 else sprintf(szTxt,"- FPS limit: %.1f\r\n\r\n",fFrameRate);
\r
253 //----------------------------------------------------//
\r
254 sprintf(szTxt,"Compatibility:\r\n- Offscreen drawing: %d\r\n",iOffscreenDrawing);
\r
256 sprintf(szTxt,"- Framebuffer texture: %d",iFrameTexType);
\r
257 if(!hW && iFrameTexType==2)
\r
259 if(gTexFrameName) strcat(szTxt," - texture created\r\n");
\r
260 else strcat(szTxt," - not used yet\r\n");
\r
262 else strcat(szTxt,"\r\n");
\r
264 sprintf(szTxt,"- Framebuffer access: %d\r\n",iFrameReadType);
\r
266 sprintf(szTxt,"- Alpha multipass: %s\r\n",szO[bOpaquePass]);
\r
268 sprintf(szTxt,"- Mask bit: %s\r\n",szO[iUseMask]);
\r
270 sprintf(szTxt,"- Advanced blending: %s",szO[bAdvancedBlend]);
\r
271 if(!hW && bAdvancedBlend)
\r
273 if(bGLBlend) strcat(szTxt," (hardware)\r\n");
\r
274 else strcat(szTxt," (software)\r\n");
\r
276 else strcat(szTxt,"\r\n");
\r
281 strcpy(szTxt,"- Subtractive blending: ");
\r
282 if(glBlendEquationEXTEx)
\r
284 if(bUseMultiPass) strcat(szTxt,"supported, but not used!");
\r
285 else strcat(szTxt,"activated");
\r
287 else strcat(szTxt," NOT supported!");
\r
288 strcat(szTxt,"\r\n\r\n");
\r
290 else strcpy(szTxt,"\r\n");
\r
293 //----------------------------------------------------//
\r
294 sprintf(szTxt,"Misc:\r\n- Scanlines: %s",szO[iUseScanLines]);
\r
296 if(iUseScanLines) sprintf(szTxt," [%d]\r\n",iScanBlend);
\r
297 else strcpy(szTxt,"\r\n");
\r
299 sprintf(szTxt,"- Line mode: %s\r\n",szO[bUseLines]);
\r
301 // sprintf(szTxt,"- Line AA: %s\r\n",szO[bUseAntiAlias]);
\r
302 // fwrite(szTxt,lstrlen(szTxt),1,txtfile);
\r
303 sprintf(szTxt,"- Unfiltered FB: %s\r\n",szO[bUseFastMdec]);
\r
305 sprintf(szTxt,"- 15 bit FB: %s\r\n",szO[bUse15bitMdec]);
\r
307 sprintf(szTxt,"- Dithering: %s\r\n",szO[bDrawDither]);
\r
309 sprintf(szTxt,"- Screen smoothing: %s",szO[iBlurBuffer]);
\r
311 if(!hW && iBlurBuffer)
\r
313 if(gTexBlurName) strcat(pB," - supported\r\n");
\r
314 else strcat(pB," - not supported\r\n");
\r
316 else strcat(pB,"\r\n");
\r
317 sprintf(szTxt,"- Game fixes: %s [%08x]\r\n",szO[bUseFixes],dwCfgFixes);
\r
319 //----------------------------------------------------//
\r
323 ////////////////////////////////////////////////////////////////////////
\r
324 // save text infos to file
\r
325 ////////////////////////////////////////////////////////////////////////
\r
327 void DoTextSnapShot(int iNum)
\r
329 FILE *txtfile;char szTxt[256];char * pB;
\r
331 sprintf(szTxt,"%s/pcsx%04d.txt",getenv("HOME"),iNum);
\r
333 if((txtfile=fopen(szTxt,"wb"))==NULL)
\r
336 pB=GetConfigInfos(0);
\r
339 fwrite(pB,strlen(pB),1,txtfile);
\r
345 ////////////////////////////////////////////////////////////////////////
\r
346 // saves screen bitmap to file
\r
347 ////////////////////////////////////////////////////////////////////////
\r
349 void DoSnapShot(void)
\r
351 unsigned char * snapshotdumpmem=NULL,* p,c;
\r
352 FILE *bmpfile;char filename[256];
\r
353 unsigned char header[0x36];int size;
\r
354 unsigned char empty[2]={0,0};int i;
\r
355 unsigned int snapshotnr = 0;
\r
362 SnapHeigth = iResY;
\r
364 size=SnapWidth * SnapHeigth * 3 + 0x38;
\r
366 if((snapshotdumpmem=(unsigned char *)
\r
367 malloc(SnapWidth*SnapHeigth*3))==NULL)
\r
370 // fill in proper values for BMP
\r
371 for(i=0;i<0x36;i++) header[i]=0;
\r
374 header[2]=(unsigned char)(size&0xff);
\r
375 header[3]=(unsigned char)((size>>8)&0xff);
\r
376 header[4]=(unsigned char)((size>>16)&0xff);
\r
377 header[5]=(unsigned char)((size>>24)&0xff);
\r
380 header[0x12]=(unsigned char)(SnapWidth%256);
\r
381 header[0x13]=(unsigned char)(SnapWidth/256);
\r
382 header[0x16]=(unsigned char)(SnapHeigth%256);
\r
383 header[0x17]=(unsigned char)(SnapHeigth/256);
\r
391 // increment snapshot value
\r
396 sprintf(filename,"%s/pcsx%04d.bmp",getenv("HOME"),snapshotnr);
\r
397 bmpfile=fopen(filename,"rb");
\r
398 if(bmpfile==NULL)break;
\r
400 if(snapshotnr==9999) break;
\r
404 // try opening new snapshot file
\r
405 if((bmpfile=fopen(filename,"wb"))==NULL)
\r
406 {free(snapshotdumpmem);return;}
\r
408 fwrite(header,0x36,1,bmpfile);
\r
410 glReadPixels(0,0,SnapWidth,SnapHeigth,GL_RGB,
\r
411 GL_UNSIGNED_BYTE,snapshotdumpmem);
\r
413 size=SnapWidth * SnapHeigth;
\r
415 for(i=0;i<size;i++,p+=3)
\r
416 {c=*p;*p=*(p+2);*(p+2)=c;}
\r
418 fwrite(snapshotdumpmem,size*3,1,bmpfile);
\r
419 fwrite(empty,0x2,1,bmpfile);
\r
421 free(snapshotdumpmem);
\r
423 DoTextSnapShot(snapshotnr);
\r
426 void CALLBACK GPUmakeSnapshot(void)
\r
431 ////////////////////////////////////////////////////////////////////////
\r
432 // GPU INIT... here starts it all (first func called by emu)
\r
433 ////////////////////////////////////////////////////////////////////////
\r
435 long CALLBACK GPUinit()
\r
437 memset(ulStatusControl,0,256*sizeof(uint32_t));
\r
439 // different ways of accessing PSX VRAM
\r
441 psxVSecure=(unsigned char *)malloc((iGPUHeight*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
\r
442 if(!psxVSecure) return -1;
\r
444 psxVub=psxVSecure+512*1024; // security offset into double sized psx vram!
\r
445 psxVsb=(signed char *)psxVub;
\r
446 psxVsw=(signed short *)psxVub;
\r
447 psxVsl=(signed int *)psxVub;
\r
448 psxVuw=(unsigned short *)psxVub;
\r
449 psxVul=(uint32_t *)psxVub;
\r
451 psxVuw_eom=psxVuw+1024*iGPUHeight; // pre-calc of end of vram
\r
453 memset(psxVSecure,0x00,(iGPUHeight*2)*1024 + (1024*1024));
\r
454 memset(ulGPUInfoVals,0x00,16*sizeof(uint32_t));
\r
456 InitFrameCap(); // init frame rate stuff
\r
458 PSXDisplay.RGB24 = 0; // init vars
\r
459 PreviousPSXDisplay.RGB24= 0;
\r
460 PSXDisplay.Interlaced = 0;
\r
461 PSXDisplay.InterlacedTest=0;
\r
462 PSXDisplay.DrawOffset.x = 0;
\r
463 PSXDisplay.DrawOffset.y = 0;
\r
464 PSXDisplay.DrawArea.x0 = 0;
\r
465 PSXDisplay.DrawArea.y0 = 0;
\r
466 PSXDisplay.DrawArea.x1 = 320;
\r
467 PSXDisplay.DrawArea.y1 = 240;
\r
468 PSXDisplay.DisplayMode.x= 320;
\r
469 PSXDisplay.DisplayMode.y= 240;
\r
470 PSXDisplay.Disabled = FALSE;
\r
471 PreviousPSXDisplay.Range.x0 =0;
\r
472 PreviousPSXDisplay.Range.x1 =0;
\r
473 PreviousPSXDisplay.Range.y0 =0;
\r
474 PreviousPSXDisplay.Range.y1 =0;
\r
475 PSXDisplay.Range.x0=0;
\r
476 PSXDisplay.Range.x1=0;
\r
477 PSXDisplay.Range.y0=0;
\r
478 PSXDisplay.Range.y1=0;
\r
479 PreviousPSXDisplay.DisplayPosition.x = 1;
\r
480 PreviousPSXDisplay.DisplayPosition.y = 1;
\r
481 PSXDisplay.DisplayPosition.x = 1;
\r
482 PSXDisplay.DisplayPosition.y = 1;
\r
483 PreviousPSXDisplay.DisplayModeNew.y=0;
\r
484 PSXDisplay.Double=1;
\r
487 PSXDisplay.DisplayModeNew.x=0;
\r
488 PSXDisplay.DisplayModeNew.y=0;
\r
490 //PreviousPSXDisplay.Height = PSXDisplay.Height = 239;
\r
492 iDataWriteMode = DR_NORMAL;
\r
494 // Reset transfer values, to prevent mis-transfer of data
\r
495 memset(&VRAMWrite,0,sizeof(VRAMLoad_t));
\r
496 memset(&VRAMRead,0,sizeof(VRAMLoad_t));
\r
498 // device initialised already !
\r
499 //lGPUstatusRet = 0x74000000;
\r
501 STATUSREG = 0x14802000;
\r
503 GPUIsReadyForCommands;
\r
508 ////////////////////////////////////////////////////////////////////////
\r
509 // GPU OPEN: funcs to open up the gpu display (Windows)
\r
510 ////////////////////////////////////////////////////////////////////////
\r
512 ////////////////////////////////////////////////////////////////////////
\r
513 // LINUX GPU OPEN: func to open up the gpu display (X stuff)
\r
514 // please note: in linux we are creating our own display, and we return
\r
515 // the display ID to the main emu... that's cleaner
\r
516 ////////////////////////////////////////////////////////////////////////
\r
518 char * pCaptionText=0;
\r
522 static Cursor cursor;
\r
523 static XVisualInfo *myvisual;
\r
524 static Colormap colormap;
\r
525 static Window window;
\r
527 static int bModeChanged=0;
\r
531 #define MWM_HINTS_DECORATIONS 2
\r
538 static int dbdepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,GLX_DEPTH_SIZE,16,None};
\r
539 static int dbnodepat[]={GLX_RGBA,GLX_DOUBLEBUFFER,None};
\r
540 static GLXContext cx;
\r
544 ////////////////////////////////////////////////////////////////////////
\r
546 void osd_close_display (void) // close display
\r
548 if(display) // display exists?
\r
550 glXDestroyContext(display,cx); // -> kill context
\r
551 XFreeColormap(display, colormap); // -> kill colormap
\r
552 XSync(display,False); // -> sync events
\r
555 if(bModeChanged) // -> repair screen mode
\r
557 int myscreen=DefaultScreen(display);
\r
558 XF86VidModeSwitchToMode(display,myscreen, // --> switch mode back
\r
560 XF86VidModeSetViewPort(display,myscreen,0,0); // --> set viewport upperleft
\r
561 free(modes); // --> finally kill mode infos
\r
562 bModeChanged=0; // --> done
\r
566 XCloseDisplay(display); // -> close display
\r
570 ////////////////////////////////////////////////////////////////////////
\r
572 void sysdep_create_display(void) // create display
\r
574 XSetWindowAttributes winattr;float fxgamma=2;
\r
575 int myscreen;char gammastr[14];
\r
576 Screen * screen;XEvent event;
\r
577 XSizeHints hints;XWMHints wm_hints;
\r
578 MotifWmHints mwmhints;Atom mwmatom;Atom delwindow;
\r
581 glxfx=getenv("MESA_GLX_FX"); // 3dfx mesa fullscreen flag
\r
584 if(glxfx[0]=='f') // -> yup, fullscreen needed
\r
586 fx=1; // -> raise flag
\r
587 putenv("FX_GLIDE_NO_SPLASH=");
\r
588 sprintf(gammastr,"SST_GAMMA=%2.1f",fxgamma); // -> set gamma
\r
593 display=XOpenDisplay(NULL); // open display
\r
594 if(!display) // no display?
\r
596 fprintf (stderr,"Failed to open display!!!\n");
\r
597 osd_close_display();
\r
601 myscreen=DefaultScreen(display); // get screen id
\r
604 if(bFullScreen) {fx=1;bModeChanged=0;}
\r
608 XF86VidModeModeLine mode;
\r
610 fx=1; // raise flag
\r
611 XF86VidModeGetModeLine(display,myscreen,&iC,&mode); // get actual mode info
\r
612 if(mode.privsize) XFree(mode.private); // no need for private stuff
\r
613 bModeChanged=0; // init mode change flag
\r
614 if(iResX!=mode.hdisplay || iResY!=mode.vdisplay) // wanted mode is different?
\r
616 XF86VidModeGetAllModeLines(display,myscreen, // -> enum all mode infos
\r
618 if(modes) // -> infos got?
\r
620 for(iC=0;iC<nmodes;++iC) // -> loop modes
\r
622 if(mode.hdisplay==modes[iC]->hdisplay && // -> act mode found?
\r
623 mode.vdisplay==modes[iC]->vdisplay) // if yes: store mode id
\r
626 if(iResX==modes[iC]->hdisplay && // -> wanted mode found?
\r
627 iResY==modes[iC]->vdisplay)
\r
629 XF86VidModeSwitchToMode(display,myscreen, // --> switch to mode
\r
631 XF86VidModeSetViewPort(display,myscreen,0,0);
\r
632 bModeChanged=1; // --> raise flag for repairing mode on close
\r
636 if(bModeChanged==0) // -> no mode found?
\r
638 free(modes); // --> free infos
\r
639 printf("No proper fullscreen mode found!\n"); // --> some info output
\r
646 screen=DefaultScreenOfDisplay(display);
\r
648 if(iZBufferDepth) // visual (with or without zbuffer)
\r
649 myvisual=glXChooseVisual(display,myscreen,dbdepat);
\r
650 else myvisual=glXChooseVisual(display,myscreen,dbnodepat);
\r
652 if(!myvisual) // no visual?
\r
654 fprintf(stderr,"Failed to obtain visual!!!\n"); // -> bye
\r
655 osd_close_display();
\r
659 cx=glXCreateContext(display,myvisual,0,GL_TRUE); // create rendering context
\r
661 if(!cx) // no context?
\r
663 fprintf(stderr,"Failed to create OpenGL context!!!\n");
\r
664 osd_close_display(); // -> bxe
\r
668 // pffff... much work for a simple blank cursor... oh, well...
\r
669 if(!bFullScreen) cursor=XCreateFontCursor(display,XC_trek);
\r
672 Pixmap p1,p2;XImage * img;
\r
673 XColor b,w;unsigned char * idata;
\r
677 memset(&b,0,sizeof(XColor));
\r
678 memset(&w,0,sizeof(XColor));
\r
679 idata=(unsigned char *)malloc(8);
\r
682 p1=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1);
\r
683 p2=XCreatePixmap(display,RootWindow(display,myvisual->screen),8,8,1);
\r
685 img = XCreateImage(display,myvisual->visual,
\r
686 1,XYBitmap,0,idata,8,8,8,1);
\r
688 GCv.function = GXcopy;
\r
689 GCv.foreground = ~0;
\r
690 GCv.background = 0;
\r
691 GCv.plane_mask = AllPlanes;
\r
692 GCc = XCreateGC(display,p1,
\r
693 (GCFunction|GCForeground|GCBackground|GCPlaneMask),&GCv);
\r
695 XPutImage(display, p1,GCc,img,0,0,0,0,8,8);
\r
696 XPutImage(display, p2,GCc,img,0,0,0,0,8,8);
\r
697 XFreeGC(display, GCc);
\r
699 cursor = XCreatePixmapCursor(display,p1,p2,&b,&w,0,0);
\r
701 XFreePixmap(display,p1);
\r
702 XFreePixmap(display,p2);
\r
703 XDestroyImage(img); // will free idata as well
\r
706 colormap=XCreateColormap(display, // create colormap
\r
707 RootWindow(display,myvisual->screen),
\r
708 myvisual->visual,AllocNone);
\r
710 winattr.background_pixel=0;
\r
711 winattr.border_pixel=WhitePixelOfScreen(screen);
\r
712 winattr.bit_gravity=ForgetGravity;
\r
713 winattr.win_gravity=NorthWestGravity;
\r
714 winattr.backing_store=NotUseful;
\r
715 winattr.override_redirect=False;
\r
716 winattr.save_under=False;
\r
717 winattr.event_mask=0;
\r
718 winattr.do_not_propagate_mask=0;
\r
719 winattr.colormap=colormap;
\r
720 winattr.cursor=None;
\r
722 window=XCreateWindow(display, // create own window
\r
723 RootWindow(display,DefaultScreen(display)),
\r
726 InputOutput,myvisual->visual,
\r
727 CWBorderPixel | CWBackPixel |
\r
728 CWEventMask | CWDontPropagate |
\r
729 CWColormap | CWCursor,
\r
732 if(!window) // no window?
\r
734 fprintf(stderr,"Failed in XCreateWindow()!!!\n");
\r
735 osd_close_display(); // -> bye
\r
739 delwindow = XInternAtom(display,"WM_DELETE_WINDOW",0);
\r
740 XSetWMProtocols(display, window, &delwindow, 1);
\r
742 hints.flags=PMinSize|PMaxSize; // hints
\r
743 if(fx) hints.flags|=USPosition|USSize;
\r
744 else hints.flags|=PSize;
\r
746 hints.min_width = hints.max_width = hints.base_width = iResX;
\r
747 hints.min_height = hints.max_height = hints.base_height = iResY;
\r
750 wm_hints.flags=InputHint;
\r
752 XSetWMHints(display,window,&wm_hints);
\r
753 XSetWMNormalHints(display,window,&hints);
\r
754 if(pCaptionText) // caption
\r
755 XStoreName(display,window,pCaptionText);
\r
756 else XStoreName(display,window,"Pete MesaGL PSX Gpu");
\r
758 XDefineCursor(display,window,cursor); // cursor
\r
760 if(fx) // window title bar hack
\r
762 mwmhints.flags=MWM_HINTS_DECORATIONS;
\r
763 mwmhints.decorations=0;
\r
764 mwmatom=XInternAtom(display,"_MOTIF_WM_HINTS",0);
\r
765 XChangeProperty(display,window,mwmatom,mwmatom,32,
\r
766 PropModeReplace,(unsigned char *)&mwmhints,4);
\r
769 XSelectInput(display,window, // input setup
\r
770 FocusChangeMask | ExposureMask |
\r
771 KeyPressMask | KeyReleaseMask);
\r
773 XMapRaised(display,window);
\r
774 XClearWindow(display,window);
\r
775 XWindowEvent(display,window,ExposureMask,&event);
\r
776 glXMakeCurrent(display,window,cx);
\r
779 printf(glGetString(GL_VENDOR));
\r
781 printf(glGetString(GL_RENDERER));
\r
785 if (fx) // after make current: fullscreen resize
\r
787 XResizeWindow(display,window,screen->width,screen->height);
\r
788 hints.min_width = hints.max_width = hints.base_width = screen->width;
\r
789 hints.min_height= hints.max_height = hints.base_height = screen->height;
\r
790 XSetWMNormalHints(display,window,&hints);
792 // set the window layer for GNOME
796 memset(&xev, 0, sizeof(xev));
797 xev.xclient.type = ClientMessage;
798 xev.xclient.serial = 0;
799 xev.xclient.send_event = 1;
800 xev.xclient.message_type = XInternAtom(display, "_NET_WM_STATE", 0);
801 xev.xclient.window = window;
802 xev.xclient.format = 32;
803 xev.xclient.data.l[0] = 1;
804 xev.xclient.data.l[1] = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", 0);
805 xev.xclient.data.l[2] = 0;
806 xev.xclient.data.l[3] = 0;
807 xev.xclient.data.l[4] = 0;
809 XSendEvent(display, RootWindow(display, DefaultScreen(display)), 0,
810 SubstructureRedirectMask | SubstructureNotifyMask, &xev);
815 ////////////////////////////////////////////////////////////////////////
\r
817 long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
\r
819 pCaptionText=CapText;
\r
820 pConfigFile=CfgFile;
\r
822 ReadConfig(); // read text file for config
\r
824 SetFrameRateConfig(); // setup frame rate stuff
\r
826 bIsFirstFrame = TRUE; // we have to init later (well, no really... in Linux we do all in GPUopen)
\r
828 sysdep_create_display(); // create display
\r
830 InitializeTextureStore(); // init texture mem
\r
832 rRatioRect.left = rRatioRect.top=0;
\r
833 rRatioRect.right = iResX;
\r
834 rRatioRect.bottom = iResY;
\r
836 GLinitialize(); // init opengl
\r
840 *disp=(unsigned long *)display; // return display ID to main emu
\r
843 if(display) return 0;
\r
847 ////////////////////////////////////////////////////////////////////////
\r
849 ////////////////////////////////////////////////////////////////////////
\r
851 long GPUclose() // LINUX CLOSE
\r
853 GLcleanup(); // close OGL
\r
855 if(pGfxCardScreen) free(pGfxCardScreen); // free helper memory
\r
858 osd_close_display(); // destroy display
\r
863 ////////////////////////////////////////////////////////////////////////
\r
864 // I shot the sheriff... last function called from emu
\r
865 ////////////////////////////////////////////////////////////////////////
\r
867 long CALLBACK GPUshutdown()
\r
869 if(psxVSecure) free(psxVSecure); // kill emulated vram memory
\r
875 ////////////////////////////////////////////////////////////////////////
\r
876 // paint it black: simple func to clean up optical border garbage
\r
877 ////////////////////////////////////////////////////////////////////////
\r
879 void PaintBlackBorders(void)
\r
883 glDisable(GL_SCISSOR_TEST);
\r
884 if(bTexEnabled) {glDisable(GL_TEXTURE_2D);bTexEnabled=FALSE;}
\r
885 if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}
\r
886 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
\r
887 glDisable(GL_ALPHA_TEST);
\r
891 vertex[0].c.lcol=0xff000000;
\r
892 SETCOL(vertex[0]);
\r
894 if(PreviousPSXDisplay.Range.x0)
\r
896 s=PreviousPSXDisplay.Range.x0+1;
\r
897 glVertex3f(0,0,0.99996f);
\r
898 glVertex3f(0,PSXDisplay.DisplayMode.y,0.99996f);
\r
899 glVertex3f(s,PSXDisplay.DisplayMode.y,0.99996f);
\r
900 glVertex3f(s,0,0.99996f);
\r
902 s+=PreviousPSXDisplay.Range.x1-2;
\r
904 glVertex3f(s,0,0.99996f);
\r
905 glVertex3f(s,PSXDisplay.DisplayMode.y,0.99996f);
\r
906 glVertex3f(PSXDisplay.DisplayMode.x,PSXDisplay.DisplayMode.y,0.99996f);
\r
907 glVertex3f(PSXDisplay.DisplayMode.x,0,0.99996f);
\r
910 if(PreviousPSXDisplay.Range.y0)
\r
912 s=PreviousPSXDisplay.Range.y0+1;
\r
913 glVertex3f(0,0,0.99996f);
\r
914 glVertex3f(0,s,0.99996f);
\r
915 glVertex3f(PSXDisplay.DisplayMode.x,s,0.99996f);
\r
916 glVertex3f(PSXDisplay.DisplayMode.x,0,0.99996f);
\r
921 glEnable(GL_ALPHA_TEST);
\r
922 glEnable(GL_SCISSOR_TEST);
\r
925 ////////////////////////////////////////////////////////////////////////
\r
926 // helper to draw scanlines
\r
927 ////////////////////////////////////////////////////////////////////////
\r
929 __inline void XPRIMdrawTexturedQuad(OGLVertex* vertex1, OGLVertex* vertex2,
\r
930 OGLVertex* vertex3, OGLVertex* vertex4)
\r
933 glBegin(GL_QUAD_STRIP);
\r
934 glTexCoord2fv(&vertex1->sow);
\r
935 glVertex3fv(&vertex1->x);
\r
937 glTexCoord2fv(&vertex2->sow);
\r
938 glVertex3fv(&vertex2->x);
\r
940 glTexCoord2fv(&vertex4->sow);
\r
941 glVertex3fv(&vertex4->x);
\r
943 glTexCoord2fv(&vertex3->sow);
\r
944 glVertex3fv(&vertex3->x);
\r
948 ////////////////////////////////////////////////////////////////////////
\r
950 ////////////////////////////////////////////////////////////////////////
\r
952 void SetScanLines(void)
\r
955 glOrtho(0,iResX,iResY, 0, -1, 1);
\r
958 glViewport(0,0,iResX,iResY);
\r
960 glDisable(GL_SCISSOR_TEST);
\r
961 glDisable(GL_ALPHA_TEST);
\r
962 if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}
\r
964 if(iScanBlend<0) // special texture mask scanline mode
\r
966 if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}
\r
967 gTexName=gTexScanName;
\r
968 glBindTexture(GL_TEXTURE_2D, gTexName);
\r
969 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
970 if(!bBlendEnable) {glEnable(GL_BLEND);bBlendEnable=TRUE;}
\r
975 vertex[0].z=0.99996f;
\r
979 vertex[1].z=0.99996f;
\r
983 vertex[2].z=0.99996f;
\r
987 vertex[3].z=0.99996f;
\r
991 vertex[1].sow=(float)iResX/4.0f;
\r
993 vertex[2].sow=vertex[1].sow;
\r
994 vertex[2].tow=(float)iResY/4.0f;
\r
996 vertex[3].tow=vertex[2].tow;
\r
998 vertex[0].c.lcol=0xffffffff;
\r
999 SETCOL(vertex[0]);
\r
1001 XPRIMdrawTexturedQuad(&vertex[0], &vertex[1], &vertex[2], &vertex[3]);
\r
1003 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT);
\r
1005 else // typical line mode
\r
1007 if(bTexEnabled) {glDisable(GL_TEXTURE_2D);bTexEnabled=FALSE;}
\r
1011 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
\r
1012 vertex[0].c.lcol=0xff000000;
\r
1016 if(!bBlendEnable) {glEnable(GL_BLEND);bBlendEnable=TRUE;}
\r
1018 vertex[0].c.lcol=iScanBlend<<24;
\r
1021 SETCOL(vertex[0]);
\r
1023 glCallList(uiScanLine);
\r
1027 glOrtho(0,PSXDisplay.DisplayMode.x,
\r
1028 PSXDisplay.DisplayMode.y, 0, -1, 1);
\r
1031 glViewport(rRatioRect.left,
\r
1032 iResY-(rRatioRect.top+rRatioRect.bottom),
\r
1033 rRatioRect.right,
\r
1034 rRatioRect.bottom); // init viewport
\r
1036 glEnable(GL_ALPHA_TEST);
\r
1037 glEnable(GL_SCISSOR_TEST);
\r
1040 ////////////////////////////////////////////////////////////////////////
\r
1041 // blur, babe, blur (heavy performance hit for a so-so fullscreen effect)
\r
1042 ////////////////////////////////////////////////////////////////////////
\r
1044 void BlurBackBuffer(void)
\r
1046 if(!gTexBlurName) return;
\r
1048 if(bKeepRatio) glViewport(0,0,iResX,iResY);
\r
1050 glDisable(GL_SCISSOR_TEST);
\r
1051 glDisable(GL_ALPHA_TEST);
\r
1052 if(bOldSmoothShaded) {glShadeModel(GL_FLAT);bOldSmoothShaded=FALSE;}
\r
1053 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
\r
1054 if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}
\r
1055 if(iZBufferDepth) glDisable(GL_DEPTH_TEST);
\r
1056 if(bDrawDither) glDisable(GL_DITHER);
\r
1058 gTexName=gTexBlurName;
\r
1059 glBindTexture(GL_TEXTURE_2D, gTexName);
\r
1061 glCopyTexSubImage2D( GL_TEXTURE_2D, 0, // get back buffer in texture
\r
1069 vertex[0].y=PSXDisplay.DisplayMode.y;
\r
1070 vertex[1].x=PSXDisplay.DisplayMode.x;
\r
1071 vertex[1].y=PSXDisplay.DisplayMode.y;
\r
1072 vertex[2].x=PSXDisplay.DisplayMode.x;
\r
1080 vertex[1].sow=((GLfloat)iFTexA)/256.0f;
\r
1081 vertex[2].tow=((GLfloat)iFTexB)/256.0f;
\r
1083 vertex[1].sow=iFTexA;
\r
1084 vertex[2].tow=iFTexB;
\r
1087 vertex[2].sow=vertex[1].sow;
\r
1089 vertex[3].tow=vertex[2].tow;
\r
1091 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
1092 vertex[0].c.lcol=0x7fffffff;
\r
1093 SETCOL(vertex[0]);
\r
1095 DrawMultiBlur(); // draw the backbuffer texture to create blur effect
\r
1097 glEnable(GL_ALPHA_TEST);
\r
1098 glEnable(GL_SCISSOR_TEST);
\r
1099 if(iZBufferDepth) glEnable(GL_DEPTH_TEST);
\r
1100 if(bDrawDither) glEnable(GL_DITHER);
\r
1101 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT);
\r
1104 glViewport(rRatioRect.left, // re-init viewport
\r
1105 iResY-(rRatioRect.top+rRatioRect.bottom),
\r
1106 rRatioRect.right,
\r
1107 rRatioRect.bottom);
\r
1110 ////////////////////////////////////////////////////////////////////////
\r
1111 // "unblur" repairs the backbuffer after a blur
\r
1113 void UnBlurBackBuffer(void)
\r
1115 if(!gTexBlurName) return;
\r
1117 if(bKeepRatio) glViewport(0,0,iResX,iResY);
\r
1119 glDisable(GL_SCISSOR_TEST);
\r
1120 glDisable(GL_ALPHA_TEST);
\r
1121 if(bBlendEnable) {glDisable(GL_BLEND);bBlendEnable=FALSE;}
\r
1122 if(!bTexEnabled) {glEnable(GL_TEXTURE_2D);bTexEnabled=TRUE;}
\r
1123 if(iZBufferDepth) glDisable(GL_DEPTH_TEST);
\r
1124 if(bDrawDither) glDisable(GL_DITHER);
\r
1126 gTexName=gTexBlurName;
\r
1127 glBindTexture(GL_TEXTURE_2D, gTexName);
\r
1130 vertex[0].y=PSXDisplay.DisplayMode.y;
\r
1131 vertex[1].x=PSXDisplay.DisplayMode.x;
\r
1132 vertex[1].y=PSXDisplay.DisplayMode.y;
\r
1133 vertex[2].x=PSXDisplay.DisplayMode.x;
\r
1140 vertex[1].sow=((GLfloat)iFTexA)/256.0f;
\r
1141 vertex[2].tow=((GLfloat)iFTexB)/256.0f;
\r
1143 vertex[1].sow=iFTexA;
\r
1144 vertex[2].tow=iFTexB;
\r
1147 vertex[2].sow=vertex[1].sow;
\r
1149 vertex[3].tow=vertex[2].tow;
\r
1150 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
\r
1151 vertex[0].c.lcol=0xffffffff;
\r
1152 SETCOL(vertex[0]);
\r
1154 // simply draw the backbuffer texture (without blur)
\r
1155 XPRIMdrawTexturedQuad(&vertex[0], &vertex[1], &vertex[2], &vertex[3]);
\r
1157 glEnable(GL_ALPHA_TEST);
\r
1158 glEnable(GL_SCISSOR_TEST);
\r
1159 if(iZBufferDepth) glEnable(GL_DEPTH_TEST);
\r
1160 if(bDrawDither) glEnable(GL_DITHER); // dither mode
\r
1161 if(bGLBlend) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, COMBINE_EXT);
\r
1164 glViewport(rRatioRect.left,
\r
1165 iResY-(rRatioRect.top+rRatioRect.bottom),
\r
1166 rRatioRect.right,
\r
1167 rRatioRect.bottom); // init viewport
\r
1170 ////////////////////////////////////////////////////////////////////////
\r
1171 // Update display (swap buffers)... called in interlaced mode on
\r
1172 // every emulated vsync, otherwise whenever the displayed screen region
\r
1173 // has been changed
\r
1174 ////////////////////////////////////////////////////////////////////////
\r
1176 int iLastRGB24=0; // special vars for checking when to skip two display updates
\r
1179 void updateDisplay(void) // UPDATE DISPLAY
\r
1183 bFakeFrontBuffer=FALSE;
\r
1184 bRenderFrontBuffer=FALSE;
\r
1186 if(iRenderFVR) // frame buffer read fix mode still active?
\r
1188 iRenderFVR--; // -> if some frames in a row without read access: turn off mode
\r
1189 if(!iRenderFVR) bFullVRam=FALSE;
\r
1192 if(iLastRGB24 && iLastRGB24!=PSXDisplay.RGB24+1) // (mdec) garbage check
\r
1194 iSkipTwo=2; // -> skip two frames to avoid garbage if color mode changes
\r
1198 if(PSXDisplay.RGB24)// && !bNeedUploadAfter) // (mdec) upload wanted?
\r
1200 PrepareFullScreenUpload(-1);
\r
1201 UploadScreen(PSXDisplay.Interlaced); // -> upload whole screen from psx vram
\r
1202 bNeedUploadTest=FALSE;
\r
1203 bNeedInterlaceUpdate=FALSE;
\r
1204 bNeedUploadAfter=FALSE;
\r
1205 bNeedRGB24Update=FALSE;
\r
1208 if(bNeedInterlaceUpdate) // smaller upload?
\r
1210 bNeedInterlaceUpdate=FALSE;
\r
1211 xrUploadArea=xrUploadAreaIL; // -> upload this rect
\r
1212 UploadScreen(TRUE);
\r
1215 if(dwActFixes&512) bCheckFF9G4(NULL); // special game fix for FF9
\r
1217 if(PreviousPSXDisplay.Range.x0|| // paint black borders around display area, if needed
\r
1218 PreviousPSXDisplay.Range.y0)
\r
1219 PaintBlackBorders();
\r
1221 if(PSXDisplay.Disabled) // display disabled?
\r
1224 glDisable(GL_SCISSOR_TEST);
\r
1225 glClearColor(0,0,0,128); // -> clear whole backbuffer
\r
1226 glClear(uiBufferBits);
\r
1227 glEnable(GL_SCISSOR_TEST);
\r
1229 bDisplayNotSet = TRUE;
\r
1232 if(iSkipTwo) // we are in skipping mood?
\r
1235 iDrawnSomething=0; // -> simply lie about something drawn
\r
1238 if(iBlurBuffer && !bSkipNextFrame) // "blur display" activated?
\r
1239 {BlurBackBuffer();bBlur=TRUE;} // -> blur it
\r
1241 if(iUseScanLines) SetScanLines(); // "scan lines" activated? do it
\r
1243 if(usCursorActive) ShowGunCursor(); // "gun cursor" wanted? show 'em
\r
1245 if(dwActFixes&128) // special FPS limitation mode?
\r
1247 if(bUseFrameLimit) PCFrameCap(); // -> ok, do it
\r
1248 if(bUseFrameSkip || ulKeybits&KEY_SHOWFPS)
\r
1252 if(gTexPicName) DisplayPic(); // some gpu info picture active? display it
\r
1254 if(bSnapShot) DoSnapShot(); // snapshot key pressed? cheeeese :)
\r
1256 if(ulKeybits&KEY_SHOWFPS) // wanna see FPS?
\r
1258 sprintf(szDispBuf,"%06.1f",fps_cur);
\r
1259 DisplayText(); // -> show it
\r
1262 //----------------------------------------------------//
\r
1263 // main buffer swapping (well, or skip it)
\r
1265 if(bUseFrameSkip) // frame skipping active ?
\r
1267 if(!bSkipNextFrame)
\r
1269 if(iDrawnSomething)
\r
1270 glXSwapBuffers(display,window);
\r
1272 if(dwActFixes&0x180) // -> special old frame skipping: skip max one in a row
\r
1274 if((fps_skip < fFrameRateHz) && !(bSkipNextFrame))
\r
1275 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
\r
1276 else bSkipNextFrame = FALSE;
\r
1282 if(iDrawnSomething)
\r
1283 glXSwapBuffers(display,window);
\r
1286 iDrawnSomething=0;
\r
1288 //----------------------------------------------------//
\r
1290 if(lClearOnSwap) // clear buffer after swap?
\r
1294 if(bDisplayNotSet) // -> set new vals
\r
1295 SetOGLDisplaySettings(1);
\r
1297 g=((GLclampf)GREEN(lClearOnSwapColor))/255.0f; // -> get col
\r
1298 b=((GLclampf)BLUE(lClearOnSwapColor))/255.0f;
\r
1299 r=((GLclampf)RED(lClearOnSwapColor))/255.0f;
\r
1301 glDisable(GL_SCISSOR_TEST);
\r
1302 glClearColor(r,g,b,128); // -> clear
\r
1303 glClear(uiBufferBits);
\r
1304 glEnable(GL_SCISSOR_TEST);
\r
1305 lClearOnSwap=0; // -> done
\r
1309 if(bBlur) UnBlurBackBuffer(); // unblur buff, if blurred before
\r
1311 if(iZBufferDepth) // clear zbuffer as well (if activated)
\r
1313 glDisable(GL_SCISSOR_TEST);
\r
1314 glClear(GL_DEPTH_BUFFER_BIT);
\r
1315 glEnable(GL_SCISSOR_TEST);
\r
1320 //----------------------------------------------------//
\r
1321 // additional uploads immediatly after swapping
\r
1323 if(bNeedUploadAfter) // upload wanted?
\r
1325 bNeedUploadAfter=FALSE;
\r
1326 bNeedUploadTest=FALSE;
\r
1327 UploadScreen(-1); // -> upload
\r
1330 if(bNeedUploadTest)
\r
1332 bNeedUploadTest=FALSE;
\r
1333 if(PSXDisplay.InterlacedTest &&
\r
1334 //iOffscreenDrawing>2 &&
\r
1335 PreviousPSXDisplay.DisplayPosition.x==PSXDisplay.DisplayPosition.x &&
\r
1336 PreviousPSXDisplay.DisplayEnd.x==PSXDisplay.DisplayEnd.x &&
\r
1337 PreviousPSXDisplay.DisplayPosition.y==PSXDisplay.DisplayPosition.y &&
\r
1338 PreviousPSXDisplay.DisplayEnd.y==PSXDisplay.DisplayEnd.y)
\r
1340 PrepareFullScreenUpload(TRUE);
\r
1341 UploadScreen(TRUE);
\r
1345 //----------------------------------------------------//
\r
1346 // rumbling (main emu pad effect)
\r
1348 if(iRumbleTime) // shake screen by modifying view port
\r
1350 int i1=0,i2=0,i3=0,i4=0;
\r
1355 i1=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
\r
1356 i2=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
\r
1357 i3=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
\r
1358 i4=((rand()*iRumbleVal)/RAND_MAX)-(iRumbleVal/2);
\r
1361 glViewport(rRatioRect.left+i1,
\r
1362 iResY-(rRatioRect.top+rRatioRect.bottom)+i2,
\r
1363 rRatioRect.right+i3,
\r
1364 rRatioRect.bottom+i4);
\r
1367 if(ulKeybits&KEY_RESETTEXSTORE) ResetStuff(); // reset on gpu mode changes? do it before next frame is filled
\r
1370 ////////////////////////////////////////////////////////////////////////
\r
1371 // update front display: smaller update func, if something has changed
\r
1372 // in the frontbuffer... dirty, but hey... real men know no pain
\r
1373 ////////////////////////////////////////////////////////////////////////
\r
1375 void updateFrontDisplay(void)
\r
1377 if(PreviousPSXDisplay.Range.x0||
\r
1378 PreviousPSXDisplay.Range.y0)
\r
1379 PaintBlackBorders();
\r
1381 if(iBlurBuffer) BlurBackBuffer();
\r
1383 if(iUseScanLines) SetScanLines();
\r
1385 if(usCursorActive) ShowGunCursor();
\r
1387 bFakeFrontBuffer=FALSE;
\r
1388 bRenderFrontBuffer=FALSE;
\r
1390 if(gTexPicName) DisplayPic();
\r
1391 if(ulKeybits&KEY_SHOWFPS) DisplayText();
\r
1393 if(iDrawnSomething) // linux:
\r
1394 glXSwapBuffers(display,window);
\r
1396 if(iBlurBuffer) UnBlurBackBuffer();
\r
1399 ////////////////////////////////////////////////////////////////////////
\r
1400 // check if update needed
\r
1401 ////////////////////////////////////////////////////////////////////////
\r
1403 void ChangeDispOffsetsX(void) // CENTER X
\r
1405 int lx,l;short sO;
\r
1407 if(!PSXDisplay.Range.x1) return; // some range given?
\r
1409 l=PSXDisplay.DisplayMode.x;
\r
1411 l*=(int)PSXDisplay.Range.x1; // some funky calculation
\r
1412 l/=2560;lx=l;l&=0xfffffff8;
\r
1414 if(l==PreviousPSXDisplay.Range.x1) return; // some change?
\r
1416 sO=PreviousPSXDisplay.Range.x0; // store old
\r
1418 if(lx>=PSXDisplay.DisplayMode.x) // range bigger?
\r
1420 PreviousPSXDisplay.Range.x1= // -> take display width
\r
1421 PSXDisplay.DisplayMode.x;
\r
1422 PreviousPSXDisplay.Range.x0=0; // -> start pos is 0
\r
1424 else // range smaller? center it
\r
1426 PreviousPSXDisplay.Range.x1=l; // -> store width (8 pixel aligned)
\r
1427 PreviousPSXDisplay.Range.x0= // -> calc start pos
\r
1428 (PSXDisplay.Range.x0-500)/8;
\r
1429 if(PreviousPSXDisplay.Range.x0<0) // -> we don't support neg. values yet
\r
1430 PreviousPSXDisplay.Range.x0=0;
\r
1432 if((PreviousPSXDisplay.Range.x0+lx)> // -> uhuu... that's too much
\r
1433 PSXDisplay.DisplayMode.x)
\r
1435 PreviousPSXDisplay.Range.x0= // -> adjust start
\r
1436 PSXDisplay.DisplayMode.x-lx;
\r
1437 PreviousPSXDisplay.Range.x1+=lx-l; // -> adjust width
\r
1441 if(sO!=PreviousPSXDisplay.Range.x0) // something changed?
\r
1443 bDisplayNotSet=TRUE; // -> recalc display stuff
\r
1447 ////////////////////////////////////////////////////////////////////////
\r
1449 void ChangeDispOffsetsY(void) // CENTER Y
\r
1451 int iT;short sO; // store previous y size
\r
1453 if(PSXDisplay.PAL) iT=48; else iT=28; // different offsets on PAL/NTSC
\r
1455 if(PSXDisplay.Range.y0>=iT) // crossed the security line? :)
\r
1457 PreviousPSXDisplay.Range.y1= // -> store width
\r
1458 PSXDisplay.DisplayModeNew.y;
\r
1460 sO=(PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double; // -> calc offset
\r
1463 PSXDisplay.DisplayModeNew.y+=sO; // -> add offset to y size, too
\r
1465 else sO=0; // else no offset
\r
1467 if(sO!=PreviousPSXDisplay.Range.y0) // something changed?
\r
1469 PreviousPSXDisplay.Range.y0=sO;
\r
1470 bDisplayNotSet=TRUE; // -> recalc display stuff
\r
1474 ////////////////////////////////////////////////////////////////////////
\r
1475 // Aspect ratio of ogl screen: simply adjusting ogl view port
\r
1476 ////////////////////////////////////////////////////////////////////////
\r
1478 void SetAspectRatio(void)
\r
1480 float xs,ys,s;RECT r;
\r
1482 if(!PSXDisplay.DisplayModeNew.x) return;
\r
1483 if(!PSXDisplay.DisplayModeNew.y) return;
\r
1485 xs=(float)iResX/(float)PSXDisplay.DisplayModeNew.x;
\r
1486 ys=(float)iResY/(float)PSXDisplay.DisplayModeNew.y;
\r
1489 r.right =(int)((float)PSXDisplay.DisplayModeNew.x*s);
\r
1490 r.bottom=(int)((float)PSXDisplay.DisplayModeNew.y*s);
\r
1491 if(r.right > iResX) r.right = iResX;
\r
1492 if(r.bottom > iResY) r.bottom = iResY;
\r
1493 if(r.right < 1) r.right = 1;
\r
1494 if(r.bottom < 1) r.bottom = 1;
\r
1496 r.left = (iResX-r.right)/2;
\r
1497 r.top = (iResY-r.bottom)/2;
\r
1499 if(r.bottom<rRatioRect.bottom ||
\r
1500 r.right <rRatioRect.right)
\r
1503 glClearColor(0,0,0,128);
\r
1505 if(r.right <rRatioRect.right)
\r
1511 glScissor(rC.left,rC.top,rC.right,rC.bottom);
\r
1512 glClear(uiBufferBits);
\r
1513 rC.left=iResX-rC.right;
\r
1514 glScissor(rC.left,rC.top,rC.right,rC.bottom);
\r
1515 glClear(uiBufferBits);
\r
1518 if(r.bottom <rRatioRect.bottom)
\r
1524 glScissor(rC.left,rC.top,rC.right,rC.bottom);
\r
1525 glClear(uiBufferBits);
\r
1526 rC.top=iResY-rC.bottom;
\r
1527 glScissor(rC.left,rC.top,rC.right,rC.bottom);
\r
1528 glClear(uiBufferBits);
\r
1532 bDisplayNotSet=TRUE;
\r
1538 glViewport(rRatioRect.left,
\r
1539 iResY-(rRatioRect.top+rRatioRect.bottom),
\r
1541 rRatioRect.bottom); // init viewport
\r
1544 ////////////////////////////////////////////////////////////////////////
\r
1545 // big ass check, if an ogl swap buffer is needed
\r
1546 ////////////////////////////////////////////////////////////////////////
\r
1548 void updateDisplayIfChanged(void)
\r
1552 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
\r
1553 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
\r
1555 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
\r
1556 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew))
\r
1557 return; // nothing has changed? fine, no swap buffer needed
\r
1559 else // some res change?
\r
1562 glOrtho(0,PSXDisplay.DisplayModeNew.x, // -> new psx resolution
\r
1563 PSXDisplay.DisplayModeNew.y, 0, -1, 1);
\r
1564 if(bKeepRatio) SetAspectRatio();
\r
1567 bDisplayNotSet = TRUE; // re-calc offsets/display area
\r
1570 if(PSXDisplay.RGB24!=PSXDisplay.RGB24New) // clean up textures, if rgb mode change (usually mdec on/off)
\r
1572 PreviousPSXDisplay.RGB24=0; // no full 24 frame uploaded yet
\r
1573 ResetTextureArea(FALSE);
\r
1577 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
\r
1578 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
\r
1579 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
\r
1580 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
\r
1582 PSXDisplay.DisplayEnd.x= // calc new ends
\r
1583 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
\r
1584 PSXDisplay.DisplayEnd.y=
\r
1585 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
\r
1586 PreviousPSXDisplay.DisplayEnd.x=
\r
1587 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
\r
1588 PreviousPSXDisplay.DisplayEnd.y=
\r
1589 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
\r
1591 ChangeDispOffsetsX();
\r
1593 if(iFrameLimit==2) SetAutoFrameCap(); // set new fps limit vals (depends on interlace)
\r
1595 if(bUp) updateDisplay(); // yeah, real update (swap buffer)
\r
1598 ////////////////////////////////////////////////////////////////////////
\r
1599 // swap update check (called by psx vsync function)
\r
1600 ////////////////////////////////////////////////////////////////////////
\r
1602 BOOL bSwapCheck(void)
\r
1604 static int iPosCheck=0;
\r
1605 static PSXPoint_t pO;
\r
1606 static PSXPoint_t pD;
\r
1607 static int iDoAgain=0;
\r
1609 if(PSXDisplay.DisplayPosition.x==pO.x &&
\r
1610 PSXDisplay.DisplayPosition.y==pO.y &&
\r
1611 PSXDisplay.DisplayEnd.x==pD.x &&
\r
1612 PSXDisplay.DisplayEnd.y==pD.y)
\r
1616 pO=PSXDisplay.DisplayPosition;
\r
1617 pD=PSXDisplay.DisplayEnd;
\r
1619 if(iPosCheck<=4) return FALSE;
\r
1623 if(PSXDisplay.Interlaced) return FALSE;
\r
1625 if (bNeedInterlaceUpdate||
\r
1626 bNeedRGB24Update ||
\r
1627 bNeedUploadAfter||
\r
1628 bNeedUploadTest ||
\r
1633 if(bNeedUploadAfter)
\r
1635 if(bNeedUploadTest && PSXDisplay.InterlacedTest)
\r
1638 bDisplayNotSet = TRUE;
\r
1641 PreviousPSXDisplay.DisplayPosition.x=PSXDisplay.DisplayPosition.x;
\r
1642 PreviousPSXDisplay.DisplayPosition.y=PSXDisplay.DisplayPosition.y;
\r
1643 PreviousPSXDisplay.DisplayEnd.x=PSXDisplay.DisplayEnd.x;
\r
1644 PreviousPSXDisplay.DisplayEnd.y=PSXDisplay.DisplayEnd.y;
\r
1645 pO=PSXDisplay.DisplayPosition;
\r
1646 pD=PSXDisplay.DisplayEnd;
\r
1654 ////////////////////////////////////////////////////////////////////////
\r
1655 // gun cursor func: player=0-7, x=0-511, y=0-255
\r
1656 ////////////////////////////////////////////////////////////////////////
\r
1658 void CALLBACK GPUcursor(int iPlayer,int x,int y)
\r
1660 if(iPlayer<0) return;
\r
1661 if(iPlayer>7) return;
\r
1663 usCursorActive|=(1<<iPlayer);
\r
1666 if(x>iGPUHeightMask) x=iGPUHeightMask;
\r
1670 ptCursorPoint[iPlayer].x=x;
\r
1671 ptCursorPoint[iPlayer].y=y;
\r
1674 ////////////////////////////////////////////////////////////////////////
\r
1675 // update lace is called every VSync. Basically we limit frame rate
\r
1676 // here, and in interlaced mode we swap ogl display buffers.
\r
1677 ////////////////////////////////////////////////////////////////////////
\r
1679 static unsigned short usFirstPos=2;
\r
1681 void CALLBACK GPUupdateLace(void)
\r
1683 if(!(dwActFixes&0x1000))
\r
1684 STATUSREG^=0x80000000; // interlaced bit toggle, if the CC game fix is not active (see gpuReadStatus)
\r
1686 if(!(dwActFixes&128)) // normal frame limit func
\r
1689 if(iOffscreenDrawing==4) // special check if high offscreen drawing is on
\r
1691 if(bSwapCheck()) return;
\r
1694 if(PSXDisplay.Interlaced) // interlaced mode?
\r
1696 if(PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
\r
1698 updateDisplay(); // -> swap buffers (new frame)
\r
1701 else if(bRenderFrontBuffer) // no interlace mode? and some stuff in front has changed?
\r
1703 updateFrontDisplay(); // -> update front buffer
\r
1705 else if(usFirstPos==1) // initial updates (after startup)
\r
1711 ////////////////////////////////////////////////////////////////////////
\r
1712 // process read request from GPU status register
\r
1713 ////////////////////////////////////////////////////////////////////////
\r
1715 uint32_t CALLBACK GPUreadStatus(void)
\r
1717 if(dwActFixes&0x1000) // CC game fix
\r
1719 static int iNumRead=0;
\r
1720 if((iNumRead++)==2)
\r
1723 STATUSREG^=0x80000000; // interlaced bit toggle... we do it on every second read status... needed by some games (like ChronoCross)
\r
1727 if(iFakePrimBusy) // 27.10.2007 - emulating some 'busy' while drawing... pfff... not perfect, but since our emulated dma is not done in an extra thread...
\r
1731 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
\r
1734 GPUIsNotReadyForCommands;
\r
1739 GPUIsReadyForCommands;
\r
1746 ////////////////////////////////////////////////////////////////////////
\r
1747 // processes data send to GPU status register
\r
1748 // these are always single packet commands.
\r
1749 ////////////////////////////////////////////////////////////////////////
\r
1751 void CALLBACK GPUwriteStatus(uint32_t gdata)
\r
1753 uint32_t lCommand=(gdata>>24)&0xff;
\r
1755 ulStatusControl[lCommand]=gdata;
\r
1759 //--------------------------------------------------//
\r
1762 memset(ulGPUInfoVals, 0x00, 16 * sizeof(uint32_t));
\r
1763 lGPUstatusRet = 0x14802000;
\r
1764 PSXDisplay.Disabled=1;
\r
1765 iDataWriteMode=iDataReadMode=DR_NORMAL;
\r
1766 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
\r
1767 drawX=drawY=0;drawW=drawH=0;
\r
1768 sSetMask=0;lSetMask=0;bCheckMask=FALSE;iSetMask=0;
\r
1770 GlobalTextAddrX=0;GlobalTextAddrY=0;
\r
1771 GlobalTextTP=0;GlobalTextABR=0;
\r
1772 PSXDisplay.RGB24=FALSE;
\r
1773 PSXDisplay.Interlaced=FALSE;
\r
1774 bUsingTWin = FALSE;
\r
1777 // dis/enable display
\r
1779 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
\r
1780 PSXDisplay.Disabled = (gdata & 1);
\r
1782 if(PSXDisplay.Disabled)
\r
1783 STATUSREG|=GPUSTATUS_DISPLAYDISABLED;
\r
1784 else STATUSREG&=~GPUSTATUS_DISPLAYDISABLED;
\r
1786 if (iOffscreenDrawing==4 &&
\r
1787 PreviousPSXDisplay.Disabled &&
\r
1788 !(PSXDisplay.Disabled))
\r
1791 if(!PSXDisplay.RGB24)
\r
1793 PrepareFullScreenUpload(TRUE);
\r
1794 UploadScreen(TRUE);
\r
1801 // setting transfer mode
\r
1803 gdata &= 0x03; // only want the lower two bits
\r
1805 iDataWriteMode=iDataReadMode=DR_NORMAL;
\r
1806 if(gdata==0x02) iDataWriteMode=DR_VRAMTRANSFER;
\r
1807 if(gdata==0x03) iDataReadMode =DR_VRAMTRANSFER;
\r
1809 STATUSREG&=~GPUSTATUS_DMABITS; // clear the current settings of the DMA bits
\r
1810 STATUSREG|=(gdata << 29); // set the DMA bits according to the received data
\r
1814 // setting display position
\r
1817 short sx=(short)(gdata & 0x3ff);
\r
1820 if(iGPUHeight==1024)
\r
1822 if(dwGPUVersion==2)
\r
1823 sy = (short)((gdata>>12)&0x3ff);
\r
1824 else sy = (short)((gdata>>10)&0x3ff);
\r
1826 else sy = (short)((gdata>>10)&0x3ff); // really: 0x1ff, but we adjust it later
\r
1831 PreviousPSXDisplay.DisplayModeNew.y=sy/PSXDisplay.Double;
\r
1834 else PreviousPSXDisplay.DisplayModeNew.y=0;
\r
1843 PreviousPSXDisplay.DisplayPosition.x = sx;
\r
1844 PreviousPSXDisplay.DisplayPosition.y = sy;
\r
1845 PSXDisplay.DisplayPosition.x = sx;
\r
1846 PSXDisplay.DisplayPosition.y = sy;
\r
1852 if((!PSXDisplay.Interlaced) &&
\r
1853 PreviousPSXDisplay.DisplayPosition.x == sx &&
\r
1854 PreviousPSXDisplay.DisplayPosition.y == sy)
\r
1857 PSXDisplay.DisplayPosition.x = PreviousPSXDisplay.DisplayPosition.x;
\r
1858 PSXDisplay.DisplayPosition.y = PreviousPSXDisplay.DisplayPosition.y;
\r
1859 PreviousPSXDisplay.DisplayPosition.x = sx;
\r
1860 PreviousPSXDisplay.DisplayPosition.y = sy;
\r
1864 if((!PSXDisplay.Interlaced) &&
\r
1865 PSXDisplay.DisplayPosition.x == sx &&
\r
1866 PSXDisplay.DisplayPosition.y == sy)
\r
1868 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
\r
1869 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
\r
1870 PSXDisplay.DisplayPosition.x = sx;
\r
1871 PSXDisplay.DisplayPosition.y = sy;
\r
1874 PSXDisplay.DisplayEnd.x=
\r
1875 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
\r
1876 PSXDisplay.DisplayEnd.y=
\r
1877 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
\r
1879 PreviousPSXDisplay.DisplayEnd.x=
\r
1880 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
\r
1881 PreviousPSXDisplay.DisplayEnd.y=
\r
1882 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
\r
1884 bDisplayNotSet = TRUE;
\r
1886 if (!(PSXDisplay.Interlaced))
\r
1891 if(PSXDisplay.InterlacedTest &&
\r
1892 ((PreviousPSXDisplay.DisplayPosition.x != PSXDisplay.DisplayPosition.x)||
\r
1893 (PreviousPSXDisplay.DisplayPosition.y != PSXDisplay.DisplayPosition.y)))
\r
1894 PSXDisplay.InterlacedTest--;
\r
1902 PSXDisplay.Range.x0=gdata & 0x7ff; //0x3ff;
\r
1903 PSXDisplay.Range.x1=(gdata>>12) & 0xfff;//0x7ff;
\r
1905 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
\r
1907 ChangeDispOffsetsX();
\r
1914 PreviousPSXDisplay.Height = PSXDisplay.Height;
\r
1916 PSXDisplay.Range.y0=gdata & 0x3ff;
\r
1917 PSXDisplay.Range.y1=(gdata>>10) & 0x3ff;
\r
1919 PSXDisplay.Height = PSXDisplay.Range.y1 -
\r
1920 PSXDisplay.Range.y0 +
\r
1921 PreviousPSXDisplay.DisplayModeNew.y;
\r
1923 if (PreviousPSXDisplay.Height != PSXDisplay.Height)
\r
1925 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
\r
1926 ChangeDispOffsetsY();
\r
1927 updateDisplayIfChanged();
\r
1931 // setting display infos
\r
1934 PSXDisplay.DisplayModeNew.x = dispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
\r
1936 if (gdata&0x04) PSXDisplay.Double=2;
\r
1937 else PSXDisplay.Double=1;
\r
1938 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
\r
1940 ChangeDispOffsetsY();
\r
1942 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
\r
1943 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
\r
1944 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
\r
1946 STATUSREG&=~GPUSTATUS_WIDTHBITS; // clear the width bits
\r
1949 (((gdata & 0x03) << 17) |
\r
1950 ((gdata & 0x40) << 10)); // set the width bits
\r
1952 PreviousPSXDisplay.InterlacedNew=FALSE;
\r
1953 if (PSXDisplay.InterlacedNew)
\r
1955 if(!PSXDisplay.Interlaced)
\r
1957 PSXDisplay.InterlacedTest=2;
\r
1958 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
\r
1959 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
\r
1960 PreviousPSXDisplay.InterlacedNew=TRUE;
\r
1963 STATUSREG|=GPUSTATUS_INTERLACED;
\r
1967 PSXDisplay.InterlacedTest=0;
\r
1968 STATUSREG&=~GPUSTATUS_INTERLACED;
\r
1971 if (PSXDisplay.PAL)
\r
1972 STATUSREG|=GPUSTATUS_PAL;
\r
1973 else STATUSREG&=~GPUSTATUS_PAL;
\r
1975 if (PSXDisplay.Double==2)
\r
1976 STATUSREG|=GPUSTATUS_DOUBLEHEIGHT;
\r
1977 else STATUSREG&=~GPUSTATUS_DOUBLEHEIGHT;
\r
1979 if (PSXDisplay.RGB24New)
\r
1980 STATUSREG|=GPUSTATUS_RGB24;
\r
1981 else STATUSREG&=~GPUSTATUS_RGB24;
\r
1983 updateDisplayIfChanged();
\r
1987 //--------------------------------------------------//
\r
1988 // ask about GPU version and other stuff
\r
1996 GPUdataRet=ulGPUInfoVals[INFO_TW]; // tw infos
\r
1999 GPUdataRet=ulGPUInfoVals[INFO_DRAWSTART]; // draw start
\r
2002 GPUdataRet=ulGPUInfoVals[INFO_DRAWEND]; // draw end
\r
2006 GPUdataRet=ulGPUInfoVals[INFO_DRAWOFF]; // draw offset
\r
2009 if(dwGPUVersion==2)
\r
2011 else GPUdataRet=0x02; // gpu type
\r
2014 case 0x0F: // some bios addr?
\r
2015 GPUdataRet=0xBFC03720;
\r
2019 //--------------------------------------------------//
\r
2023 ////////////////////////////////////////////////////////////////////////
\r
2024 // vram read/write helpers
\r
2025 ////////////////////////////////////////////////////////////////////////
\r
2027 BOOL bNeedWriteUpload=FALSE;
\r
2029 __inline void FinishedVRAMWrite(void)
\r
2031 if(bNeedWriteUpload)
\r
2033 bNeedWriteUpload=FALSE;
\r
2034 CheckWriteUpdate();
\r
2037 // set register to NORMAL operation
\r
2038 iDataWriteMode = DR_NORMAL;
\r
2040 // reset transfer values, to prevent mis-transfer of data
\r
2041 VRAMWrite.ColsRemaining = 0;
\r
2042 VRAMWrite.RowsRemaining = 0;
\r
2045 __inline void FinishedVRAMRead(void)
\r
2047 // set register to NORMAL operation
\r
2048 iDataReadMode = DR_NORMAL;
\r
2049 // reset transfer values, to prevent mis-transfer of data
\r
2052 VRAMRead.Width = 0;
\r
2053 VRAMRead.Height = 0;
\r
2054 VRAMRead.ColsRemaining = 0;
\r
2055 VRAMRead.RowsRemaining = 0;
\r
2057 // indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
\r
2058 STATUSREG&=~GPUSTATUS_READYFORVRAM;
\r
2061 ////////////////////////////////////////////////////////////////////////
\r
2062 // vram read check ex (reading from card's back/frontbuffer if needed...
\r
2064 ////////////////////////////////////////////////////////////////////////
\r
2066 void CheckVRamReadEx(int x, int y, int dx, int dy)
\r
2068 unsigned short sArea;
\r
2069 int ux,uy,udx,udy,wx,wy;
\r
2070 unsigned short * p1, *p2;
\r
2072 unsigned char * ps;
\r
2073 unsigned char * px;
\r
2074 unsigned short s,sx;
\r
2076 if(STATUSREG&GPUSTATUS_RGB24) return;
\r
2078 if(((dx > PSXDisplay.DisplayPosition.x) &&
\r
2079 (x < PSXDisplay.DisplayEnd.x) &&
\r
2080 (dy > PSXDisplay.DisplayPosition.y) &&
\r
2081 (y < PSXDisplay.DisplayEnd.y)))
\r
2084 if((!(PSXDisplay.InterlacedTest) &&
\r
2085 (dx > PreviousPSXDisplay.DisplayPosition.x) &&
\r
2086 (x < PreviousPSXDisplay.DisplayEnd.x) &&
\r
2087 (dy > PreviousPSXDisplay.DisplayPosition.y) &&
\r
2088 (y < PreviousPSXDisplay.DisplayEnd.y)))
\r
2099 bFullVRam=TRUE;iRenderFVR=2;return;
\r
2101 bFullVRam=TRUE;iRenderFVR=2;
\r
2109 ux=PSXDisplay.DisplayPosition.x;
\r
2110 uy=PSXDisplay.DisplayPosition.y;
\r
2111 udx=PSXDisplay.DisplayEnd.x-ux;
\r
2112 udy=PSXDisplay.DisplayEnd.y-uy;
\r
2113 if((PreviousPSXDisplay.DisplayEnd.x-
\r
2114 PreviousPSXDisplay.DisplayPosition.x)==udx &&
\r
2115 (PreviousPSXDisplay.DisplayEnd.y-
\r
2116 PreviousPSXDisplay.DisplayPosition.y)==udy)
\r
2117 p2=(psxVuw + (1024*PreviousPSXDisplay.DisplayPosition.y) +
\r
2118 PreviousPSXDisplay.DisplayPosition.x);
\r
2122 ux=PreviousPSXDisplay.DisplayPosition.x;
\r
2123 uy=PreviousPSXDisplay.DisplayPosition.y;
\r
2124 udx=PreviousPSXDisplay.DisplayEnd.x-ux;
\r
2125 udy=PreviousPSXDisplay.DisplayEnd.y-uy;
\r
2126 if((PSXDisplay.DisplayEnd.x-
\r
2127 PSXDisplay.DisplayPosition.x)==udx &&
\r
2128 (PSXDisplay.DisplayEnd.y-
\r
2129 PSXDisplay.DisplayPosition.y)==udy)
\r
2130 p2=(psxVuw + (1024*PSXDisplay.DisplayPosition.y) +
\r
2131 PSXDisplay.DisplayPosition.x);
\r
2134 p1=(psxVuw + (1024*uy) + ux);
\r
2138 wx=dx=udx;wy=dy=udy;
\r
2140 if(udx<=0) return;
\r
2141 if(udy<=0) return;
\r
2147 XS=(float)rRatioRect.right/(float)wx;
\r
2148 YS=(float)rRatioRect.bottom/(float)wy;
\r
2150 dx=(int)((float)(dx)*XS);
\r
2151 dy=(int)((float)(dy)*YS);
\r
2153 if(dx>iResX) dx=iResX;
\r
2154 if(dy>iResY) dy=iResY;
\r
2162 x+=rRatioRect.left;
\r
2163 y-=rRatioRect.top;
\r
2165 if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;
\r
2167 if(!pGfxCardScreen)
\r
2169 glPixelStorei(GL_PACK_ALIGNMENT,1);
\r
2170 pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);
\r
2173 ps=pGfxCardScreen;
\r
2175 if(!sArea) glReadBuffer(GL_FRONT);
\r
2177 glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);
\r
2179 if(!sArea) glReadBuffer(GL_BACK);
\r
2183 XS=(float)dx/(float)(udx);
\r
2184 YS=(float)dy/(float)(udy+1);
\r
2186 for(y=udy;y>0;y--)
\r
2188 for(x=0;x<udx;x++)
\r
2190 if(p1>=psxVuw && p1<psxVuw_eom)
\r
2192 px=ps+(3*((int)((float)x * XS))+
\r
2193 (3*dx)*((int)((float)y*YS)));
\r
2203 if(p2>=psxVuw && p2<psxVuw_eom) *p2=s;
\r
2210 if(p2) p2 += 1024 - udx;
\r
2214 ////////////////////////////////////////////////////////////////////////
\r
2215 // vram read check (reading from card's back/frontbuffer if needed...
\r
2217 ////////////////////////////////////////////////////////////////////////
\r
2219 void CheckVRamRead(int x, int y, int dx, int dy,BOOL bFront)
\r
2221 unsigned short sArea;unsigned short * p;
\r
2222 int ux,uy,udx,udy,wx,wy;float XS,YS;
\r
2223 unsigned char * ps, * px;
\r
2224 unsigned short s=0,sx;
\r
2226 if(STATUSREG&GPUSTATUS_RGB24) return;
\r
2228 if(((dx > PSXDisplay.DisplayPosition.x) &&
\r
2229 (x < PSXDisplay.DisplayEnd.x) &&
\r
2230 (dy > PSXDisplay.DisplayPosition.y) &&
\r
2231 (y < PSXDisplay.DisplayEnd.y)))
\r
2234 if((!(PSXDisplay.InterlacedTest) &&
\r
2235 (dx > PreviousPSXDisplay.DisplayPosition.x) &&
\r
2236 (x < PreviousPSXDisplay.DisplayEnd.x) &&
\r
2237 (dy > PreviousPSXDisplay.DisplayPosition.y) &&
\r
2238 (y < PreviousPSXDisplay.DisplayEnd.y)))
\r
2245 if(dwActFixes&0x40)
\r
2249 bFullVRam=TRUE;iRenderFVR=2;return;
\r
2251 bFullVRam=TRUE;iRenderFVR=2;
\r
2254 ux=x;uy=y;udx=dx;udy=dy;
\r
2258 x -=PSXDisplay.DisplayPosition.x;
\r
2259 dx-=PSXDisplay.DisplayPosition.x;
\r
2260 y -=PSXDisplay.DisplayPosition.y;
\r
2261 dy-=PSXDisplay.DisplayPosition.y;
\r
2262 wx=PSXDisplay.DisplayEnd.x-PSXDisplay.DisplayPosition.x;
\r
2263 wy=PSXDisplay.DisplayEnd.y-PSXDisplay.DisplayPosition.y;
\r
2267 x -=PreviousPSXDisplay.DisplayPosition.x;
\r
2268 dx-=PreviousPSXDisplay.DisplayPosition.x;
\r
2269 y -=PreviousPSXDisplay.DisplayPosition.y;
\r
2270 dy-=PreviousPSXDisplay.DisplayPosition.y;
\r
2271 wx=PreviousPSXDisplay.DisplayEnd.x-PreviousPSXDisplay.DisplayPosition.x;
\r
2272 wy=PreviousPSXDisplay.DisplayEnd.y-PreviousPSXDisplay.DisplayPosition.y;
\r
2274 if(x<0) {ux-=x;x=0;}
\r
2275 if(y<0) {uy-=y;y=0;}
\r
2276 if(dx>wx) {udx-=(dx-wx);dx=wx;}
\r
2277 if(dy>wy) {udy-=(dy-wy);dy=wy;}
\r
2281 p=(psxVuw + (1024*uy) + ux);
\r
2283 if(udx<=0) return;
\r
2284 if(udy<=0) return;
\r
2290 XS=(float)rRatioRect.right/(float)wx;
\r
2291 YS=(float)rRatioRect.bottom/(float)wy;
\r
2293 dx=(int)((float)(dx)*XS);
\r
2294 dy=(int)((float)(dy)*YS);
\r
2295 x=(int)((float)x*XS);
\r
2296 y=(int)((float)y*YS);
\r
2301 if(dx>iResX) dx=iResX;
\r
2302 if(dy>iResY) dy=iResY;
\r
2310 x+=rRatioRect.left;
\r
2311 y-=rRatioRect.top;
\r
2313 if(y<0) y=0; if((y+dy)>iResY) dy=iResY-y;
\r
2315 if(!pGfxCardScreen)
\r
2317 glPixelStorei(GL_PACK_ALIGNMENT,1);
\r
2318 pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);
\r
2321 ps=pGfxCardScreen;
\r
2323 if(bFront) glReadBuffer(GL_FRONT);
\r
2325 glReadPixels(x,y,dx,dy,GL_RGB,GL_UNSIGNED_BYTE,ps);
\r
2327 if(bFront) glReadBuffer(GL_BACK);
\r
2329 XS=(float)dx/(float)(udx);
\r
2330 YS=(float)dy/(float)(udy+1);
\r
2332 for(y=udy;y>0;y--)
\r
2334 for(x=0;x<udx;x++)
\r
2336 if(p>=psxVuw && p<psxVuw_eom)
\r
2338 px=ps+(3*((int)((float)x * XS))+
\r
2339 (3*dx)*((int)((float)y*YS)));
\r
2355 ////////////////////////////////////////////////////////////////////////
\r
2356 // core read from vram
\r
2357 ////////////////////////////////////////////////////////////////////////
\r
2359 void CALLBACK GPUreadDataMem(uint32_t *pMem, int iSize)
\r
2363 if(iDataReadMode!=DR_VRAMTRANSFER) return;
\r
2367 // adjust read ptr, if necessary
\r
2368 while(VRAMRead.ImagePtr>=psxVuw_eom)
\r
2369 VRAMRead.ImagePtr-=iGPUHeight*1024;
\r
2370 while(VRAMRead.ImagePtr<psxVuw)
\r
2371 VRAMRead.ImagePtr+=iGPUHeight*1024;
\r
2373 if((iFrameReadType&1 && iSize>1) &&
\r
2374 !(iDrawnSomething==2 &&
\r
2375 VRAMRead.x == VRAMWrite.x &&
\r
2376 VRAMRead.y == VRAMWrite.y &&
\r
2377 VRAMRead.Width == VRAMWrite.Width &&
\r
2378 VRAMRead.Height == VRAMWrite.Height))
\r
2379 CheckVRamRead(VRAMRead.x,VRAMRead.y,
\r
2380 VRAMRead.x+VRAMRead.RowsRemaining,
\r
2381 VRAMRead.y+VRAMRead.ColsRemaining,
\r
2384 for(i=0;i<iSize;i++)
\r
2386 // do 2 seperate 16bit reads for compatibility (wrap issues)
\r
2387 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
\r
2390 GPUdataRet=(uint32_t)*VRAMRead.ImagePtr;
\r
2392 VRAMRead.ImagePtr++;
\r
2393 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
\r
2394 VRAMRead.RowsRemaining --;
\r
2396 if(VRAMRead.RowsRemaining<=0)
\r
2398 VRAMRead.RowsRemaining = VRAMRead.Width;
\r
2399 VRAMRead.ColsRemaining--;
\r
2400 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
\r
2401 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
\r
2404 // higher 16 bit (always, even if it's an odd width)
\r
2405 GPUdataRet|=(uint32_t)(*VRAMRead.ImagePtr)<<16;
\r
2406 *pMem++=GPUdataRet;
\r
2408 if(VRAMRead.ColsRemaining <= 0)
\r
2409 {FinishedVRAMRead();goto ENDREAD;}
\r
2411 VRAMRead.ImagePtr++;
\r
2412 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
\r
2413 VRAMRead.RowsRemaining--;
\r
2414 if(VRAMRead.RowsRemaining<=0)
\r
2416 VRAMRead.RowsRemaining = VRAMRead.Width;
\r
2417 VRAMRead.ColsRemaining--;
\r
2418 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
\r
2419 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=iGPUHeight*1024;
\r
2421 if(VRAMRead.ColsRemaining <= 0)
\r
2422 {FinishedVRAMRead();goto ENDREAD;}
\r
2424 else {FinishedVRAMRead();goto ENDREAD;}
\r
2431 uint32_t CALLBACK GPUreadData(void)
\r
2434 GPUreadDataMem(&l,1);
\r
2435 return GPUdataRet;
\r
2438 ////////////////////////////////////////////////////////////////////////
\r
2439 // helper table to know how much data is used by drawing commands
\r
2440 ////////////////////////////////////////////////////////////////////////
\r
2442 const unsigned char primTableCX[256] =
\r
2459 8,8,8,8,12,12,12,12,
\r
2463 // 5,5,5,5,6,6,6,6, //FLINE
\r
2464 254,254,254,254,254,254,254,254,
\r
2468 // 7,7,7,7,9,9,9,9, // LINEG3 LINEG4
\r
2469 255,255,255,255,255,255,255,255,
\r
2471 3,3,3,3,4,4,4,4, // TILE SPRT
\r
2473 2,2,2,2,3,3,3,3, // TILE1
\r
2512 ////////////////////////////////////////////////////////////////////////
\r
2513 // processes data send to GPU data register
\r
2514 ////////////////////////////////////////////////////////////////////////
\r
2516 void CALLBACK GPUwriteDataMem(uint32_t *pMem, int iSize)
\r
2518 unsigned char command;
\r
2522 GPUIsNotReadyForCommands;
\r
2526 if(iDataWriteMode==DR_VRAMTRANSFER)
\r
2528 // make sure we are in vram
\r
2529 while(VRAMWrite.ImagePtr>=psxVuw_eom)
\r
2530 VRAMWrite.ImagePtr-=iGPUHeight*1024;
\r
2531 while(VRAMWrite.ImagePtr<psxVuw)
\r
2532 VRAMWrite.ImagePtr+=iGPUHeight*1024;
\r
2534 // now do the loop
\r
2535 while(VRAMWrite.ColsRemaining>0)
\r
2537 while(VRAMWrite.RowsRemaining>0)
\r
2539 if(i>=iSize) {goto ENDVRAM;}
\r
2544 *VRAMWrite.ImagePtr++ = (unsigned short)gdata;
\r
2545 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
\r
2546 VRAMWrite.RowsRemaining --;
\r
2548 if(VRAMWrite.RowsRemaining <= 0)
\r
2550 VRAMWrite.ColsRemaining--;
\r
2551 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
\r
2553 gdata=(gdata&0xFFFF)|(((uint32_t)(*VRAMWrite.ImagePtr))<<16);
\r
2554 FinishedVRAMWrite();
\r
2557 VRAMWrite.RowsRemaining = VRAMWrite.Width;
\r
2558 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
\r
2561 *VRAMWrite.ImagePtr++ = (unsigned short)(gdata>>16);
\r
2562 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=iGPUHeight*1024;
\r
2563 VRAMWrite.RowsRemaining --;
\r
2566 VRAMWrite.RowsRemaining = VRAMWrite.Width;
\r
2567 VRAMWrite.ColsRemaining--;
\r
2568 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
\r
2571 FinishedVRAMWrite();
\r
2576 if(iDataWriteMode==DR_NORMAL)
\r
2578 void (* *primFunc)(unsigned char *);
\r
2579 if(bSkipNextFrame) primFunc=primTableSkip;
\r
2580 else primFunc=primTableJ;
\r
2584 if(iDataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
\r
2586 gdata=*pMem++;i++;
\r
2590 command = (unsigned char)((gdata>>24) & 0xff);
\r
2592 if(primTableCX[command])
\r
2594 gpuDataC = primTableCX[command];
\r
2595 gpuCommand = command;
\r
2596 gpuDataM[0] = gdata;
\r
2603 gpuDataM[gpuDataP] = gdata;
\r
2606 if((gpuDataC==254 && gpuDataP>=3) ||
\r
2607 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
\r
2609 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
\r
2610 gpuDataP=gpuDataC-1;
\r
2616 if(gpuDataP == gpuDataC)
\r
2618 gpuDataC=gpuDataP=0;
\r
2619 primFunc[gpuCommand]((unsigned char *)gpuDataM);
\r
2621 if(dwEmuFixes&0x0001 || dwActFixes&0x20000) // hack for emulating "gpu busy" in some games
\r
2629 GPUIsReadyForCommands;
\r
2633 ////////////////////////////////////////////////////////////////////////
\r
2635 void CALLBACK GPUwriteData(uint32_t gdata)
\r
2637 GPUwriteDataMem(&gdata,1);
\r
2640 ////////////////////////////////////////////////////////////////////////
\r
2641 // call config dlg
\r
2642 ////////////////////////////////////////////////////////////////////////
\r
2644 void StartCfgTool(char *arg) // linux: start external cfg tool
\r
2649 strcpy(cfg, "./cfgpeopsxgl");
\r
2650 if (stat(cfg, &buf) != -1) {
\r
2651 if (fork() == 0) {
\r
2652 execl(cfg, "cfgpeopsxgl", arg, NULL);
\r
2658 strcpy(cfg, "./cfg/cfgpeopsxgl");
\r
2659 if (stat(cfg, &buf) != -1) {
\r
2660 if (fork() == 0) {
\r
2661 execl(cfg, "cfgpeopsxgl", arg, NULL);
\r
2667 sprintf(cfg, "%s/.pcsx/plugins/cfg/cfgpeopsxgl", getenv("HOME"));
\r
2668 if (stat(cfg, &buf) != -1) {
\r
2669 if (fork() == 0) {
\r
2670 execl(cfg, "cfgpeopsxgl", arg, NULL);
\r
2676 printf("ERROR: cfgpeopsxgl file not found!\n");
\r
2679 long CALLBACK GPUconfigure(void)
\r
2681 StartCfgTool("CFG");
\r
2685 ////////////////////////////////////////////////////////////////////////
\r
2686 // sets all kind of act fixes
\r
2687 ////////////////////////////////////////////////////////////////////////
\r
2689 void SetFixes(void)
\r
2693 if(dwActFixes & 0x2000)
\r
2694 dispWidths[4]=384;
\r
2695 else dispWidths[4]=368;
\r
2698 ////////////////////////////////////////////////////////////////////////
\r
2699 // Pete Special: make an 'intelligent' dma chain check (<-Tekken3)
\r
2700 ////////////////////////////////////////////////////////////////////////
\r
2702 uint32_t lUsedAddr[3];
\r
2704 __inline BOOL CheckForEndlessLoop(uint32_t laddr)
\r
2706 if(laddr==lUsedAddr[1]) return TRUE;
\r
2707 if(laddr==lUsedAddr[2]) return TRUE;
\r
2709 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
\r
2710 else lUsedAddr[2]=laddr;
\r
2711 lUsedAddr[0]=laddr;
\r
2715 ////////////////////////////////////////////////////////////////////////
\r
2716 // core gives a dma chain to gpu: same as the gpuwrite interface funcs
\r
2717 ////////////////////////////////////////////////////////////////////////
\r
2719 long CALLBACK GPUdmaChain(uint32_t *baseAddrL, uint32_t addr)
\r
2722 unsigned char * baseAddrB;
\r
2723 short count;unsigned int DMACommandCounter = 0;
\r
2725 if(bIsFirstFrame) GLinitialize();
\r
2729 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
\r
2731 baseAddrB = (unsigned char*) baseAddrL;
\r
2735 if(iGPUHeight==512) addr&=0x1FFFFC;
\r
2737 if(DMACommandCounter++ > 2000000) break;
\r
2738 if(CheckForEndlessLoop(addr)) break;
\r
2740 count = baseAddrB[addr+3];
\r
2744 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
\r
2746 addr = baseAddrL[addr>>2]&0xffffff;
\r
2748 while (addr != 0xffffff);
\r
2755 ////////////////////////////////////////////////////////////////////////
\r
2757 ////////////////////////////////////////////////////////////////////////
\r
2759 void CALLBACK GPUabout(void)
\r
2761 StartCfgTool("ABOUT");
\r
2764 ////////////////////////////////////////////////////////////////////////
\r
2765 // We are ever fine ;)
\r
2766 ////////////////////////////////////////////////////////////////////////
\r
2768 long CALLBACK GPUtest(void)
\r
2770 // if test fails this function should return negative value for error (unable to continue)
\r
2771 // and positive value for warning (can continue but output might be crappy)
\r
2776 ////////////////////////////////////////////////////////////////////////
\r
2777 // save state funcs
\r
2778 ////////////////////////////////////////////////////////////////////////
\r
2780 typedef struct GPUFREEZETAG
\r
2782 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
\r
2783 uint32_t ulStatus; // current gpu status
\r
2784 uint32_t ulControl[256]; // latest control register values
\r
2785 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
\r
2788 ////////////////////////////////////////////////////////////////////////
\r
2790 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
\r
2792 if(ulGetFreezeData==2)
\r
2794 int lSlotNum=*((int *)pF);
\r
2795 if(lSlotNum<0) return 0;
\r
2796 if(lSlotNum>8) return 0;
\r
2797 lSelectedSlot=lSlotNum+1;
\r
2801 if(!pF) return 0;
\r
2802 if(pF->ulFreezeVersion!=1) return 0;
\r
2804 if(ulGetFreezeData==1)
\r
2806 pF->ulStatus=STATUSREG;
\r
2807 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
\r
2808 memcpy(pF->psxVRam, psxVub, 1024*iGPUHeight*2);
\r
2813 if(ulGetFreezeData!=0) return 0;
\r
2815 STATUSREG=pF->ulStatus;
\r
2816 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
\r
2817 memcpy(psxVub, pF->psxVRam, 1024*iGPUHeight*2);
\r
2819 ResetTextureArea(TRUE);
\r
2821 GPUwriteStatus(ulStatusControl[0]);
\r
2822 GPUwriteStatus(ulStatusControl[1]);
\r
2823 GPUwriteStatus(ulStatusControl[2]);
\r
2824 GPUwriteStatus(ulStatusControl[3]);
\r
2825 GPUwriteStatus(ulStatusControl[8]);
\r
2826 GPUwriteStatus(ulStatusControl[6]);
\r
2827 GPUwriteStatus(ulStatusControl[7]);
\r
2828 GPUwriteStatus(ulStatusControl[5]);
\r
2829 GPUwriteStatus(ulStatusControl[4]);
\r
2834 ////////////////////////////////////////////////////////////////////////
\r
2835 // special "emu infos" / "emu effects" functions
\r
2836 ////////////////////////////////////////////////////////////////////////
\r
2841 //11 = transparent
\r
2843 unsigned char cFont[10][120]=
\r
2846 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
2847 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2848 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2849 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2850 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2851 0x80,0x00,0x05,0x54,0x00,0x00,
\r
2852 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2853 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2854 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2855 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2856 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2857 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2858 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2859 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2860 0x80,0x00,0x05,0x54,0x00,0x00,
\r
2861 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2862 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2863 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2864 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2865 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
2868 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
2869 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2870 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2871 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2872 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2873 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2874 0x80,0x00,0x05,0x50,0x00,0x00,
\r
2875 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2876 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2877 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2878 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2879 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2880 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2881 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2882 0x80,0x00,0x05,0x55,0x00,0x00,
\r
2883 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2884 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2885 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2886 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2887 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
2890 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
2891 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2892 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2893 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2894 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2895 0x80,0x00,0x05,0x54,0x00,0x00,
\r
2896 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2897 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2898 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2899 0x80,0x00,0x00,0x14,0x00,0x00,
\r
2900 0x80,0x00,0x00,0x50,0x00,0x00,
\r
2901 0x80,0x00,0x01,0x40,0x00,0x00,
\r
2902 0x80,0x00,0x05,0x00,0x00,0x00,
\r
2903 0x80,0x00,0x14,0x00,0x00,0x00,
\r
2904 0x80,0x00,0x15,0x55,0x00,0x00,
\r
2905 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2906 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2907 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2908 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2909 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
2912 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
2913 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2914 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2915 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2916 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2917 0x80,0x00,0x05,0x54,0x00,0x00,
\r
2918 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2919 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2920 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2921 0x80,0x00,0x01,0x54,0x00,0x00,
\r
2922 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2923 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2924 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2925 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2926 0x80,0x00,0x05,0x54,0x00,0x00,
\r
2927 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2928 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2929 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2930 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2931 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
2934 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
2935 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2936 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2937 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2938 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2939 0x80,0x00,0x00,0x14,0x00,0x00,
\r
2940 0x80,0x00,0x00,0x54,0x00,0x00,
\r
2941 0x80,0x00,0x01,0x54,0x00,0x00,
\r
2942 0x80,0x00,0x01,0x54,0x00,0x00,
\r
2943 0x80,0x00,0x05,0x14,0x00,0x00,
\r
2944 0x80,0x00,0x14,0x14,0x00,0x00,
\r
2945 0x80,0x00,0x15,0x55,0x00,0x00,
\r
2946 0x80,0x00,0x00,0x14,0x00,0x00,
\r
2947 0x80,0x00,0x00,0x14,0x00,0x00,
\r
2948 0x80,0x00,0x00,0x55,0x00,0x00,
\r
2949 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2950 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2951 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2952 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2953 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
2956 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
2957 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2958 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2959 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2960 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2961 0x80,0x00,0x15,0x55,0x00,0x00,
\r
2962 0x80,0x00,0x14,0x00,0x00,0x00,
\r
2963 0x80,0x00,0x14,0x00,0x00,0x00,
\r
2964 0x80,0x00,0x14,0x00,0x00,0x00,
\r
2965 0x80,0x00,0x15,0x54,0x00,0x00,
\r
2966 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2967 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2968 0x80,0x00,0x00,0x05,0x00,0x00,
\r
2969 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2970 0x80,0x00,0x05,0x54,0x00,0x00,
\r
2971 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2972 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2973 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2974 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2975 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
2978 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
2979 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2980 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2981 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2982 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2983 0x80,0x00,0x01,0x54,0x00,0x00,
\r
2984 0x80,0x00,0x05,0x00,0x00,0x00,
\r
2985 0x80,0x00,0x14,0x00,0x00,0x00,
\r
2986 0x80,0x00,0x14,0x00,0x00,0x00,
\r
2987 0x80,0x00,0x15,0x54,0x00,0x00,
\r
2988 0x80,0x00,0x15,0x05,0x00,0x00,
\r
2989 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2990 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2991 0x80,0x00,0x14,0x05,0x00,0x00,
\r
2992 0x80,0x00,0x05,0x54,0x00,0x00,
\r
2993 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2994 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2995 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2996 0x80,0x00,0x00,0x00,0x00,0x00,
\r
2997 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
3000 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
3001 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3002 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3003 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3004 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3005 0x80,0x00,0x15,0x55,0x00,0x00,
\r
3006 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3007 0x80,0x00,0x00,0x14,0x00,0x00,
\r
3008 0x80,0x00,0x00,0x14,0x00,0x00,
\r
3009 0x80,0x00,0x00,0x50,0x00,0x00,
\r
3010 0x80,0x00,0x00,0x50,0x00,0x00,
\r
3011 0x80,0x00,0x01,0x40,0x00,0x00,
\r
3012 0x80,0x00,0x01,0x40,0x00,0x00,
\r
3013 0x80,0x00,0x05,0x00,0x00,0x00,
\r
3014 0x80,0x00,0x05,0x00,0x00,0x00,
\r
3015 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3016 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3017 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3018 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3019 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
3022 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
3023 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3024 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3025 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3026 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3027 0x80,0x00,0x05,0x54,0x00,0x00,
\r
3028 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3029 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3030 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3031 0x80,0x00,0x05,0x54,0x00,0x00,
\r
3032 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3033 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3034 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3035 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3036 0x80,0x00,0x05,0x54,0x00,0x00,
\r
3037 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3038 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3039 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3040 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3041 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
3044 {0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
\r
3045 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3046 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3047 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3048 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3049 0x80,0x00,0x05,0x54,0x00,0x00,
\r
3050 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3051 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3052 0x80,0x00,0x14,0x05,0x00,0x00,
\r
3053 0x80,0x00,0x14,0x15,0x00,0x00,
\r
3054 0x80,0x00,0x05,0x55,0x00,0x00,
\r
3055 0x80,0x00,0x00,0x05,0x00,0x00,
\r
3056 0x80,0x00,0x00,0x05,0x00,0x00,
\r
3057 0x80,0x00,0x00,0x14,0x00,0x00,
\r
3058 0x80,0x00,0x05,0x50,0x00,0x00,
\r
3059 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3060 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3061 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3062 0x80,0x00,0x00,0x00,0x00,0x00,
\r
3063 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
\r
3067 ////////////////////////////////////////////////////////////////////////
\r
3069 void PaintPicDot(unsigned char * p,unsigned char c)
\r
3071 if(c==0) {*p++=0x00;*p++=0x00;*p=0x00;return;}
\r
3072 if(c==1) {*p++=0xff;*p++=0xff;*p=0xff;return;}
\r
3073 if(c==2) {*p++=0x00;*p++=0x00;*p=0xff;return;}
\r
3076 ////////////////////////////////////////////////////////////////////////
\r
3078 void CALLBACK GPUgetScreenPic(unsigned char * pMem)
\r
3080 float XS,YS;int x,y,v;
\r
3081 unsigned char * ps, * px, * pf;
\r
3084 if(!pGfxCardScreen)
\r
3086 glPixelStorei(GL_PACK_ALIGNMENT,1);
\r
3087 pGfxCardScreen=(unsigned char *)malloc(iResX*iResY*4);
\r
3090 ps=pGfxCardScreen;
\r
3092 glReadBuffer(GL_FRONT);
\r
3094 glReadPixels(0,0,iResX,iResY,GL_RGB,GL_UNSIGNED_BYTE,ps);
\r
3096 glReadBuffer(GL_BACK);
\r
3098 XS=(float)iResX/128;
\r
3099 YS=(float)iResY/96;
\r
3104 for(x=0;x<128;x++)
\r
3106 px=ps+(3*((int)((float)x * XS))+
\r
3107 (3*iResX)*((int)((float)y*YS)));
\r
3115 /////////////////////////////////////////////////////////////////////
\r
3116 // generic number/border painter
\r
3124 c=cFont[lSelectedSlot][x+y*6];
\r
3126 PaintPicDot(pf,(unsigned char)v);pf+=3; // paint the dots into the rect
\r
3128 PaintPicDot(pf,(unsigned char)v);pf+=3;
\r
3130 PaintPicDot(pf,(unsigned char)v);pf+=3;
\r
3132 PaintPicDot(pf,(unsigned char)v);pf+=3;
\r
3138 for(x=0;x<128;x++)
\r
3140 *(pf+(95*128*3))=0x00;*pf++=0x00;
\r
3141 *(pf+(95*128*3))=0x00;*pf++=0x00;
\r
3142 *(pf+(95*128*3))=0xff;*pf++=0xff;
\r
3147 *(pf+(127*3))=0x00;*pf++=0x00;
\r
3148 *(pf+(127*3))=0x00;*pf++=0x00;
\r
3149 *(pf+(127*3))=0xff;*pf++=0xff;
\r
3155 ////////////////////////////////////////////////////////////////////////
\r
3157 void CALLBACK GPUshowScreenPic(unsigned char * pMem)
\r
3160 if(pMem==0) return;
\r
3164 ////////////////////////////////////////////////////////////////////////
\r
3166 void CALLBACK GPUsetfix(uint32_t dwFixBits)
\r
3168 dwEmuFixes=dwFixBits;
\r
3171 ////////////////////////////////////////////////////////////////////////
\r
3173 void CALLBACK GPUvisualVibration(uint32_t iSmall, uint32_t iBig)
\r
3177 if(PSXDisplay.DisplayModeNew.x) // calc min "shake pixel" from screen width
\r
3178 iVibVal=max(1,iResX/PSXDisplay.DisplayModeNew.x);
\r
3180 // big rumble: 4...15 sp ; small rumble 1...3 sp
\r
3181 if(iBig) iRumbleVal=max(4*iVibVal,min(15*iVibVal,((int)iBig *iVibVal)/10));
\r
3182 else iRumbleVal=max(1*iVibVal,min( 3*iVibVal,((int)iSmall*iVibVal)/10));
\r
3184 srand(timeGetTime()); // init rand (will be used in BufferSwap)
\r
3186 iRumbleTime=15; // let the rumble last 16 buffer swaps
\r
3189 ////////////////////////////////////////////////////////////////////////
\r
3190 // main emu can set display infos (A/M/G/D)
\r
3191 ////////////////////////////////////////////////////////////////////////
\r
3193 void CALLBACK GPUdisplayFlags(uint32_t dwFlags)
\r
3195 dwCoreFlags=dwFlags;
\r