Blit overlay to host backbuffer during swap too (#7)

This commit is contained in:
PatrickvL 2018-05-13 16:34:19 +02:00
parent 156a22d2a2
commit 39ff82ea85
1 changed files with 121 additions and 122 deletions

View File

@ -113,6 +113,14 @@ static DWORD g_CallbackParam; // Callback param
static BOOL g_bHasDepthStencil = FALSE; // Does device have a Depth/Stencil Buffer?
static DWORD g_dwPrimPerFrame = 0; // Number of primitives within one frame
struct {
XTL::X_D3DSurface *pSurface;
RECT SrcRect;
RECT DstRect;
BOOL EnableColorKey;
XTL::D3DCOLOR ColorKey;
} g_OverlayProxy;
// D3D based variables
static GUID g_ddguid; // DirectDraw driver GUID
static XTL::IDirect3D *g_pDirect3D = nullptr;
@ -1324,24 +1332,6 @@ uint8 *XTL::ConvertD3DTextureToARGB(
return pDst;
}
VOID CxbxReleaseBackBufferLock()
{
XTL::IDirect3DSurface *pBackBuffer = nullptr;
if (D3D_OK == g_pD3DDevice->GetBackBuffer(
#ifdef CXBX_USE_D3D9
0, // iSwapChain
#endif
0, XTL::D3DBACKBUFFER_TYPE_MONO, &pBackBuffer))
{
assert(pBackBuffer != nullptr);
pBackBuffer->UnlockRect(); // remove old lock
pBackBuffer->Release();
}
}
// Direct3D initialization (called before emulation begins)
VOID XTL::EmuD3DInit()
{
@ -4601,26 +4591,106 @@ DWORD WINAPI XTL::EMUPATCH(D3DDevice_Swap)
if (Flags != CXBX_SWAP_PRESENT_FORWARD) // Avoid a warning when forwarded
EmuWarning("XTL::EmuD3DDevice_Swap: Flags != 0");
CxbxReleaseBackBufferLock();
// Fetch the host backbuffer
XTL::IDirect3DSurface *pCurrentHostBackBuffer = nullptr;
HRESULT hRet = g_pD3DDevice->GetBackBuffer(
#ifdef CXBX_USE_D3D9
0, // iSwapChain
#endif
0, XTL::D3DBACKBUFFER_TYPE_MONO, &pCurrentHostBackBuffer);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetBackBuffer - Unable to get backbuffer surface!");
if (hRet == D3D_OK) {
assert(pCurrentHostBackBuffer != nullptr);
pCurrentHostBackBuffer->UnlockRect(); // remove any old lock
auto pXboxBackBufferHostSurface = GetHostSurface(g_XboxBackBufferSurface);
if (pXboxBackBufferHostSurface) {
// Blit Xbox BackBuffer to host BackBuffer
hRet = D3DXLoadSurfaceFromSurface(pCurrentHostBackBuffer, nullptr, nullptr, pXboxBackBufferHostSurface, nullptr, nullptr, D3DX_DEFAULT, 0);
if (hRet != D3D_OK) {
EmuWarning("Couldn't blit Xbox BackBuffer to host BackBuffer : %X", hRet);
}
}
if (g_OverlayProxy.pSurface && g_fYuvEnabled) {
// Blit Xbox overlay to host backbuffer
uint08 *pOverlayData = (uint08*)GetDataFromXboxResource(g_OverlayProxy.pSurface);
UINT OverlayWidth, OverlayHeight, OverlayDepth, OverlayRowPitch, OverlaySlicePitch;
CxbxGetPixelContainerMeasures(
(XTL::X_D3DPixelContainer *)g_OverlayProxy.pSurface,
0, // dwMipMapLevel
&OverlayWidth, &OverlayHeight, &OverlayDepth, &OverlayRowPitch, &OverlaySlicePitch);
RECT EmuSourRect;
RECT EmuDestRect;
if (g_OverlayProxy.SrcRect.right > 0) {
EmuSourRect = g_OverlayProxy.SrcRect;
}
else {
SetRect(&EmuSourRect, 0, 0, OverlayWidth, OverlayHeight);
}
if (g_OverlayProxy.DstRect.right > 0) {
// If there's a destination rectangle given, copy that into our local variable :
EmuDestRect = g_OverlayProxy.DstRect;
}
else {
GetClientRect(g_hEmuWindow, &EmuDestRect);
}
// load the YUY2 into the backbuffer
// Get backbuffer dimenions; TODO : remember this once, at creation/resize time
D3DSURFACE_DESC BackBufferDesc;
pCurrentHostBackBuffer->GetDesc(&BackBufferDesc);
#if 0
// 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)
{
// Use our (bounded) copy when bounds exceed :
if (EmuDestRect.right > (LONG)BackBufferDesc.Width) {
EmuDestRect.right = (LONG)BackBufferDesc.Width;
DstRect = &EmuDestRect;
}
if (EmuDestRect.bottom > (LONG)BackBufferDesc.Height) {
EmuDestRect.bottom = (LONG)BackBufferDesc.Height;
DstRect = &EmuDestRect;
}
}
#endif
// Use D3DXLoadSurfaceFromMemory() to do conversion, stretching and filtering
// 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
hRet = D3DXLoadSurfaceFromMemory(
/* pDestSurface = */ pCurrentHostBackBuffer,
/* pDestPalette = */ nullptr, // Palette not needed for YUY2
/* pDestRect = */ &EmuDestRect,
/* pSrcMemory = */ pOverlayData, // Source buffer
/* SrcFormat = */ D3DFMT_YUY2,
/* SrcPitch = */ OverlayRowPitch,
/* pSrcPalette = */ nullptr, // Palette not needed for YUY2
/* SrcRect = */ &EmuSourRect,
/* Filter = */ D3DX_FILTER_POINT, // Dxbx note : D3DX_FILTER_LINEAR gives a smoother image, but 'bleeds' across borders
/* ColorKey = */ g_OverlayProxy.EnableColorKey ? g_OverlayProxy.ColorKey : 0);
DEBUG_D3DRESULT(hRet, "D3DXLoadSurfaceFromMemory - UpdateOverlay could not convert buffer!\n");
if (hRet != D3D_OK) {
EmuWarning("Couldn't blit Xbox overlay to host BackBuffer : %X", hRet);
}
}
pCurrentHostBackBuffer->Release();
}
g_pD3DDevice->EndScene();
// Blit the Xbox BackBuffer to the Host
if (g_XboxBackBufferSurface != NULL) {
auto pXboxBackBufferHostSurface = GetHostSurface(g_XboxBackBufferSurface);
// Now we can fetch the host backbuffer
XTL::IDirect3DSurface *pCurrentHostBackBuffer = nullptr;
g_pD3DDevice->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &pCurrentHostBackBuffer);
if (pCurrentHostBackBuffer && pXboxBackBufferHostSurface) {
HRESULT hRet = D3DXLoadSurfaceFromSurface(pCurrentHostBackBuffer, nullptr, nullptr, pXboxBackBufferHostSurface, nullptr, nullptr, D3DX_DEFAULT, 0);
if (hRet != D3D_OK) {
EmuWarning("FAILED: %X", hRet);
}
}
}
HRESULT hRet = g_pD3DDevice->Present(0, 0, 0, 0);
hRet = g_pD3DDevice->Present(0, 0, 0, 0);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->Present");
hRet = g_pD3DDevice->BeginScene();
if (!g_UncapFramerate) {
@ -5532,84 +5602,14 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
LOG_FUNC_ARG(ColorKey)
LOG_FUNC_END;
if (!g_fYuvEnabled) {
return;
}
if (pSurface == NULL) {
EmuWarning("pSurface == NULL!");
} else {
uint08 *pOverlayData = (uint08*)GetDataFromXboxResource(pSurface);
UINT OverlayWidth, OverlayHeight, OverlayDepth, OverlayRowPitch, OverlaySlicePitch;
CxbxGetPixelContainerMeasures(
(XTL::X_D3DPixelContainer *)pSurface,
0, // dwMipMapLevel
&OverlayWidth, &OverlayHeight, &OverlayDepth, &OverlayRowPitch, &OverlaySlicePitch);
RECT EmuSourRect;
RECT EmuDestRect;
if (SrcRect != NULL) {
EmuSourRect = *SrcRect;
} else {
SetRect(&EmuSourRect, 0, 0, OverlayWidth, OverlayHeight);
}
if (DstRect != NULL) {
// If there's a destination rectangle given, copy that into our local variable :
EmuDestRect = *DstRect;
} else {
GetClientRect(g_hEmuWindow, &EmuDestRect);
}
IDirect3DSurface *pCurrentHostBackBuffer = nullptr;
HRESULT hRet = g_pD3DDevice->GetBackBuffer(
#ifdef CXBX_USE_D3D9
0, // iSwapChain
#endif
0, D3DBACKBUFFER_TYPE_MONO, &pCurrentHostBackBuffer);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->GetBackBuffer - Unable to get backbuffer surface!");
// if we obtained the backbuffer, load the YUY2 into the backbuffer
if (SUCCEEDED(hRet)) {
// Get backbuffer dimenions; TODO : remember this once, at creation/resize time
D3DSURFACE_DESC BackBufferDesc;
pCurrentHostBackBuffer->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)
{
// Use our (bounded) copy when bounds exceed :
if (EmuDestRect.right > (LONG)BackBufferDesc.Width) {
EmuDestRect.right = (LONG)BackBufferDesc.Width;
DstRect = &EmuDestRect;
}
if (EmuDestRect.bottom > (LONG)BackBufferDesc.Height) {
EmuDestRect.bottom = (LONG)BackBufferDesc.Height;
DstRect = &EmuDestRect;
}
}
// Use D3DXLoadSurfaceFromMemory() to do conversion, stretching and filtering
// 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
hRet = D3DXLoadSurfaceFromMemory(
/* pDestSurface = */ pCurrentHostBackBuffer,
/* pDestPalette = */ nullptr, // Palette not needed for YUY2
/* pDestRect = */DstRect, // Either the unmodified original (can be NULL) or a pointer to our local variable
/* pSrcMemory = */ pOverlayData, // Source buffer
/* SrcFormat = */ D3DFMT_YUY2,
/* SrcPitch = */ OverlayRowPitch,
/* pSrcPalette = */ nullptr, // Palette not needed for YUY2
/* SrcRect = */ &EmuSourRect,
/* Filter = */ D3DX_FILTER_POINT, // Dxbx note : D3DX_FILTER_LINEAR gives a smoother image, but 'bleeds' across borders
/* ColorKey = */ EnableColorKey ? ColorKey : 0);
DEBUG_D3DRESULT(hRet, "D3DXLoadSurfaceFromMemory - UpdateOverlay could not convert buffer!\n");
pCurrentHostBackBuffer->Release();
}
g_OverlayProxy = {};
g_OverlayProxy.pSurface = pSurface;
if (SrcRect)
g_OverlayProxy.SrcRect = *SrcRect;
if (DstRect)
g_OverlayProxy.DstRect = *DstRect;
g_OverlayProxy.EnableColorKey = EnableColorKey;
g_OverlayProxy.ColorKey = ColorKey;
// Update overlay if present was not called since the last call to
// EmuD3DDevice_UpdateOverlay.
@ -5619,7 +5619,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_UpdateOverlay)
g_OverlaySwap = g_SwapData.Swap;
}
}
// ******************************************************************
// * patch: D3DDevice_GetOverlayUpdateStatus