Merge pull request #383 from PatrickvL/OverlayFixes

Overlay fixes
This commit is contained in:
Luke Usher 2017-04-20 16:41:55 +01:00 committed by GitHub
commit 2eb34d69be
1 changed files with 77 additions and 84 deletions

View File

@ -62,8 +62,8 @@ namespace xboxkrnl
HWND g_hEmuWindow = NULL; // rendering window HWND g_hEmuWindow = NULL; // rendering window
XTL::LPDIRECT3DDEVICE8 g_pD3DDevice8 = NULL; // Direct3D8 Device XTL::LPDIRECT3DDEVICE8 g_pD3DDevice8 = NULL; // Direct3D8 Device
XTL::LPDIRECTDRAWSURFACE7 g_pDDSPrimary = NULL; // DirectDraw7 Primary Surface XTL::LPDIRECTDRAWSURFACE7 g_pDDSPrimary = NULL; // DirectDraw7 Primary Surface
XTL::LPDIRECTDRAWSURFACE7 g_pDDSOverlay7 = NULL; // DirectDraw7 Overlay Surface XTL::LPDIRECTDRAWSURFACE7 g_pDDSOverlay7 = nullptr; // DirectDraw7 Overlay Surface
XTL::LPDIRECTDRAWCLIPPER g_pDDClipper = NULL; // DirectDraw7 Clipper XTL::LPDIRECTDRAWCLIPPER g_pDDClipper = nullptr; // DirectDraw7 Clipper
DWORD g_CurrentVertexShader = 0; DWORD g_CurrentVertexShader = 0;
DWORD g_dwCurrentPixelShader = 0; DWORD g_dwCurrentPixelShader = 0;
XTL::PIXEL_SHADER *g_CurrentPixelShader = NULL; XTL::PIXEL_SHADER *g_CurrentPixelShader = NULL;
@ -84,6 +84,7 @@ static void EmuAdjustPower2(UINT *dwWidth, UINT *dwHeigh
static HMONITOR g_hMonitor = NULL; // Handle to DirectDraw monitor static HMONITOR g_hMonitor = NULL; // Handle to DirectDraw monitor
static BOOL g_bSupportsYUY2 = FALSE;// Does device support YUY2 overlays? static BOOL g_bSupportsYUY2 = FALSE;// Does device support YUY2 overlays?
static XTL::LPDIRECTDRAW7 g_pDD7 = NULL; // DirectDraw7 static XTL::LPDIRECTDRAW7 g_pDD7 = NULL; // DirectDraw7
static XTL::DDCAPS g_DriverCaps = { 0 };
static DWORD g_dwOverlayW = 640; // Cached Overlay Width static DWORD g_dwOverlayW = 640; // Cached Overlay Width
static DWORD g_dwOverlayH = 480; // Cached Overlay Height static DWORD g_dwOverlayH = 480; // Cached Overlay Height
static DWORD g_dwOverlayP = 640; // Cached Overlay Pitch static DWORD g_dwOverlayP = 640; // Cached Overlay Pitch
@ -1060,6 +1061,8 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID)
if(FAILED(hRet)) if(FAILED(hRet))
CxbxKrnlCleanup("Could not initialize DirectDraw7"); CxbxKrnlCleanup("Could not initialize DirectDraw7");
g_pDD7->GetCaps(&g_DriverCaps, nullptr);
hRet = g_pDD7->SetCooperativeLevel(0, DDSCL_NORMAL); hRet = g_pDD7->SetCooperativeLevel(0, DDSCL_NORMAL);
if(FAILED(hRet)) if(FAILED(hRet))
@ -1176,17 +1179,17 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID)
} }
// cleanup overlay clipper // cleanup overlay clipper
if (g_pDDClipper != 0) if (g_pDDClipper != nullptr)
{ {
g_pDDClipper->Release(); g_pDDClipper->Release();
g_pDDClipper = 0; g_pDDClipper = nullptr;
} }
// cleanup overlay surface // cleanup overlay surface
if (g_pDDSOverlay7 != 0) if (g_pDDSOverlay7 != nullptr)
{ {
g_pDDSOverlay7->Release(); g_pDDSOverlay7->Release();
g_pDDSOverlay7 = 0; g_pDDSOverlay7 = nullptr;
} }
// cleanup directdraw surface // cleanup directdraw surface
@ -3569,9 +3572,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_SetTexture)
// NOTE: TODO: This is almost a hack! :) // NOTE: TODO: This is almost a hack! :)
// //
EMUPATCH(D3DDevice_UpdateOverlay)((X_D3DSurface*)pTexture, NULL, NULL, FALSE, 0);
EMUPATCH(D3DDevice_EnableOverlay)(TRUE);
EMUPATCH(D3DDevice_UpdateOverlay)((X_D3DSurface*)pTexture, 0, 0, FALSE, 0);
} }
else else
@ -5494,7 +5495,7 @@ HRESULT WINAPI XTL::EMUPATCH(D3DSurface_GetDesc)
if(pThis->Data == X_D3DRESOURCE_DATA_YUV_SURFACE) if(pThis->Data == X_D3DRESOURCE_DATA_YUV_SURFACE)
{ {
pDesc->Format = EmuPC2XB_D3DFormat(D3DFMT_YUY2); pDesc->Format = X_D3DFMT_YUY2;
pDesc->Height = g_dwOverlayH; pDesc->Height = g_dwOverlayH;
pDesc->Width = g_dwOverlayW; pDesc->Width = g_dwOverlayW;
pDesc->MultiSampleType = (D3DMULTISAMPLE_TYPE)0; pDesc->MultiSampleType = (D3DMULTISAMPLE_TYPE)0;
@ -5980,25 +5981,25 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_EnableOverlay)
");\n", ");\n",
Enable); Enable);
if(Enable == FALSE && (g_pDDSOverlay7 != NULL)) if(Enable == FALSE && (g_pDDSOverlay7 != nullptr))
{ {
g_pDDSOverlay7->UpdateOverlay(NULL, g_pDDSPrimary, NULL, DDOVER_HIDE, 0); g_pDDSOverlay7->UpdateOverlay(NULL, g_pDDSPrimary, NULL, DDOVER_HIDE, 0);
// cleanup overlay clipper // cleanup overlay clipper
if(g_pDDClipper != 0) if(g_pDDClipper != nullptr)
{ {
g_pDDClipper->Release(); g_pDDClipper->Release();
g_pDDClipper = 0; g_pDDClipper = nullptr;
} }
// cleanup overlay surface // cleanup overlay surface
if(g_pDDSOverlay7 != 0) if(g_pDDSOverlay7 != nullptr)
{ {
g_pDDSOverlay7->Release(); g_pDDSOverlay7->Release();
g_pDDSOverlay7 = 0; g_pDDSOverlay7 = nullptr;
} }
} }
else if(Enable == TRUE && (g_pDDSOverlay7 == 0)) else if(Enable == TRUE && (g_pDDSOverlay7 == nullptr))
{ {
// initialize overlay surface // initialize overlay surface
if(g_bSupportsYUY2) if(g_bSupportsYUY2)
@ -6017,12 +6018,10 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_EnableOverlay)
ddsd2.ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y','U','Y','2'); ddsd2.ddpfPixelFormat.dwFourCC = MAKEFOURCC('Y','U','Y','2');
HRESULT hRet = g_pDD7->CreateSurface(&ddsd2, &g_pDDSOverlay7, NULL); HRESULT hRet = g_pDD7->CreateSurface(&ddsd2, &g_pDDSOverlay7, NULL);
if(FAILED(hRet)) if(FAILED(hRet))
CxbxKrnlCleanup("Could not create overlay surface"); CxbxKrnlCleanup("Could not create overlay surface");
hRet = g_pDD7->CreateClipper(0, &g_pDDClipper, NULL); hRet = g_pDD7->CreateClipper(0, &g_pDDClipper, NULL);
if(FAILED(hRet)) if(FAILED(hRet))
CxbxKrnlCleanup("Could not create overlay clipper"); CxbxKrnlCleanup("Could not create overlay clipper");
@ -6047,8 +6046,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
D3DCOLOR ColorKey D3DCOLOR ColorKey
) )
{ {
DbgPrintf("EmuD3D8: EmuD3DDevice_UpdateOverlay\n" DbgPrintf("EmuD3D8: EmuD3DDevice_UpdateOverlay\n"
"(\n" "(\n"
" pSurface : 0x%.08X\n" " pSurface : 0x%.08X\n"
@ -6059,12 +6056,29 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
");\n", ");\n",
pSurface, SrcRect, DstRect, EnableColorKey, ColorKey); pSurface, SrcRect, DstRect, EnableColorKey, ColorKey);
if(pSurface) if (pSurface == NULL) {
{ EmuWarning("pSurface == NULL!");
} else {
uint08 *pYUY2SourceBuffer = (uint08*)pSurface->Lock; // TODO : DxbxGetDataFromXboxResource(pSurface);
RECT EmuSourRect;
RECT EmuDestRect;
if (SrcRect != NULL) {
EmuSourRect = *SrcRect;
} else {
SetRect(&EmuSourRect, 0, 0, g_dwOverlayW, g_dwOverlayH);
}
if (DstRect != NULL) {
// If there's a destination rectangle given, copy that into our local variable :
EmuDestRect = *DstRect;
} else {
GetClientRect(g_hEmuWindow, &EmuDestRect);
}
// manually copy data over to overlay // manually copy data over to overlay
if(g_bSupportsYUY2) if(g_bSupportsYUY2)
{ {
DDSURFACEDESC2 ddsd2;
// Make sure the overlay is allocated before using it // Make sure the overlay is allocated before using it
if (g_pDDSOverlay7 == nullptr) { if (g_pDDSOverlay7 == nullptr) {
EMUPATCH(D3DDevice_EnableOverlay)(TRUE); EMUPATCH(D3DDevice_EnableOverlay)(TRUE);
@ -6072,6 +6086,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
assert(g_pDDSOverlay7 != nullptr); assert(g_pDDSOverlay7 != nullptr);
} }
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)))
@ -6080,20 +6095,19 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
// copy data // copy data
{ {
char *pDest = (char*)ddsd2.lpSurface; char *pDest = (char*)ddsd2.lpSurface;
char *pSour = (char*)pSurface->Lock; char *pSour = (char*)pYUY2SourceBuffer;
int w = g_dwOverlayW; int p = g_dwOverlayW * 2; // 2 = EmuXBFormatBytesPerPixel(D3DFMT_YUY2);
int h = g_dwOverlayH; int h = g_dwOverlayH;
// TODO: sucker the game into rendering directly to the overlay (speed boost) // TODO: sucker the game into rendering directly to the overlay (speed boost)
if( (ddsd2.lPitch == w*2) && ((int)g_dwOverlayP == w*2) ) if( (ddsd2.lPitch == p) && ((int)g_dwOverlayP == p) )
memcpy(pDest, pSour, h*w*2); memcpy(pDest, pSour, p*h);
else else
{ {
for(int y=0;y<h;y++) for(int y=0;y<h;y++)
{ {
memcpy(pDest, pSour, w*2); memcpy(pDest, pSour, p);
pDest += ddsd2.lPitch; pDest += ddsd2.lPitch;
pSour += g_dwOverlayP; pSour += g_dwOverlayP;
} }
@ -6101,52 +6115,42 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
g_pDDSOverlay7->Unlock(NULL); g_pDDSOverlay7->Unlock(NULL);
} }
}
RECT SourRect = { 0, 0, (LONG)g_dwOverlayW, (LONG)g_dwOverlayH };
if (SrcRect != NULL)
SourRect = *SrcRect;
// update overlay!
if(g_bSupportsYUY2)
{
RECT DestRect;
MONITORINFO MonitorInfo = {0};
int nTitleHeight = 0;//GetSystemMetrics(SM_CYCAPTION);
int nBorderWidth = 0;//GetSystemMetrics(SM_CXSIZEFRAME);
int nBorderHeight = 0;//GetSystemMetrics(SM_CYSIZEFRAME);
MonitorInfo.cbSize = sizeof(MONITORINFO);
GetMonitorInfo(g_hMonitor, &MonitorInfo);
GetWindowRect(g_hEmuWindow, &DestRect);
DestRect.left += nBorderWidth;
DestRect.right -= nBorderWidth;
DestRect.top += nTitleHeight + nBorderHeight;
DestRect.bottom -= nBorderHeight;
DestRect.left -= MonitorInfo.rcMonitor.left;
DestRect.right -= MonitorInfo.rcMonitor.left;
DestRect.top -= MonitorInfo.rcMonitor.top;
DestRect.bottom -= MonitorInfo.rcMonitor.top;
// update overlay!
DWORD dwUpdateFlags = DDOVER_SHOW;
DDOVERLAYFX ddofx; DDOVERLAYFX ddofx;
ZeroMemory(&ddofx, sizeof(ddofx)); ZeroMemory(&ddofx, sizeof(ddofx));
ddofx.dwSize = sizeof(DDOVERLAYFX); ddofx.dwSize = sizeof(DDOVERLAYFX);
ddofx.dckDestColorkey.dwColorSpaceLowValue = 0; if (EnableColorKey) {
ddofx.dckDestColorkey.dwColorSpaceHighValue = 0; {
if (g_DriverCaps.dwCKeyCaps & DDCKEYCAPS_DESTOVERLAY)
dwUpdateFlags |= DDOVER_KEYDESTOVERRIDE | DDOVER_DDFX;
ddofx.dckDestColorkey.dwColorSpaceLowValue = ColorKey;
ddofx.dckDestColorkey.dwColorSpaceHighValue = ColorKey;
}
} else {
if (g_DriverCaps.dwCKeyCaps & DDCKEYCAPS_SRCOVERLAY)
{
dwUpdateFlags |= DDOVER_KEYSRCOVERRIDE | DDOVER_DDFX;
ddofx.dckSrcColorkey.dwColorSpaceLowValue = ColorKey;
ddofx.dckSrcColorkey.dwColorSpaceHighValue = ColorKey;
}
}
HRESULT hRet = g_pDDSOverlay7->UpdateOverlay(&SourRect, g_pDDSPrimary, &DestRect, /*DDOVER_KEYDESTOVERRIDE | */DDOVER_SHOW, /*&ddofx*/0); // Get the screen (multi-monitor-compatible) coordinates of the client area :
MapWindowPoints(g_hEmuWindow, HWND_DESKTOP, (LPPOINT)&EmuDestRect, 2);
HRESULT hRet = g_pDDSOverlay7->UpdateOverlay(&EmuSourRect, g_pDDSPrimary, &EmuDestRect, dwUpdateFlags, &ddofx);
} }
else else // No hardware overlay
{ {
IDirect3DSurface8 *pBackBufferSurface = nullptr; IDirect3DSurface8 *pBackBufferSurface = nullptr;
HRESULT hRet = g_pD3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBufferSurface); HRESULT hRet = g_pD3DDevice8->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pBackBufferSurface);
// if we obtained the backbuffer, load the YUY2 into the backbuffer // if we obtained the backbuffer, load the YUY2 into the backbuffer
if (hRet == D3D_OK) { if (hRet != D3D_OK) {
EmuWarning("Unable to get backbuffer surface!");
} else {
// Get backbuffer dimenions; TODO : remember this once, at creation/resize time // Get backbuffer dimenions; TODO : remember this once, at creation/resize time
D3DSURFACE_DESC BackBufferDesc; D3DSURFACE_DESC BackBufferDesc;
pBackBufferSurface->GetDesc(&BackBufferDesc); pBackBufferSurface->GetDesc(&BackBufferDesc);
@ -6154,26 +6158,19 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
// Limit the width and height of the output to the backbuffer dimensions. // Limit the width and height of the output to the backbuffer dimensions.
// This will (hopefully) prevent exceptions in Blinx - The Time Sweeper // This will (hopefully) prevent exceptions in Blinx - The Time Sweeper
// (see https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/285) // (see https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/285)
RECT DestRect = { 0 };
{ {
// If there's a destination rectangle given, copy that into our local variable :
if (DstRect != NULL)
DestRect = *DstRect;
// Use our (bounded) copy when bounds exceed : // Use our (bounded) copy when bounds exceed :
if (DestRect.right > BackBufferDesc.Width) { if (EmuDestRect.right > (LONG)BackBufferDesc.Width) {
DestRect.right = BackBufferDesc.Width; EmuDestRect.right = (LONG)BackBufferDesc.Width;
DstRect = &DestRect; DstRect = &EmuDestRect;
} }
if (g_dwOverlayH > BackBufferDesc.Height) { if (EmuDestRect.bottom > (LONG)BackBufferDesc.Height) {
DestRect.bottom = BackBufferDesc.Height; EmuDestRect.bottom = (LONG)BackBufferDesc.Height;
DstRect = &DestRect; DstRect = &EmuDestRect;
} }
} }
uint08 *pYUY2Input = (uint08*)pSurface->Lock; // TODO : DxbxGetDataFromXboxResource(pSurface);
// Use D3DXLoadSurfaceFromMemory() to do conversion, stretching and filtering // Use D3DXLoadSurfaceFromMemory() to do conversion, stretching and filtering
// avoiding the need for YUY2toARGB() (might become relevant when porting to D3D9 or OpenGL) // avoiding the need for YUY2toARGB() (might become relevant when porting to D3D9 or OpenGL)
// see https://msdn.microsoft.com/en-us/library/windows/desktop/bb172902(v=vs.85).aspx // see https://msdn.microsoft.com/en-us/library/windows/desktop/bb172902(v=vs.85).aspx
@ -6181,11 +6178,11 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
/* pDestSurface = */ pBackBufferSurface, /* pDestSurface = */ pBackBufferSurface,
/* pDestPalette = */ nullptr, // Palette not needed for YUY2 /* pDestPalette = */ nullptr, // Palette not needed for YUY2
/* pDestRect = */DstRect, // Either the unmodified original (can be NULL) or a pointer to our local variable /* pDestRect = */DstRect, // Either the unmodified original (can be NULL) or a pointer to our local variable
/* pSrcMemory = */ pYUY2Input, // Source buffer /* pSrcMemory = */ pYUY2SourceBuffer, // Source buffer
/* SrcFormat = */ D3DFMT_YUY2, /* SrcFormat = */ D3DFMT_YUY2,
/* SrcPitch = */ g_dwOverlayP, /* SrcPitch = */ g_dwOverlayP,
/* pSrcPalette = */ nullptr, // Palette not needed for YUY2 /* pSrcPalette = */ nullptr, // Palette not needed for YUY2
/* pSrcRect = */ &SourRect, /* SrcRect = */ &EmuSourRect,
/* Filter = */ D3DX_FILTER_POINT, // Dxbx note : D3DX_FILTER_LINEAR gives a smoother image, but 'bleeds' across borders /* Filter = */ D3DX_FILTER_POINT, // Dxbx note : D3DX_FILTER_LINEAR gives a smoother image, but 'bleeds' across borders
/* ColorKey = */ EnableColorKey ? ColorKey : 0); /* ColorKey = */ EnableColorKey ? ColorKey : 0);
if (hRet != D3D_OK) { if (hRet != D3D_OK) {
@ -6205,10 +6202,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
g_bHackUpdateSoftwareOverlay = TRUE; g_bHackUpdateSoftwareOverlay = TRUE;
} }
} }
else
{
EmuWarning("pSurface == NULL!");
}
return; return;
} }
@ -7284,7 +7277,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetRenderState_YuvEnable)
if(g_fYuvEnabled) if(g_fYuvEnabled)
{ {
EMUPATCH(D3DDevice_UpdateOverlay)(g_pCachedYuvSurface, 0, 0, FALSE, 0); EMUPATCH(D3DDevice_UpdateOverlay)(g_pCachedYuvSurface, NULL, NULL, FALSE, 0);
} }