mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-03-01 19:29:16 +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() {
|
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::TestCooperativeLevel() {
|
||||||
|
D3D9DeviceLock lock = LockDevice();
|
||||||
|
|
||||||
// Equivelant of D3D11/DXGI present tests. We can always present.
|
// Equivelant of D3D11/DXGI present tests. We can always present.
|
||||||
|
if (likely(m_deviceLostState == D3D9DeviceLostState::Ok)) {
|
||||||
return D3D_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) {
|
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::Reset(D3DPRESENT_PARAMETERS* pPresentationParameters) {
|
||||||
D3D9DeviceLock lock = LockDevice();
|
D3D9DeviceLock lock = LockDevice();
|
||||||
|
|
||||||
|
Logger::info("Device reset");
|
||||||
|
m_deviceLostState = D3D9DeviceLostState::Ok;
|
||||||
|
|
||||||
HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr);
|
HRESULT hr = ResetSwapChain(pPresentationParameters, nullptr);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
hr = ResetState(pPresentationParameters);
|
ResetState(pPresentationParameters);
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
Flush();
|
Flush();
|
||||||
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
||||||
@ -911,6 +920,10 @@ namespace dxvk {
|
|||||||
IDirect3DSurface9* pDestSurface) {
|
IDirect3DSurface9* pDestSurface) {
|
||||||
D3D9DeviceLock lock = LockDevice();
|
D3D9DeviceLock lock = LockDevice();
|
||||||
|
|
||||||
|
if (unlikely(IsDeviceLost())) {
|
||||||
|
return D3DERR_DEVICELOST;
|
||||||
|
}
|
||||||
|
|
||||||
D3D9Surface* src = static_cast<D3D9Surface*>(pRenderTarget);
|
D3D9Surface* src = static_cast<D3D9Surface*>(pRenderTarget);
|
||||||
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
|
D3D9Surface* dst = static_cast<D3D9Surface*>(pDestSurface);
|
||||||
|
|
||||||
@ -2365,10 +2378,12 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ValidateDevice(DWORD* pNumPasses) {
|
HRESULT STDMETHODCALLTYPE D3D9DeviceEx::ValidateDevice(DWORD* pNumPasses) {
|
||||||
|
D3D9DeviceLock lock = LockDevice();
|
||||||
|
|
||||||
if (pNumPasses != nullptr)
|
if (pNumPasses != nullptr)
|
||||||
*pNumPasses = 1;
|
*pNumPasses = 1;
|
||||||
|
|
||||||
return D3D_OK;
|
return IsDeviceLost() ? D3DERR_DEVICELOST : D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3726,6 +3741,10 @@ namespace dxvk {
|
|||||||
if (!m_implicitSwapchain->GetPresentParams()->Windowed)
|
if (!m_implicitSwapchain->GetPresentParams()->Windowed)
|
||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
|
|
||||||
|
if (unlikely(IsDeviceLost())) {
|
||||||
|
return D3DERR_DEVICELOST;
|
||||||
|
}
|
||||||
|
|
||||||
m_implicitSwapchain->Invalidate(pPresentationParameters->hDeviceWindow);
|
m_implicitSwapchain->Invalidate(pPresentationParameters->hDeviceWindow);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -7094,7 +7113,7 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
HRESULT D3D9DeviceEx::ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters) {
|
void D3D9DeviceEx::ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters) {
|
||||||
if (!pPresentationParameters->EnableAutoDepthStencil)
|
if (!pPresentationParameters->EnableAutoDepthStencil)
|
||||||
SetDepthStencilSurface(nullptr);
|
SetDepthStencilSurface(nullptr);
|
||||||
|
|
||||||
@ -7335,8 +7354,6 @@ namespace dxvk {
|
|||||||
UpdateVertexBoolSpec(0u);
|
UpdateVertexBoolSpec(0u);
|
||||||
UpdatePixelBoolSpec(0u);
|
UpdatePixelBoolSpec(0u);
|
||||||
UpdateCommonSamplerSpec(0u, 0u, 0u);
|
UpdateCommonSamplerSpec(0u, 0u, 0u);
|
||||||
|
|
||||||
return D3D_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -7410,9 +7427,7 @@ namespace dxvk {
|
|||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
hr = ResetState(pPresentationParameters);
|
ResetState(pPresentationParameters);
|
||||||
if (FAILED(hr))
|
|
||||||
return hr;
|
|
||||||
|
|
||||||
Flush();
|
Flush();
|
||||||
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
|
||||||
|
@ -87,6 +87,12 @@ namespace dxvk {
|
|||||||
|
|
||||||
using D3D9DeviceFlags = Flags<D3D9DeviceFlag>;
|
using D3D9DeviceFlags = Flags<D3D9DeviceFlag>;
|
||||||
|
|
||||||
|
enum class D3D9DeviceLostState {
|
||||||
|
Ok = 0,
|
||||||
|
Lost = 1,
|
||||||
|
NotReset = 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct D3D9DrawInfo {
|
struct D3D9DrawInfo {
|
||||||
uint32_t vertexCount;
|
uint32_t vertexCount;
|
||||||
uint32_t instanceCount;
|
uint32_t instanceCount;
|
||||||
@ -933,7 +939,7 @@ namespace dxvk {
|
|||||||
const D3D9ConstantLayout& GetVertexConstantLayout() { return m_vsLayout; }
|
const D3D9ConstantLayout& GetVertexConstantLayout() { return m_vsLayout; }
|
||||||
const D3D9ConstantLayout& GetPixelConstantLayout() { return m_psLayout; }
|
const D3D9ConstantLayout& GetPixelConstantLayout() { return m_psLayout; }
|
||||||
|
|
||||||
HRESULT ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters);
|
void ResetState(D3DPRESENT_PARAMETERS* pPresentationParameters);
|
||||||
HRESULT ResetSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
HRESULT ResetSwapChain(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
||||||
|
|
||||||
HRESULT InitialReset(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
HRESULT InitialReset(D3DPRESENT_PARAMETERS* pPresentationParameters, D3DDISPLAYMODEEX* pFullscreenDisplayMode);
|
||||||
@ -950,6 +956,43 @@ namespace dxvk {
|
|||||||
void TouchMappedTexture(D3D9CommonTexture* pTexture);
|
void TouchMappedTexture(D3D9CommonTexture* pTexture);
|
||||||
void RemoveMappedTexture(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:
|
private:
|
||||||
|
|
||||||
DxvkCsChunkRef AllocCsChunk() {
|
DxvkCsChunkRef AllocCsChunk() {
|
||||||
@ -1317,6 +1360,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
Direct3DState9 m_state;
|
Direct3DState9 m_state;
|
||||||
|
|
||||||
|
D3D9DeviceLostState m_deviceLostState = D3D9DeviceLostState::Ok;
|
||||||
|
HWND m_fullscreenWindow = NULL;
|
||||||
|
|
||||||
#ifdef D3D9_ALLOW_UNMAPPING
|
#ifdef D3D9_ALLOW_UNMAPPING
|
||||||
lru_list<D3D9CommonTexture*> m_mappedTextures;
|
lru_list<D3D9CommonTexture*> m_mappedTextures;
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,6 +74,7 @@ namespace dxvk {
|
|||||||
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
|
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
|
||||||
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
|
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
|
||||||
this->textureMemory = config.getOption<int32_t> ("d3d9.textureMemory", 100) << 20;
|
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"));
|
std::string floatEmulation = Config::toLower(config.getOption<std::string>("d3d9.floatEmulation", "auto"));
|
||||||
if (floatEmulation == "strict") {
|
if (floatEmulation == "strict") {
|
||||||
|
@ -158,6 +158,9 @@ namespace dxvk {
|
|||||||
|
|
||||||
/// Shader dump path
|
/// Shader dump path
|
||||||
std::string shaderDumpPath;
|
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) {
|
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) {
|
if (m_state == D3D9_VK_QUERY_CACHED) {
|
||||||
// Query data was already retrieved once.
|
// Query data was already retrieved once.
|
||||||
// Use cached query data to prevent having to check the VK event
|
// Use cached query data to prevent having to check the VK event
|
||||||
@ -148,8 +156,6 @@ namespace dxvk {
|
|||||||
|
|
||||||
HRESULT hr = this->GetQueryData(pData, dwSize);
|
HRESULT hr = this->GetQueryData(pData, dwSize);
|
||||||
|
|
||||||
bool flush = dwGetDataFlags & D3DGETDATA_FLUSH;
|
|
||||||
|
|
||||||
// If we get S_FALSE and it's not from the fact
|
// If we get S_FALSE and it's not from the fact
|
||||||
// they didn't call end, do some flushy stuff...
|
// they didn't call end, do some flushy stuff...
|
||||||
if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
|
if (flush && hr == S_FALSE && m_state != D3D9_VK_QUERY_BEGUN) {
|
||||||
|
@ -103,6 +103,9 @@ namespace dxvk {
|
|||||||
DWORD dwFlags) {
|
DWORD dwFlags) {
|
||||||
D3D9DeviceLock lock = m_parent->LockDevice();
|
D3D9DeviceLock lock = m_parent->LockDevice();
|
||||||
|
|
||||||
|
if (unlikely(m_parent->IsDeviceLost()))
|
||||||
|
return D3DERR_DEVICELOST;
|
||||||
|
|
||||||
// If we have no backbuffers, error out.
|
// If we have no backbuffers, error out.
|
||||||
// This handles the case where a ::Reset failed due to OOM
|
// This handles the case where a ::Reset failed due to OOM
|
||||||
// or whatever.
|
// or whatever.
|
||||||
@ -238,6 +241,10 @@ namespace dxvk {
|
|||||||
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;
|
||||||
|
|
||||||
|
if (unlikely(m_parent->IsDeviceLost())) {
|
||||||
|
return D3DERR_DEVICELOST;
|
||||||
|
}
|
||||||
|
|
||||||
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
|
VkExtent3D dstTexExtent = dstTexInfo->GetExtentMip(dst->GetMipLevel());
|
||||||
VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(0);
|
VkExtent3D srcTexExtent = srcTexInfo->GetExtentMip(0);
|
||||||
|
|
||||||
@ -540,6 +547,8 @@ namespace dxvk {
|
|||||||
this->LeaveFullscreenMode();
|
this->LeaveFullscreenMode();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
m_parent->NotifyFullscreen(m_window, true);
|
||||||
|
|
||||||
if (changeFullscreen) {
|
if (changeFullscreen) {
|
||||||
hr = this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode);
|
hr = this->EnterFullscreenMode(pPresentParams, pFullscreenDisplayMode);
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
@ -1151,6 +1160,8 @@ namespace dxvk {
|
|||||||
return D3DERR_INVALIDCALL;
|
return D3DERR_INVALIDCALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_parent->NotifyFullscreen(m_window, true);
|
||||||
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1171,6 +1182,8 @@ namespace dxvk {
|
|||||||
return D3DERR_NOTAVAILABLE;
|
return D3DERR_NOTAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_parent->NotifyFullscreen(m_window, false);
|
||||||
|
|
||||||
return D3D_OK;
|
return D3D_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ namespace dxvk
|
|||||||
bool unicode;
|
bool unicode;
|
||||||
bool filter;
|
bool filter;
|
||||||
bool activateProcessed;
|
bool activateProcessed;
|
||||||
|
bool deactivateProcessed;
|
||||||
WNDPROC proc;
|
WNDPROC proc;
|
||||||
D3D9SwapChainEx* swapchain;
|
D3D9SwapChainEx* swapchain;
|
||||||
};
|
};
|
||||||
@ -53,11 +54,14 @@ namespace dxvk
|
|||||||
DefWindowProcW, DefWindowProcA, unicode,
|
DefWindowProcW, DefWindowProcA, unicode,
|
||||||
window, message, wparam, lparam);
|
window, message, wparam, lparam);
|
||||||
|
|
||||||
|
|
||||||
|
D3D9DeviceEx* device = windowData.swapchain->GetParent();
|
||||||
|
|
||||||
if (message == WM_DESTROY)
|
if (message == WM_DESTROY)
|
||||||
ResetWindowProc(window);
|
ResetWindowProc(window);
|
||||||
else if (message == WM_ACTIVATEAPP) {
|
else if (message == WM_ACTIVATEAPP) {
|
||||||
D3DDEVICE_CREATION_PARAMETERS create_parms;
|
D3DDEVICE_CREATION_PARAMETERS create_parms;
|
||||||
windowData.swapchain->GetDevice()->GetCreationParameters(&create_parms);
|
device->GetCreationParameters(&create_parms);
|
||||||
|
|
||||||
if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES)) {
|
if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES)) {
|
||||||
D3D9WindowMessageFilter filter(window);
|
D3D9WindowMessageFilter filter(window);
|
||||||
@ -70,19 +74,24 @@ namespace dxvk
|
|||||||
windowData.swapchain->GetPresentParameters(¶ms);
|
windowData.swapchain->GetPresentParameters(¶ms);
|
||||||
SetWindowPos(window, nullptr, rect.left, rect.top, params.BackBufferWidth, params.BackBufferHeight,
|
SetWindowPos(window, nullptr, rect.left, rect.top, params.BackBufferWidth, params.BackBufferHeight,
|
||||||
SWP_NOACTIVATE | SWP_NOZORDER);
|
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||||
SetActivateProcessed(window, true);
|
|
||||||
}
|
}
|
||||||
else if (!wparam) {
|
else if (!wparam) {
|
||||||
if (IsWindowVisible(window))
|
if (IsWindowVisible(window))
|
||||||
ShowWindow(window, SW_MINIMIZE);
|
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)
|
else if (message == WM_SIZE)
|
||||||
{
|
{
|
||||||
D3DDEVICE_CREATION_PARAMETERS create_parms;
|
D3DDEVICE_CREATION_PARAMETERS create_parms;
|
||||||
windowData.swapchain->GetDevice()->GetCreationParameters(&create_parms);
|
device->GetCreationParameters(&create_parms);
|
||||||
|
|
||||||
if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES) && !IsIconic(window))
|
if (!(create_parms.BehaviorFlags & D3DCREATE_NOWINDOWCHANGES) && !IsIconic(window))
|
||||||
PostMessageW(window, WM_ACTIVATEAPP, 1, GetCurrentThreadId());
|
PostMessageW(window, WM_ACTIVATEAPP, 1, GetCurrentThreadId());
|
||||||
@ -137,8 +146,10 @@ namespace dxvk
|
|||||||
{
|
{
|
||||||
std::lock_guard lock(g_windowProcMapMutex);
|
std::lock_guard lock(g_windowProcMapMutex);
|
||||||
auto it = g_windowProcMap.find(window);
|
auto it = g_windowProcMap.find(window);
|
||||||
if (it != g_windowProcMap.end())
|
if (it != g_windowProcMap.end()) {
|
||||||
it->second.activateProcessed = processed;
|
it->second.activateProcessed = processed;
|
||||||
|
it->second.deactivateProcessed = !processed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
D3D9WindowMessageFilter::D3D9WindowMessageFilter(HWND window, bool filter) {
|
D3D9WindowMessageFilter::D3D9WindowMessageFilter(HWND window, bool filter) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user