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:
parent
b5f43063b1
commit
b4366db398
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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") {
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(¶ms);
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user