Merge pull request #289 from PatrickvL/master

UpdateOverlay improvements
This commit is contained in:
Luke Usher 2017-03-30 13:06:11 +01:00 committed by GitHub
commit 0e63d5055f
1 changed files with 93 additions and 67 deletions

View File

@ -366,6 +366,20 @@ VOID CxbxSetPixelContainerHeader
; ;
} }
VOID CxbxReleaseBackBufferLock()
{
XTL::IDirect3DSurface8 *pBackBuffer = nullptr;
if (D3D_OK == g_pD3DDevice8->GetBackBuffer(0, XTL::D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))
{
// TODO : assert(pBackBuffer != nullptr);
pBackBuffer->UnlockRect();
pBackBuffer->Release();
}
}
// Direct3D initialization (called before emulation begins) // Direct3D initialization (called before emulation begins)
VOID XTL::EmuD3DInit() VOID XTL::EmuD3DInit()
{ {
@ -4273,14 +4287,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Present)
HRESULT hRet = S_OK; HRESULT hRet = S_OK;
// release back buffer lock CxbxReleaseBackBufferLock();
{
IDirect3DSurface8 *pBackBuffer;
g_pD3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
pBackBuffer->UnlockRect();
}
// TODO: Make a video option to wait for VBlank before calling Present. // TODO: Make a video option to wait for VBlank before calling Present.
// Makes syncing to 30fps easier (which is the native frame rate for Azurik // Makes syncing to 30fps easier (which is the native frame rate for Azurik
@ -4351,14 +4358,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_Swap)
if(Flags != 0) if(Flags != 0)
EmuWarning("XTL::EmuD3DDevice_Swap: Flags != 0"); EmuWarning("XTL::EmuD3DDevice_Swap: Flags != 0");
// release back buffer lock CxbxReleaseBackBufferLock();
{
IDirect3DSurface8 *pBackBuffer;
g_pD3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
if(pBackBuffer) pBackBuffer->UnlockRect();
}
// TODO: Make a video option to wait for VBlank before calling Present. // TODO: Make a video option to wait for VBlank before calling Present.
// Makes syncing to 30fps easier (which is the native frame rate for Azurik // Makes syncing to 30fps easier (which is the native frame rate for Azurik
@ -6010,6 +6010,13 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_EnableOverlay)
return; return;
} }
// Based on http://codereview.stackexchange.com/questions/6502/fastest-way-to-clamp-an-integer-to-the-range-0-255
inline uint08 ClampIntToByte(int x)
{
int r = x > 255 ? 255 : x;
return r < 0 ? 0 : (uint08)r;
}
// ****************************************************************** // ******************************************************************
// * patch: D3DDevice_UpdateOverlay // * patch: D3DDevice_UpdateOverlay
// ****************************************************************** // ******************************************************************
@ -6042,12 +6049,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
DDSURFACEDESC2 ddsd2; DDSURFACEDESC2 ddsd2;
ZeroMemory(&ddsd2, sizeof(ddsd2)); ZeroMemory(&ddsd2, sizeof(ddsd2));
ddsd2.dwSize = sizeof(ddsd2); ddsd2.dwSize = sizeof(ddsd2);
if(FAILED(g_pDDSOverlay7->Lock(NULL, &ddsd2, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL))) if(FAILED(g_pDDSOverlay7->Lock(NULL, &ddsd2, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL)))
EmuWarning("Unable to lock overlay surface!"); EmuWarning("Unable to lock overlay surface!");
else
// copy data // copy data
{ {
char *pDest = (char*)ddsd2.lpSurface; char *pDest = (char*)ddsd2.lpSurface;
@ -6069,10 +6074,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
pSour += g_dwOverlayP; pSour += g_dwOverlayP;
} }
} }
}
g_pDDSOverlay7->Unlock(NULL); g_pDDSOverlay7->Unlock(NULL);
} }
}
// update overlay! // update overlay!
if(g_bSupportsYUY2) if(g_bSupportsYUY2)
@ -6102,7 +6107,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
DDOVERLAYFX ddofx; DDOVERLAYFX ddofx;
ZeroMemory(&ddofx, sizeof(ddofx)); ZeroMemory(&ddofx, sizeof(ddofx));
ddofx.dwSize = sizeof(DDOVERLAYFX); ddofx.dwSize = sizeof(DDOVERLAYFX);
ddofx.dckDestColorkey.dwColorSpaceLowValue = 0; ddofx.dckDestColorkey.dwColorSpaceLowValue = 0;
ddofx.dckDestColorkey.dwColorSpaceHighValue = 0; ddofx.dckDestColorkey.dwColorSpaceHighValue = 0;
@ -6115,79 +6119,100 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
D3DLOCKED_RECT LockedRectDest; D3DLOCKED_RECT LockedRectDest;
IDirect3DSurface8 *pBackBuffer = 0; IDirect3DSurface8 *pBackBuffer = 0;
HRESULT hRet = g_pD3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer); HRESULT hRet = g_pD3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer);
// if we obtained the backbuffer, manually translate the YUY2 into the backbuffer format // if we obtained the backbuffer, manually translate the YUY2 into the backbuffer format
if (hRet == D3D_OK && pBackBuffer->LockRect(&LockedRectDest, NULL, NULL) == D3D_OK) if (hRet == D3D_OK && pBackBuffer->LockRect(&LockedRectDest, NULL, NULL) == D3D_OK)
{ {
uint08 *pCurByte = (uint08*)pSurface->Lock; uint08 *pbSource = (uint08*)pSurface->Lock;
uint08 *pbDest = (uint08*)LockedRectDest.pBits;
uint08 *pDest = (uint08*)LockedRectDest.pBits;
uint32 dx = 0, dy = 0; uint32 dx = 0, dy = 0;
uint32 dwImageSize = g_dwOverlayP*g_dwOverlayH; uint32 dwImageSize = g_dwOverlayP*g_dwOverlayH;
// grayscale // Get backbuffer dimenions; TODO : remember this once, at creation/resize time
D3DSURFACE_DESC BackBufferDesc;
pBackBuffer->GetDesc(&BackBufferDesc);
// Limit the width and height of the output to the backbuffer dimensions.
// This will (hopefully) prevent exceptions in Blinx - The Time Sweeper
// (see https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/285)
uint32 W = min(g_dwOverlayW, BackBufferDesc.Width);
uint32 H = min(g_dwOverlayH, BackBufferDesc.Height);
// grayscale - TODO : Either remove or make configurable
if(false) if(false)
{ {
for(uint32 y=0;y<g_dwOverlayH;y++) // Clip to backbuffer height :
for(uint32 y=0;y<H;y++)
{ {
uint32 stop = g_dwOverlayW *4; uint32 stop = g_dwOverlayW *4;
for(uint32 x=0;x<stop;x+=4) for(uint32 x=0;x<stop;x+=4)
{ {
uint08 Y = *pCurByte; uint08 Y = *pbSource;
pDest[x+0] = Y; // Clip to backbuffer width :
pDest[x+1] = Y; if (x / 4 < W)
pDest[x+2] = Y; {
pDest[x+3] = 0xFF; pbDest[x + 0] = Y;
pbDest[x + 1] = Y;
pCurByte+=2; pbDest[x + 2] = Y;
pbDest[x + 3] = 0xFF;
} }
pDest += LockedRectDest.Pitch; pbSource += 2;
}
pbDest += LockedRectDest.Pitch;
} }
} }
// full color conversion (YUY2->XRGB) // full color conversion (YUY2->XRGB)
else else
{ {
// The following is a combination of https://pastebin.com/mDcwqJV3 and
// https://en.wikipedia.org/wiki/YUV#Y.E2.80.B2UV422_to_RGB888_conversion
const int K1 = int(1.402f * (1 << 16));
const int K2 = int(0.334f * (1 << 16));
const int K3 = int(0.714f * (1 << 16));
const int K4 = int(1.772f * (1 << 16));
for(uint32 v=0;v<dwImageSize;v+=4) for(uint32 v=0;v<dwImageSize;v+=4)
{ {
float Y[2], U, V; // Clip to backbuffer width :
if (dx < W)
Y[0] = *pCurByte++;
U = *pCurByte++;
Y[1] = *pCurByte++;
V = *pCurByte++;
int a=0;
for(int x=0;x<2;x++)
{ {
float R = Y[a] + 1.402f*(V-128); uint8_t Y0 = pbSource[0];
float G = Y[a] - 0.344f*(U-128) - 0.714f*(V-128); uint8_t Cb = pbSource[1];
float B = Y[a] + 1.772f*(U-128); uint8_t Y1 = pbSource[2];
uint8_t Cr = pbSource[3];
R = (R < 0) ? 0 : ((R > 255) ? 255 : R); int nCb = Cb - 128;
G = (G < 0) ? 0 : ((G > 255) ? 255 : G); int nCr = Cr - 128;
B = (B < 0) ? 0 : ((B > 255) ? 255 : B);
uint32 i = (dy*LockedRectDest.Pitch+(dx+x)*4); int Rd = (K1 * nCr) >> 16;
int Gd = ((K2 * nCb) + (K3 * nCr)) >> 16;
int Bd = (K4 * nCb) >> 16;
pDest[i+0] = (uint08)B; uint32 i = (dy * LockedRectDest.Pitch) + (dx * 4);
pDest[i+1] = (uint08)G;
pDest[i+2] = (uint08)R;
pDest[i+3] = 0xFF;
a++; pbDest[i + 0] = ClampIntToByte((int)Y0 + Bd);
pbDest[i + 1] = ClampIntToByte((int)Y0 - Gd);
pbDest[i + 2] = ClampIntToByte((int)Y0 + Rd);
pbDest[i + 3] = 0xFF;
pbDest[i + 4] = ClampIntToByte((int)Y1 + Bd);
pbDest[i + 5] = ClampIntToByte((int)Y1 - Gd);
pbDest[i + 6] = ClampIntToByte((int)Y1 + Rd);
pbDest[i + 7] = 0xFF;
} }
pbSource += 4;
dx += 2; dx += 2;
if ((dx % g_dwOverlayW) == 0) if ((dx % g_dwOverlayW) == 0)
{ {
dy++; dy++;
// Clip to backbuffer height :
if (dy >= H)
break;
dx = 0; dx = 0;
} }
@ -6195,6 +6220,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
} }
pBackBuffer->UnlockRect(); pBackBuffer->UnlockRect();
pBackBuffer->Release();
} }
// Update overlay if present was not called since the last call to // Update overlay if present was not called since the last call to