mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-13 07:08:50 +01:00
[d3d9] Don't swap buffers for SWAPEFFECT_COPY & DISCARD with 1 backbuffer
This commit is contained in:
parent
83a294285e
commit
5443a2f9f5
@ -44,6 +44,10 @@
|
|||||||
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
|
#define D3DPRESENT_FORCEIMMEDIATE 0x00000100L
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef D3DSWAPEFFECT_COPY_VSYNC
|
||||||
|
#define D3DSWAPEFFECT_COPY_VSYNC 4
|
||||||
|
#endif
|
||||||
|
|
||||||
// MinGW headers are broken. Who'dve guessed?
|
// MinGW headers are broken. Who'dve guessed?
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
typedef struct _D3DDEVINFO_RESOURCEMANAGER
|
typedef struct _D3DDEVINFO_RESOURCEMANAGER
|
||||||
|
@ -153,9 +153,9 @@ namespace dxvk {
|
|||||||
m_lastDialog = m_dialog;
|
m_lastDialog = m_dialog;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
const bool useGDIFallback = m_partialCopy && m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY;
|
const bool useGDIFallback = m_partialCopy && !HasFrontBuffer();
|
||||||
if (useGDIFallback)
|
if (useGDIFallback)
|
||||||
return BlitGDI(window);
|
return PresentImageGDI(window);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -176,7 +176,7 @@ namespace dxvk {
|
|||||||
} catch (const DxvkError& e) {
|
} catch (const DxvkError& e) {
|
||||||
Logger::err(e.message());
|
Logger::err(e.message());
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
return BlitGDI(window);
|
return PresentImageGDI(window);
|
||||||
#else
|
#else
|
||||||
return D3DERR_DEVICEREMOVED;
|
return D3DERR_DEVICEREMOVED;
|
||||||
#endif
|
#endif
|
||||||
@ -186,8 +186,11 @@ namespace dxvk {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define DCX_USESTYLE 0x00010000
|
#define DCX_USESTYLE 0x00010000
|
||||||
|
|
||||||
HRESULT D3D9SwapChainEx::BlitGDI(HWND Window) {
|
HRESULT D3D9SwapChainEx::PresentImageGDI(HWND Window) {
|
||||||
if (!std::exchange(m_warnedAboutFallback, true))
|
m_parent->EndFrame();
|
||||||
|
m_parent->Flush();
|
||||||
|
|
||||||
|
if (!std::exchange(m_warnedGDIAboutFallback, true))
|
||||||
Logger::warn("Using GDI for swapchain presentation. This will impact performance.");
|
Logger::warn("Using GDI for swapchain presentation. This will impact performance.");
|
||||||
|
|
||||||
HDC hDC;
|
HDC hDC;
|
||||||
@ -233,13 +236,18 @@ namespace dxvk {
|
|||||||
// of src onto a temp image of dst's extents,
|
// of src onto a temp image of dst's extents,
|
||||||
// then copy buffer back to dst (given dst is subresource)
|
// then copy buffer back to dst (given dst is subresource)
|
||||||
|
|
||||||
|
// For SWAPEFFECT_COPY and windowed SWAPEFFECT_DISCARD with 1 backbuffer, we just copy the backbuffer data instead.
|
||||||
|
// We just copy from the backbuffer instead of the front buffer to avoid having to do another blit.
|
||||||
|
// This mostly impacts windowed mode and our implementation was not accurate in that case anyway as Windows D3D9
|
||||||
|
// takes a screenshot of the entire screen.
|
||||||
|
|
||||||
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
|
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
|
||||||
|
|
||||||
if (unlikely(dst == nullptr))
|
if (unlikely(dst == nullptr))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture();
|
D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture();
|
||||||
D3D9CommonTexture* srcTexInfo = m_backBuffers.back()->GetCommonTexture();
|
D3D9CommonTexture* srcTexInfo = GetFrontBuffer()->GetCommonTexture();
|
||||||
|
|
||||||
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH))
|
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH))
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
@ -730,8 +738,8 @@ namespace dxvk {
|
|||||||
m_parent->Flush();
|
m_parent->Flush();
|
||||||
|
|
||||||
// Retrieve the image and image view to present
|
// Retrieve the image and image view to present
|
||||||
auto swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
|
Rc<DxvkImage> swapImage = m_backBuffers[0]->GetCommonTexture()->GetImage();
|
||||||
auto swapImageView = m_backBuffers[0]->GetImageView(false);
|
Rc<DxvkImageView> swapImageView = m_backBuffers[0]->GetImageView(false);
|
||||||
|
|
||||||
// Bump our frame id.
|
// Bump our frame id.
|
||||||
++m_frameId;
|
++m_frameId;
|
||||||
@ -821,7 +829,6 @@ namespace dxvk {
|
|||||||
RecreateSwapChain(m_vsync);
|
RecreateSwapChain(m_vsync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) {
|
void D3D9SwapChainEx::RecreateSwapChain(BOOL Vsync) {
|
||||||
// Ensure that we can safely destroy the swap chain
|
// Ensure that we can safely destroy the swap chain
|
||||||
m_device->waitForSubmission(&m_presentStatus);
|
m_device->waitForSubmission(&m_presentStatus);
|
||||||
@ -954,7 +961,7 @@ namespace dxvk {
|
|||||||
// creating a new one to free up resources
|
// creating a new one to free up resources
|
||||||
DestroyBackBuffers();
|
DestroyBackBuffers();
|
||||||
|
|
||||||
int NumFrontBuffer = m_parent->GetOptions()->noExplicitFrontBuffer ? 0 : 1;
|
int NumFrontBuffer = HasFrontBuffer() ? 1 : 0;
|
||||||
const uint32_t NumBuffers = NumBackBuffers + NumFrontBuffer;
|
const uint32_t NumBuffers = NumBackBuffers + NumFrontBuffer;
|
||||||
|
|
||||||
m_backBuffers.reserve(NumBuffers);
|
m_backBuffers.reserve(NumBuffers);
|
||||||
@ -1235,7 +1242,11 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool D3D9SwapChainEx::UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect) {
|
bool D3D9SwapChainEx::UpdatePresentRegion(const RECT* pSourceRect, const RECT* pDestRect) {
|
||||||
if (pSourceRect == nullptr) {
|
const bool isWindowed = m_presentParams.Windowed;
|
||||||
|
|
||||||
|
// Tests show that present regions are ignored in fullscreen
|
||||||
|
|
||||||
|
if (pSourceRect == nullptr || !isWindowed) {
|
||||||
m_srcRect.top = 0;
|
m_srcRect.top = 0;
|
||||||
m_srcRect.left = 0;
|
m_srcRect.left = 0;
|
||||||
m_srcRect.right = m_presentParams.BackBufferWidth;
|
m_srcRect.right = m_presentParams.BackBufferWidth;
|
||||||
@ -1249,7 +1260,7 @@ namespace dxvk {
|
|||||||
wsi::getWindowSize(m_window, &width, &height);
|
wsi::getWindowSize(m_window, &width, &height);
|
||||||
|
|
||||||
RECT dstRect;
|
RECT dstRect;
|
||||||
if (pDestRect == nullptr) {
|
if (pDestRect == nullptr || !isWindowed) {
|
||||||
// TODO: Should we hook WM_SIZE message for this?
|
// TODO: Should we hook WM_SIZE message for this?
|
||||||
dstRect.top = 0;
|
dstRect.top = 0;
|
||||||
dstRect.left = 0;
|
dstRect.left = 0;
|
||||||
@ -1266,21 +1277,18 @@ namespace dxvk {
|
|||||||
|| dstRect.right - dstRect.left != LONG(width)
|
|| dstRect.right - dstRect.left != LONG(width)
|
||||||
|| dstRect.bottom - dstRect.top != LONG(height);
|
|| dstRect.bottom - dstRect.top != LONG(height);
|
||||||
|
|
||||||
bool recreate =
|
bool recreate =
|
||||||
m_dstRect.left != dstRect.left
|
m_swapchainExtent.width != width
|
||||||
|| m_dstRect.top != dstRect.top
|
|| m_swapchainExtent.height != height;
|
||||||
|| m_dstRect.right != dstRect.right
|
|
||||||
|| m_dstRect.bottom != dstRect.bottom;
|
|
||||||
|
|
||||||
|
m_swapchainExtent = { width, height };
|
||||||
m_dstRect = dstRect;
|
m_dstRect = dstRect;
|
||||||
|
|
||||||
return recreate;
|
return recreate;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkExtent2D D3D9SwapChainEx::GetPresentExtent() {
|
VkExtent2D D3D9SwapChainEx::GetPresentExtent() {
|
||||||
return VkExtent2D {
|
return m_swapchainExtent;
|
||||||
std::max<uint32_t>(m_dstRect.right - m_dstRect.left, 1u),
|
|
||||||
std::max<uint32_t>(m_dstRect.bottom - m_dstRect.top, 1u) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ namespace dxvk {
|
|||||||
DWORD dwFlags);
|
DWORD dwFlags);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
HRESULT BlitGDI(HWND Window);
|
HRESULT PresentImageGDI(HWND Window);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9* pDestSurface);
|
HRESULT STDMETHODCALLTYPE GetFrontBufferData(IDirect3DSurface9* pDestSurface);
|
||||||
@ -107,6 +107,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
RECT m_srcRect;
|
RECT m_srcRect;
|
||||||
RECT m_dstRect;
|
RECT m_dstRect;
|
||||||
|
VkExtent2D m_swapchainExtent = { 0u, 0u };
|
||||||
bool m_partialCopy = false;
|
bool m_partialCopy = false;
|
||||||
|
|
||||||
DxvkSubmitStatus m_presentStatus;
|
DxvkSubmitStatus m_presentStatus;
|
||||||
@ -131,7 +132,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
double m_displayRefreshRate = 0.0;
|
double m_displayRefreshRate = 0.0;
|
||||||
|
|
||||||
bool m_warnedAboutFallback = false;
|
bool m_warnedGDIAboutFallback = false;
|
||||||
|
|
||||||
void PresentImage(UINT PresentInterval);
|
void PresentImage(UINT PresentInterval);
|
||||||
|
|
||||||
@ -197,6 +198,24 @@ namespace dxvk {
|
|||||||
|
|
||||||
std::string GetApiName();
|
std::string GetApiName();
|
||||||
|
|
||||||
|
const Com<D3D9Surface, false>& GetFrontBuffer() const {
|
||||||
|
return m_backBuffers.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasFrontBuffer() const {
|
||||||
|
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_COPY_VSYNC)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Tests show that SWAPEEFFECT_DISCARD + 1 backbuffer in windowed mode behaves identically to SWAPEFFECT_COPY
|
||||||
|
// For SWAPEFFECT_COPY we don't swap buffers but do another blit to the front buffer instead.
|
||||||
|
if (m_presentParams.SwapEffect == D3DSWAPEFFECT_DISCARD && m_presentParams.BackBufferCount == 1 && m_presentParams.Windowed)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user