* win32: speed up screen blitting

This commit is contained in:
ansstuff 2013-02-03 16:03:25 +00:00
parent 181c48efdb
commit d3f0cb48b7
3 changed files with 132 additions and 138 deletions

View File

@ -40,7 +40,7 @@ static int bpp;
static int vflags;
static int veflags;
int disvaccel = 1; //Disable video hardware acceleration. 1 by default (meaning disable in windowed but not Fullscreen)
int disvaccel = 1; // Disable video hardware acceleration. By default it's disabled in windowed, but enabled in Fullscreen mode
int fssync=0;
int winsync=0;
@ -77,16 +77,14 @@ LPDIRECTDRAWPALETTE lpddpal = 0;
DDSURFACEDESC2 ddsd;
DDSURFACEDESC2 ddsdback;
DDSURFACEDESC2 ddsd_Resizable;
LPDIRECTDRAWSURFACE7 lpDDSPrimary=0;
LPDIRECTDRAWSURFACE7 lpDDSDBack=0;
LPDIRECTDRAWSURFACE7 lpDDSBack=0;
LPDIRECTDRAWSURFACE7 lpDDSResizable=0;
DDBLTFX blitfx = { sizeof(DDBLTFX) };
RECT resizable_surface_rect = {0};
RECT bestfitRect = {0};
#define RELEASE(x) if(x) { x->Release(); x = 0; }
@ -99,11 +97,7 @@ static void ShowDDErr(char *s)
int RestoreDD(int w)
{
if (w == 2) // lpDDSResizable
{
if(!lpDDSResizable) return 0;
if(IDirectDrawSurface7_Restore(lpDDSResizable)!=DD_OK) return 0;
} else if (w == 1) // lpDDSBack
if (w == 1) // lpDDSBack
{
if(!lpDDSBack) return 0;
if(IDirectDrawSurface7_Restore(lpDDSBack)!=DD_OK) return 0;
@ -250,73 +244,39 @@ static int InitBPPStuff(int fs)
return 1;
}
void RecreateResizableSurface(int width, int height)
void recalculateBestFitRect(int width, int height)
{
if (!lpDD7)
return; // DirectDraw isn't initialized yet
// delete old surface
RELEASE(lpDDSResizable);
// create new surface
memset(&ddsd_Resizable, 0, sizeof(ddsd_Resizable));
ddsd_Resizable.dwSize = sizeof(ddsd_Resizable);
ddsd_Resizable.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
ddsd_Resizable.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd_Resizable.dwWidth = width;
ddsd_Resizable.dwHeight = height;
ddrval = IDirectDraw7_CreateSurface(lpDD7, &ddsd_Resizable, &lpDDSResizable, (IUnknown FAR*)NULL);
if (ddrval != DD_OK)
{
//ShowDDErr("Error creating resizable surface.");
FCEU_printf("Error creating resizable surface.\n");
return;
}
RecolorResizableSurface();
// calculate resizable_surface_rect
// calculate bestfitRect
double current_aspectratio = (double)width / (double)height;
double needed_aspectratio = (double)(VNSWID) / (double)(FSettings.TotalScanlines());
if (eoptions & EO_TVASPECT)
needed_aspectratio = ((double)VNSWID / 256) * ((double)4 / 3);
if (current_aspectratio == needed_aspectratio)
{
resizable_surface_rect.left = 0;
resizable_surface_rect.right = width;
resizable_surface_rect.top = 0;
resizable_surface_rect.bottom = height;
bestfitRect.left = 0;
bestfitRect.right = width;
bestfitRect.top = 0;
bestfitRect.bottom = height;
} else if (current_aspectratio > needed_aspectratio)
{
// the window is wider than emulated screen
resizable_surface_rect.top = 0;
resizable_surface_rect.bottom = height;
bestfitRect.top = 0;
bestfitRect.bottom = height;
int center_x = width / 2;
double new_width = ((double)height * needed_aspectratio);
resizable_surface_rect.left = center_x - (new_width / 2);
resizable_surface_rect.right = resizable_surface_rect.left + new_width;
bestfitRect.left = center_x - (new_width / 2);
bestfitRect.right = bestfitRect.left + new_width;
} else
{
// the window is taller than emulated screen
resizable_surface_rect.left = 0;
resizable_surface_rect.right = width;
bestfitRect.left = 0;
bestfitRect.right = width;
int center_y = height / 2;
double new_height = ((double)width / needed_aspectratio);
resizable_surface_rect.top = center_y - (new_height / 2);
resizable_surface_rect.bottom = resizable_surface_rect.top + new_height;
}
}
void RecolorResizableSurface()
{
if (eoptions & EO_BGCOLOR)
{
// fill the surface using BG color from PPU
unsigned char r, g, b;
FCEUD_GetPalette(0x80 | PALRAM[0], &r, &g, &b);
blitfx.dwFillColor = (r << 16) + (g << 8) + b;
ddrval = IDirectDrawSurface7_Blt(lpDDSResizable, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
} else
{
// fill the surface with black color
blitfx.dwFillColor = 0;
ddrval = IDirectDrawSurface7_Blt(lpDDSResizable, NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &blitfx);
bestfitRect.top = center_y - (new_height / 2);
bestfitRect.bottom = bestfitRect.top + new_height;
}
}
@ -487,11 +447,8 @@ int SetVideoMode(int fs)
}
}
if ((vmodes[vmod].flags & VMDF_STRFS) && (eoptions & EO_BESTFIT))
{
RecreateResizableSurface(vmodes[vmod].x, vmodes[vmod].y);
}
if (eoptions & EO_BESTFIT)
recalculateBestFitRect(vmodes[vmod].x, vmodes[vmod].y);
// create foreground surface
@ -601,8 +558,7 @@ static void BlitScreenWindow(unsigned char *XBuf)
{
int pitch;
unsigned char *ScreenLoc;
static RECT srect;
RECT wrect;
static RECT srect, wrect, blitRect;
int specialmul;
if (!lpDDSBack) return;
@ -629,7 +585,8 @@ static void BlitScreenWindow(unsigned char *XBuf)
ddrval=IDirectDrawSurface7_Lock(lpDDSBack,NULL,&ddsdback, 0, NULL);
if (ddrval != DD_OK)
{
if(ddrval==DDERR_SURFACELOST) RestoreDD(1);
if (ddrval == DDERR_SURFACELOST)
RestoreDD(1);
return;
}
@ -645,44 +602,66 @@ static void BlitScreenWindow(unsigned char *XBuf)
IDirectDrawSurface7_Unlock(lpDDSBack, NULL);
if (eoptions & EO_BESTFIT && (resizable_surface_rect.top || resizable_surface_rect.left))
{
// clear lpDDSResizable surface
if (eoptions & EO_BGCOLOR)
RecolorResizableSurface();
// blit from lpDDSBack to lpDDSResizable using best fit
if (IDirectDrawSurface7_Blt(lpDDSResizable, &resizable_surface_rect, lpDDSBack, &srect, DDBLT_ASYNC, 0) != DD_OK)
{
ddrval = IDirectDrawSurface7_Blt(lpDDSResizable, &resizable_surface_rect, lpDDSBack, &srect, DDBLT_WAIT, 0);
if(ddrval != DD_OK)
{
if(ddrval == DDERR_SURFACELOST)
{
RestoreDD(2);
RestoreDD(1);
}
return;
}
}
// blit from lpDDSResizable to screen (lpDDSPrimary)
FCEUD_VerticalSync(); // aquanull 2011-11-28 fix tearing
if (IDirectDrawSurface7_Blt(lpDDSPrimary, &wrect, lpDDSResizable, NULL, DDBLT_ASYNC, 0) != DD_OK)
if (eoptions & EO_BESTFIT && (bestfitRect.top || bestfitRect.left))
{
ddrval = IDirectDrawSurface7_Blt(lpDDSPrimary, &wrect, lpDDSResizable, NULL, DDBLT_WAIT, 0);
// blit with resizing
blitRect.top = wrect.top + bestfitRect.top;
blitRect.bottom = blitRect.top + bestfitRect.bottom - bestfitRect.top;
blitRect.left = wrect.left + bestfitRect.left;
blitRect.right = blitRect.left + bestfitRect.right - bestfitRect.left;
if (IDirectDrawSurface7_Blt(lpDDSPrimary, &blitRect, lpDDSBack, &srect, DDBLT_ASYNC, 0) != DD_OK)
{
ddrval = IDirectDrawSurface7_Blt(lpDDSPrimary, &blitRect, lpDDSBack, &srect, DDBLT_WAIT, 0);
if(ddrval != DD_OK)
{
if(ddrval == DDERR_SURFACELOST)
{
RestoreDD(2);
RestoreDD(1);
RestoreDD(0);
}
return;
}
}
// clear borders
if (eoptions & EO_BGCOLOR)
{
// fill the surface using BG color from PPU
unsigned char r, g, b;
FCEUD_GetPalette(0x80 | PALRAM[0], &r, &g, &b);
blitfx.dwFillColor = (r << 16) + (g << 8) + b;
} else
{
// blit directly from lpDDSBack to screen (lpDDSPrimary)
FCEUD_VerticalSync(); // aquanull 2011-11-28 fix tearing
blitfx.dwFillColor = 0;
}
if (bestfitRect.top)
{
// upper border
blitRect.top = wrect.top;
blitRect.bottom = wrect.top + bestfitRect.top;
blitRect.left = wrect.left;
blitRect.right = wrect.right;
IDirectDrawSurface7_Blt(lpDDSPrimary, &blitRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
// lower border
blitRect.top += bestfitRect.bottom;
blitRect.bottom = wrect.bottom;
IDirectDrawSurface7_Blt(lpDDSPrimary, &blitRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
} else
{
// left border
blitRect.top = wrect.top;
blitRect.bottom = wrect.bottom;
blitRect.left = wrect.left;
blitRect.right = wrect.left + bestfitRect.left;
IDirectDrawSurface7_Blt(lpDDSPrimary, &blitRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
// right border
blitRect.left += bestfitRect.right;
blitRect.right = wrect.right;
IDirectDrawSurface7_Blt(lpDDSPrimary, &blitRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
}
} else
{
// blit without resizing
if(IDirectDrawSurface7_Blt(lpDDSPrimary, &wrect, lpDDSBack, &srect, DDBLT_ASYNC, 0) != DD_OK)
{
ddrval = IDirectDrawSurface7_Blt(lpDDSPrimary, &wrect, lpDDSBack, &srect, DDBLT_WAIT, 0);
@ -769,12 +748,13 @@ static void BlitScreenFull(uint8 *XBuf)
srect.right=VNSWID * specmul;
srect.bottom=FSettings.TotalScanlines() * specmul;
if(vmodes[vmod].flags&VMDF_STRFS)
{
//if(vmodes[vmod].flags&VMDF_STRFS)
//{
drect.top=0;
drect.left=0;
drect.right=vmodes[vmod].x;
drect.bottom=vmodes[vmod].y;
/*
}
else
{
@ -782,8 +762,6 @@ static void BlitScreenFull(uint8 *XBuf)
drect.bottom=drect.top+(FSettings.TotalScanlines()*vmodes[vmod].yscale);
drect.left=(vmodes[vmod].x-VNSWID*vmodes[vmod].xscale)>>1;
drect.right=drect.left+VNSWID*vmodes[vmod].xscale;
RECT fullScreen;
fullScreen.left = fullScreen.top = 0;
fullScreen.right = vmodes[vmod].x;
@ -803,6 +781,7 @@ static void BlitScreenFull(uint8 *XBuf)
DD_FillRect(lpDDSVPrimary,left,bottom,right,fullScreen.bottom,RGB(255,0,255)); //bottomcenter
DD_FillRect(lpDDSVPrimary,right,bottom,fullScreen.right,fullScreen.bottom,RGB(0,255,255)); //bottomright
}
*/
} else
{
// start rendering directly to screen
@ -964,48 +943,63 @@ static void BlitScreenFull(uint8 *XBuf)
if(vmodes[vmod].flags&VMDF_DXBLT)
{
IDirectDrawSurface7_Unlock(lpDDSBack, NULL);
if (eoptions & EO_BESTFIT && (resizable_surface_rect.top || resizable_surface_rect.left) && !vmod)
{
// clear lpDDSResizable surface
RecolorResizableSurface();
// blit from lpDDSBack to lpDDSResizable using best fit
if (IDirectDrawSurface7_Blt(lpDDSResizable, &resizable_surface_rect, lpDDSBack, &srect, DDBLT_ASYNC, 0) != DD_OK)
{
ddrval = IDirectDrawSurface7_Blt(lpDDSResizable, &resizable_surface_rect, lpDDSBack, &srect, DDBLT_WAIT, 0);
if(ddrval != DD_OK)
{
if(ddrval == DDERR_SURFACELOST)
{
RestoreDD(2);
RestoreDD(1);
}
return;
}
}
// blit from lpDDSResizable to screen
RECT fullScreen;
fullScreen.left = fullScreen.top = 0;
fullScreen.right = vmodes[vmod].x;
fullScreen.bottom = vmodes[vmod].y;
FCEUD_VerticalSync();
if (IDirectDrawSurface7_Blt(lpDDSVPrimary, &fullScreen, lpDDSResizable, &fullScreen, DDBLT_ASYNC, 0) != DD_OK)
if (eoptions & EO_BESTFIT && (bestfitRect.top || bestfitRect.left) && !vmod)
{
ddrval = IDirectDrawSurface7_Blt(lpDDSVPrimary, &fullScreen, lpDDSResizable, &fullScreen, DDBLT_WAIT, 0);
// blit with resizing
if (IDirectDrawSurface7_Blt(lpDDSVPrimary, &bestfitRect, lpDDSBack, &srect, DDBLT_ASYNC, 0) != DD_OK)
{
ddrval = IDirectDrawSurface7_Blt(lpDDSVPrimary, &bestfitRect, lpDDSBack, &srect, DDBLT_WAIT, 0);
if(ddrval != DD_OK)
{
if(ddrval == DDERR_SURFACELOST)
{
RestoreDD(2);
RestoreDD(1);
RestoreDD(0);
}
return;
}
}
// clear borders
if (eoptions & EO_BGCOLOR)
{
// fill the surface using BG color from PPU
unsigned char r, g, b;
FCEUD_GetPalette(0x80 | PALRAM[0], &r, &g, &b);
blitfx.dwFillColor = (r << 16) + (g << 8) + b;
} else
{
// blit directly from lpDDSBack to screen
FCEUD_VerticalSync();
blitfx.dwFillColor = 0;
}
static RECT borderRect;
if (bestfitRect.top)
{
// upper border
borderRect.top = drect.top;
borderRect.bottom = drect.top + bestfitRect.top;
borderRect.left = drect.left;
borderRect.right = drect.right;
IDirectDrawSurface7_Blt(lpDDSPrimary, &borderRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
// lower border
borderRect.top += bestfitRect.bottom;
borderRect.bottom = drect.bottom;
IDirectDrawSurface7_Blt(lpDDSPrimary, &borderRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
} else
{
// left border
borderRect.top = drect.top;
borderRect.bottom = drect.bottom;
borderRect.left = drect.left;
borderRect.right = drect.left + bestfitRect.left;
IDirectDrawSurface7_Blt(lpDDSPrimary, &borderRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
// right border
borderRect.left += bestfitRect.right;
borderRect.right = drect.right;
IDirectDrawSurface7_Blt(lpDDSPrimary, &borderRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &blitfx);
}
} else
{
/*
if(veflags&2)
{
// clear screen surface (is that really necessary?)
@ -1016,15 +1010,17 @@ static void BlitScreenFull(uint8 *XBuf)
veflags&=~2;
}
}
if(IDirectDrawSurface7_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_ASYNC,0)!=DD_OK)
*/
// blit without resizing
if(IDirectDrawSurface7_Blt(lpDDSVPrimary, NULL, lpDDSBack, &srect, DDBLT_ASYNC,0)!=DD_OK)
{
ddrval=IDirectDrawSurface7_Blt(lpDDSVPrimary, &drect,lpDDSBack,&srect,DDBLT_WAIT,0);
ddrval=IDirectDrawSurface7_Blt(lpDDSVPrimary, NULL, lpDDSBack, &srect, DDBLT_WAIT,0);
if(ddrval!=DD_OK)
{
if(ddrval==DDERR_SURFACELOST)
{
RestoreDD(0);
RestoreDD(1);
RestoreDD(0);
}
return;
}
@ -1055,7 +1051,6 @@ void ResetVideo(void)
RELEASE(lpddpal);
RELEASE(lpDDSBack);
RELEASE(lpDDSPrimary);
RELEASE(lpDDSResizable);
RELEASE(lpClipper);
RELEASE(lpDD7);
}

View File

@ -49,8 +49,7 @@ extern int winsync;
void SetFSVideoMode();
void FCEUD_BlitScreen(uint8 *XBuf);
void ConfigVideo();
void RecreateResizableSurface(int width, int height);
void RecolorResizableSurface();
void recalculateBestFitRect(int width, int height);
int SetVideoMode(int fs);
void DoVideoConfigFix();
void FCEUD_BlitScreen(uint8 *XBuf);

View File

@ -1121,29 +1121,29 @@ void LoadNewGamey(HWND hParent, const char *initialdir)
void GetMouseData(uint32 (&md)[3])
{
extern RECT resizable_surface_rect;
extern RECT bestfitRect;
if (eoptions & EO_BESTFIT && (resizable_surface_rect.top || resizable_surface_rect.left))
if (eoptions & EO_BESTFIT && (bestfitRect.top || bestfitRect.left))
{
if ((int)mousex <= resizable_surface_rect.left)
if ((int)mousex <= bestfitRect.left)
{
md[0] = 0;
} else if ((int)mousex >= resizable_surface_rect.right)
} else if ((int)mousex >= bestfitRect.right)
{
md[0] = VNSWID;
} else
{
md[0] = VNSWID * (mousex - resizable_surface_rect.left) / (resizable_surface_rect.right - resizable_surface_rect.left);
md[0] = VNSWID * (mousex - bestfitRect.left) / (bestfitRect.right - bestfitRect.left);
}
if ((int)mousey <= resizable_surface_rect.top)
if ((int)mousey <= bestfitRect.top)
{
md[1] = 0;
} else if ((int)mousey >= resizable_surface_rect.bottom)
} else if ((int)mousey >= bestfitRect.bottom)
{
md[1] = FSettings.TotalScanlines();
} else
{
md[1] = FSettings.TotalScanlines() * (mousey - resizable_surface_rect.top) / (resizable_surface_rect.bottom - resizable_surface_rect.top);
md[1] = FSettings.TotalScanlines() * (mousey - bestfitRect.top) / (bestfitRect.bottom - bestfitRect.top);
}
} else
{
@ -2620,7 +2620,7 @@ void SetMainWindowStuff()
{
RECT client_recr;
GetClientRect(hAppWnd, &client_recr);
RecreateResizableSurface(client_recr.right - client_recr.left, client_recr.bottom - client_recr.top);
recalculateBestFitRect(client_recr.right - client_recr.left, client_recr.bottom - client_recr.top);
}
}