diff --git a/src/dxgi/dxgi_adapter.cpp b/src/dxgi/dxgi_adapter.cpp index 0a076c94..27448e7d 100644 --- a/src/dxgi/dxgi_adapter.cpp +++ b/src/dxgi/dxgi_adapter.cpp @@ -64,8 +64,7 @@ namespace dxvk { || InterfaceName == __uuidof(ID3D10Device1)) { Logger::warn("DXGI: CheckInterfaceSupport: No D3D10 support"); - DxgiOptions dxgiOptions = getDxgiAppOptions(env::getExeName()); - return dxgiOptions.test(DxgiOption::FakeDx10Support) + return m_factory->GetOptions()->fakeDx10Support ? S_OK : DXGI_ERROR_UNSUPPORTED; } @@ -215,7 +214,8 @@ namespace dxvk { InitReturnPtr(ppDevice); try { - *ppDevice = new dxvk::DxgiDevice(pContainer, this, pFeatures); + *ppDevice = new dxvk::DxgiDevice(pContainer, + this, m_factory->GetOptions(), pFeatures); return S_OK; } catch (const dxvk::DxvkError& e) { dxvk::Logger::err(e.message()); diff --git a/src/dxgi/dxgi_device.cpp b/src/dxgi/dxgi_device.cpp index 38cb3da9..a675198e 100644 --- a/src/dxgi/dxgi_device.cpp +++ b/src/dxgi/dxgi_device.cpp @@ -8,9 +8,11 @@ namespace dxvk { DxgiDevice::DxgiDevice( IDXGIObject* pContainer, IDXGIVkAdapter* pAdapter, + const DxgiOptions* pOptions, const DxvkDeviceFeatures* pFeatures) - : m_container (pContainer), - m_adapter (pAdapter) { + : m_container (pContainer), + m_adapter (pAdapter), + m_frameLatencyCap (pOptions->maxFrameLatency) { m_device = m_adapter->GetDXVKAdapter()->createDevice(*pFeatures); for (uint32_t i = 0; i < m_frameEvents.size(); i++) @@ -161,7 +163,13 @@ namespace dxvk { Rc STDMETHODCALLTYPE DxgiDevice::GetFrameSyncEvent() { - uint32_t frameId = m_frameId++ % m_frameLatency; + uint32_t frameLatency = m_frameLatency; + + if (m_frameLatencyCap != 0 + && m_frameLatencyCap <= frameLatency) + frameLatency = m_frameLatencyCap; + + uint32_t frameId = m_frameId++ % frameLatency; return m_frameEvents[frameId]; } diff --git a/src/dxgi/dxgi_device.h b/src/dxgi/dxgi_device.h index 3a1e64a3..bb1a27dd 100644 --- a/src/dxgi/dxgi_device.h +++ b/src/dxgi/dxgi_device.h @@ -4,6 +4,7 @@ #include "dxgi_adapter.h" #include "dxgi_interfaces.h" +#include "dxgi_options.h" namespace dxvk { @@ -16,6 +17,7 @@ namespace dxvk { DxgiDevice( IDXGIObject* pContainer, IDXGIVkAdapter* pAdapter, + const DxgiOptions* pOptions, const DxvkDeviceFeatures* pFeatures); ~DxgiDevice(); @@ -96,8 +98,9 @@ namespace dxvk { Com m_adapter; Rc m_device; - uint32_t m_frameLatency = DefaultFrameLatency; - uint32_t m_frameId = 0; + uint32_t m_frameLatencyCap = 0; + uint32_t m_frameLatency = DefaultFrameLatency; + uint32_t m_frameId = 0; std::array, 16> m_frameEvents; diff --git a/src/dxgi/dxgi_factory.cpp b/src/dxgi/dxgi_factory.cpp index 4d9b60b6..1b97d6c2 100644 --- a/src/dxgi/dxgi_factory.cpp +++ b/src/dxgi/dxgi_factory.cpp @@ -4,7 +4,8 @@ namespace dxvk { DxgiFactory::DxgiFactory() - : m_instance(new DxvkInstance()) { + : m_instance(new DxvkInstance()), + m_options (m_instance->config()) { for (uint32_t i = 0; m_instance->enumAdapters(i) != nullptr; i++) m_instance->enumAdapters(i)->logAdapterInfo(); } diff --git a/src/dxgi/dxgi_factory.h b/src/dxgi/dxgi_factory.h index 9217a710..de2420b7 100644 --- a/src/dxgi/dxgi_factory.h +++ b/src/dxgi/dxgi_factory.h @@ -5,6 +5,7 @@ #include #include "dxgi_adapter.h" +#include "dxgi_options.h" namespace dxvk { @@ -100,9 +101,14 @@ namespace dxvk { void STDMETHODCALLTYPE UnregisterOcclusionStatus( DWORD dwCookie) final; + const DxgiOptions* GetOptions() const { + return &m_options; + } + private: Rc m_instance; + DxgiOptions m_options; HWND m_associatedWindow = nullptr; diff --git a/src/dxgi/dxgi_options.cpp b/src/dxgi/dxgi_options.cpp index 3644e74e..a251b365 100644 --- a/src/dxgi/dxgi_options.cpp +++ b/src/dxgi/dxgi_options.cpp @@ -4,23 +4,10 @@ namespace dxvk { - const static std::unordered_map g_dxgiAppOptions = {{ - { "Frostpunk.exe", DxgiOptions(DxgiOption::DeferSurfaceCreation) }, - { "Wow.exe", DxgiOptions(DxgiOption::FakeDx10Support) }, - }}; - - - DxgiOptions getDxgiAppOptions(const std::string& appName) { - DxgiOptions options; - - auto appOptions = g_dxgiAppOptions.find(appName); - if (appOptions != g_dxgiAppOptions.end()) - options = appOptions->second; - - if (env::getEnvVar(L"DXVK_FAKE_DX10_SUPPORT") == "1") - options.set(DxgiOption::FakeDx10Support); - - return options; + DxgiOptions::DxgiOptions(const Config& config) { + this->deferSurfaceCreation = config.getOption ("dxgi.deferSurfaceCreation", false); + this->fakeDx10Support = config.getOption ("dxgi.fakeDx10Support", false); + this->maxFrameLatency = config.getOption ("dxgi.maxFrameLatency", 0); } } \ No newline at end of file diff --git a/src/dxgi/dxgi_options.h b/src/dxgi/dxgi_options.h index d6376b1e..86bea890 100644 --- a/src/dxgi/dxgi_options.h +++ b/src/dxgi/dxgi_options.h @@ -1,5 +1,7 @@ #pragma once +#include "../util/config/config.h" + #include "dxgi_include.h" namespace dxvk { @@ -10,26 +12,22 @@ namespace dxvk { * Per-app options that control the * behaviour of some DXGI classes. */ - enum class DxgiOption : uint64_t { + struct DxgiOptions { + DxgiOptions(const Config& config); + /// Defer surface creation until first present call. This /// fixes issues with games that create multiple swap chains /// for a single window that may interfere with each other. - DeferSurfaceCreation, + bool deferSurfaceCreation; /// Report to the app that Dx10 interfaces are supported, /// even if they are not actually supported. Some apps /// refuse to start without it, some don't work with it. - FakeDx10Support, + bool fakeDx10Support; + + /// Override maximum frame latency if the app specifies + /// a higher value. May help with frame timing issues. + int32_t maxFrameLatency; }; - using DxgiOptions = Flags; - - /** - * \brief Gets app-specific DXGI options - * - * \param [in] appName Application name - * \returns DXGI options for this application - */ - DxgiOptions getDxgiAppOptions(const std::string& appName); - } diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index b2182849..f639b3fe 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -8,6 +8,7 @@ namespace dxvk { DxgiVkPresenter::DxgiVkPresenter( + const DxgiOptions* pOptions, const Rc& device, HWND window) : m_window (window), @@ -16,9 +17,7 @@ namespace dxvk { // Some games don't work with deferred surface creation, // so we should default to initializing it immediately. - DxgiOptions dxgiOptions = getDxgiAppOptions(env::getExeName()); - - if (!dxgiOptions.test(DxgiOption::DeferSurfaceCreation)) + if (!pOptions->deferSurfaceCreation) m_surface = CreateSurface(); // Reset options for the swap chain itself. We will diff --git a/src/dxgi/dxgi_presenter.h b/src/dxgi/dxgi_presenter.h index 9258cc66..11f4afae 100644 --- a/src/dxgi/dxgi_presenter.h +++ b/src/dxgi/dxgi_presenter.h @@ -69,6 +69,7 @@ namespace dxvk { public: DxgiVkPresenter( + const DxgiOptions* pOptions, const Rc& device, HWND window); diff --git a/src/dxgi/dxgi_swapchain.cpp b/src/dxgi/dxgi_swapchain.cpp index f705a97d..a55be36e 100644 --- a/src/dxgi/dxgi_swapchain.cpp +++ b/src/dxgi/dxgi_swapchain.cpp @@ -469,6 +469,7 @@ namespace dxvk { HRESULT DxgiSwapChain::CreatePresenter() { try { m_presenter = new DxgiVkPresenter( + m_factory->GetOptions(), m_device->GetDXVKDevice(), m_window); return S_OK;