1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-11-29 01:24:11 +01:00

[d3d9] Implement rudimentary device loss

This commit is contained in:
Robin Kertels 2023-03-27 17:46:41 +02:00 committed by Joshie
parent b5f43063b1
commit b4366db398
7 changed files with 114 additions and 19 deletions

View File

@ -211,8 +211,16 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::TestCooperativeLevel() {
D3D9DeviceLock lock = LockDevice();
// Equivelant of D3D11/DXGI present tests. We can always present.
return D3D_OK;
if (likely(m_deviceLostState == D3D9DeviceLostState::Ok)) {
return D3D_OK;
} else if (m_deviceLostState == D3D9DeviceLostState::NotReset) {
return D3DERR_DEVICENOTRESET;
} else {
return D3DERR_DEVICELOST;
}
}
@ -382,13 +390,14 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) {
D3D9DeviceLock lock = LockDevice();
Logger::info("Device reset");
m_deviceLostState = D3D9DeviceLostState::Ok;
HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr);
if (FAILED(hr))
return hr;
hr = ResetState(pPresentationParameters);
if (FAILED(hr))
return hr;
ResetState(pPresentationParameters);
Flush();
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
@ -911,6 +920,10 @@ namespace dxvk {
IDirect3DSurface9* pDestSurface) {
D3D9DeviceLock lock = LockDevice();
if (unlikely(IsDeviceLost())) {
return D3DERR_DEVICELOST;
}
D3D9Surface* src = static_cast<D3D9Surface*>(pRenderTarget);
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
@ -2365,10 +2378,12 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ValidateDevice(DWORD* pNumPasses) {
D3D9DeviceLock lock = LockDevice();
if (pNumPasses != nullptr)
*pNumPasses = 1;
return D3D_OK;
return IsDeviceLost() ? D3DERR_DEVICELOST : D3D_OK;
}
@ -3726,6 +3741,10 @@ namespace dxvk {
if (!m_implicitSwapchain->GetPresentParams()->Windowed)
return D3DERR_INVALIDCALL;
if (unlikely(IsDeviceLost())) {
return D3DERR_DEVICELOST;
}
m_implicitSwapchain->Invalidate(pPresentationParameters->hDeviceWindow);
try {
@ -7094,7 +7113,7 @@ namespace dxvk {
}
HRESULT D3D9DeviceEx::ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters) {
void D3D9DeviceEx::ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters) {
if (!pPresentationParameters->EnableAutoDepthStencil)
SetDepthStencilSurface(nullptr);
@ -7335,8 +7354,6 @@ namespace dxvk {
UpdateVertexBoolSpec(0u);
UpdatePixelBoolSpec(0u);
UpdateCommonSamplerSpec(0u, 0u, 0u);
return D3D_OK;
}
@ -7410,9 +7427,7 @@ namespace dxvk {
if (FAILED(hr))
return hr;
hr = ResetState(pPresentationParameters);
if (FAILED(hr))
return hr;
ResetState(pPresentationParameters);
Flush();
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);

View File

@ -87,6 +87,12 @@ namespace dxvk {
using D3D9DeviceFlags = Flags<D3D9DeviceFlag>;
enum class D3D9DeviceLostState {
Ok = 0,
Lost = 1,
NotReset = 2,
};
struct D3D9DrawInfo {
uint32_t vertexCount;
uint32_t instanceCount;
@ -933,7 +939,7 @@ namespace dxvk {
const D3D9ConstantLayout& GetVertexConstantLayout() { return m_vsLayout; }
const D3D9ConstantLayout& GetPixelConstantLayout() { return m_psLayout; }
HRESULT ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters);
void ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters);
HRESULT ResetSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
HRESULT InitialReset(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
@ -950,6 +956,43 @@ namespace dxvk {
void TouchMappedTexture(D3D9CommonTexture* pTexture);
void RemoveMappedTexture(D3D9CommonTexture* pTexture);
bool IsDeviceLost() const {
return m_deviceLostState != D3D9DeviceLostState::Ok;
}
void NotifyFullscreen(HWND window, bool fullscreen) {
D3D9DeviceLock lock = LockDevice();
if (fullscreen) {
if (unlikely(window != m_fullscreenWindow && m_fullscreenWindow != NULL)) {
Logger::warn("Multiple fullscreen windows detected.");
}
m_fullscreenWindow = window;
} else {
if (unlikely(m_fullscreenWindow != window)) {
Logger::warn("Window was not fullscreen in the first place.");
} else {
m_fullscreenWindow = 0;
}
}
}
void NotifyWindowActivated(HWND window, bool activated) {
D3D9DeviceLock lock = LockDevice();
if (likely(!m_d3d9Options.deviceLost || IsExtended()))
return;
if (activated && m_deviceLostState == D3D9DeviceLostState::Lost) {
Logger::info("Device not reset");
m_deviceLostState = D3D9DeviceLostState::NotReset;
} else if (!activated && m_deviceLostState != D3D9DeviceLostState::Lost && m_fullscreenWindow == window) {
Logger::info("Device lost");
m_deviceLostState = D3D9DeviceLostState::Lost;
m_fullscreenWindow = NULL;
}
}
private:
DxvkCsChunkRef AllocCsChunk() {
@ -1317,6 +1360,9 @@ namespace dxvk {
Direct3DState9 m_state;
D3D9DeviceLostState m_deviceLostState = D3D9DeviceLostState::Ok;
HWND m_fullscreenWindow = NULL;
#ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures;
#endif

View File

@ -74,6 +74,7 @@ namespace dxvk {
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
this->deviceLost = config.getOption<bool> ("d3d9.deviceLost", false);
std::string floatEmulation = Config::toLower(config.getOption<std::string>("d3d9.floatEmulation", "auto"));
if (floatEmulation == "strict") {

View File

@ -158,6 +158,9 @@ namespace dxvk {
/// Shader dump path
std::string shaderDumpPath;
/// Enable emulation of device loss when a fullscreen app loses focus
bool deviceLost;
};
}

View File

@ -132,6 +132,14 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D9Query::GetData(void* pData, DWORD dwSize, DWORD dwGetDataFlags) {
D3D9DeviceLock lock = m_parent->LockDevice();
bool flush = dwGetDataFlags & D3DGETDATA_FLUSH;
if (unlikely(m_parent->IsDeviceLost())) {
return flush ? D3DERR_DEVICELOST : S_FALSE;
}
if (m_state == D3D9_VK_QUERY_CACHED) {
// Query data was already retrieved once.
// Use cached query data to prevent having to check the VK event
@ -148,8 +156,6 @@ namespace dxvk {
HRESULT hr = this->GetQueryData(pData, dwSize);
bool flush = dwGetDataFlags & D3DGETDATA_FLUSH;
// If we get S_FALSE and it's not from the fact
// they didn't call end, do some flushy stuff...
if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {

View File

@ -103,6 +103,9 @@ namespace dxvk {
DWORD dwFlags) {
D3D9DeviceLock lock = m_parent->LockDevice();
if (unlikely(m_parent->IsDeviceLost()))
return D3DERR_DEVICELOST;
// If we have no backbuffers, error out.
// This handles the case where a ::Reset failed due to OOM
// or whatever.
@ -237,6 +240,10 @@ namespace dxvk {
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH))
return D3DERR_INVALIDCALL;
if (unlikely(m_parent->IsDeviceLost())) {
return D3DERR_DEVICELOST;
}
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(0);
@ -540,6 +547,8 @@ namespace dxvk {
this->LeaveFullscreenMode();
}
else {
m_parent->NotifyFullscreen(m_window, true);
if (changeFullscreen) {
hr = this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode);
if (FAILED(hr))
@ -1151,6 +1160,8 @@ namespace dxvk {
return D3DERR_INVALIDCALL;
}
m_parent->NotifyFullscreen(m_window, true);
return D3D_OK;
}
@ -1170,6 +1181,8 @@ namespace dxvk {
Logger::err("D3D9: LeaveFullscreenMode: Failed to exit fullscreen mode");
return D3DERR_NOTAVAILABLE;
}
m_parent->NotifyFullscreen(m_window, false);
return D3D_OK;
}

View File

@ -10,6 +10,7 @@ namespace dxvk
bool unicode;
bool filter;
bool activateProcessed;
bool deactivateProcessed;
WNDPROC proc;
D3D9SwapChainEx* swapchain;
};
@ -53,11 +54,14 @@ namespace dxvk
DefWindowProcW, DefWindowProcA, unicode,
window, message, wparam, lparam);
D3D9DeviceEx* device = windowData.swapchain->GetParent();
if (message == WM_DESTROY)
ResetWindowProc(window);
else if (message == WM_ACTIVATEAPP) {
D3DDEVICE_CREATION_PARAMETERS create_parms;
windowData.swapchain->GetDevice()->GetCreationParameters(&create_parms);
device->GetCreationParameters(&create_parms);
if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES)) {
D3D9WindowMessageFilter filter(window);
@ -70,19 +74,24 @@ namespace dxvk
windowData.swapchain->GetPresentParameters(&params);
SetWindowPos(window, nullptr, rect.left, rect.top, params.BackBufferWidth, params.BackBufferHeight,
SWP_NOACTIVATE | SWP_NOZORDER);
SetActivateProcessed(window, true);
}
else if (!wparam) {
if (IsWindowVisible(window))
ShowWindow(window, SW_MINIMIZE);
SetActivateProcessed(window, false);
}
}
if ((wparam && !windowData.activateProcessed)
|| (!wparam && !windowData.deactivateProcessed)) {
device->NotifyWindowActivated(window, wparam);
}
SetActivateProcessed(window, !!wparam);
}
else if (message == WM_SIZE)
{
D3DDEVICE_CREATION_PARAMETERS create_parms;
windowData.swapchain->GetDevice()->GetCreationParameters(&create_parms);
device->GetCreationParameters(&create_parms);
if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES) && !IsIconic(window))
PostMessageW(window, WM_ACTIVATEAPP, 1, GetCurrentThreadId());
@ -137,8 +146,10 @@ namespace dxvk
{
std::lock_guard lock(g_windowProcMapMutex);
auto it = g_windowProcMap.find(window);
if (it != g_windowProcMap.end())
if (it != g_windowProcMap.end()) {
it->second.activateProcessed = processed;
it->second.deactivateProcessed = !processed;
}
}
#else
D3D9WindowMessageFilter::D3D9WindowMessageFilter(HWND window, bool filter) {