Compare commits

...

66 Commits

Author SHA1 Message Date
Rémi Bernon f57f084bda
Merge f553af6963 into 462165da19 2024-04-26 08:07:06 -05:00
Philip Rebohle 462165da19 [util] Add Deck profile for Fallout 4
Should fix the FPS problem on Deck OLED.
2024-04-26 14:34:08 +02:00
Philip Rebohle 3f27a0ee58 [util] Add a way to define app profiles exclusive to Steam Deck 2024-04-26 14:34:08 +02:00
Katharine Chui aac3396671 [dxgi] unchain DxgiFactory::CreateSwapChain and CreateSwapChainForHwnd
similar to https://github.com/doitsujin/dxvk/pull/3966, avoid
chaining so that dxgi tools attempting to wrap swapchains don't
end up double wrapping

ref: https://github.com/SpecialKO/SpecialK/issues/168
2024-04-25 12:07:50 +02:00
Katharine Chui 92a43ebf65 [dxgi] unchain DxgiSwapChain::Present1 and Present
dxgi hooking tools might hook both, eg. https://github.com/SpecialKO/SpecialK/issues/167
2024-04-22 14:04:43 +02:00
Blisto91 8ba5256dc7 [util] Set deferSurfaceCreation for 9th Dawn II
OpenGL game that also spins up d3d9. Will black screen without deferSurfaceCreation when using dxvk
2024-04-22 04:48:56 +02:00
Philip Rebohle 2b70ba8f77 [dxbc] Do not emit OpImageQueryLevels for multisampled images 2024-04-19 13:55:31 +02:00
Philip Rebohle 9c66c4bf1d [build] Target SPIR-V 1.6 for built-in GLSL shaders
Silences a Mesa warning when the HUD is enabled.
2024-04-19 13:36:32 +02:00
Philip Rebohle 00872e9e4f [dxvk] Fix render target clears with format reinterpretation
With LOAD_OP_CLEAR, we cannot rely on the clear actually being performed
with the view format in mind. Use a vkCmdClearAttachment path instead.
2024-04-19 13:08:36 +02:00
Philip Rebohle 35157357dd [dxvk] Fix stencil discard being broken 2024-04-19 01:43:23 +02:00
Philip Rebohle 617ebf4e05 [dxbc] Take used components into account for PS inputs 2024-04-19 01:01:52 +02:00
Philip Rebohle c2489d5a45 [dxbc] Fix array register anaylsis with multiple dst operands 2024-04-19 01:01:52 +02:00
Philip Rebohle 6ef98c613f [dxvk] Re-enable maintenance4 feature
Sileces some validation errors.
2024-04-19 01:01:52 +02:00
Philip Rebohle 7441137a33 [dxbc] Ignore system value components when declaring inputs 2024-04-19 01:01:52 +02:00
WinterSnowfall 571948cfc0 [d3d9] Remove support for VERTEXSTATS queries 2024-04-13 19:11:00 +01:00
Martino Fontana 133f0794bc [util] Remove framerate limiter for Nier Replicant
Without mods, Nier Replicant runs faster when going above 60 FPS.
The game had an official patch that implemented a framerate limiter to prevent this. This limiter is terrible, because it's not a stable 60 FPS, but a weird 57-58 FPS. There's no way to disable this in-game, it has to be done by editing a config file or through a mod.

So, why remove the default frame limiter from DXVK?
- In the default case (a user plays the game as it is), it does nothing, since 57-58 is lower than 60.
- If a user is going out of their way to edit the config file, why would they assume that DXVK already provides a frame limiter? They are going to follow [a guide](https://www.pcgamingwiki.com/wiki/NieR_Replicant#Framerate_limited_to_57.7E58_FPS) that says to set up a frame limiter, it doesn't say "set up a frame limiter, unless you are using DXVK, in that case it's already there".
- They are using [Special K in order to use a mod to play at high refresh rates at normal speed](https://wiki.special-k.info/SpecialK/Custom/Replicant). In this case, DXVK's default limiter is harmful, since it is not documented that it's there by default.

Since this default limiter is useless in the first two cases and harmful in the third, I think it should be removed.
The alternative would be to document this (e.g. in PCGamingWiki), but the instructions wouldn't look pretty... "After following the instructions to use Special K in order to play at higher framerates at normal speed, if are using DXVK/Proton, also do these things to disable its default 60 FPS cap: [...]"

Especially because that the game isn't broken in the default case, I don't think DXVK should tamper with these things in a way that requires documentation to revert.

Tested Special K's mod to play at higher refresh rates on Linux.
2024-04-08 21:48:47 +02:00
Philip Rebohle 44695f9311 [dxvk] Adjust desciptor pool reset heuristic
Drastically limits the amount of descriptor memory we allocate in situations
where an application renders without presenting anything to a swap chain.

The new limit is a bit tight for some real-world use cases (e.g. Ashes of the Singularity),
but at worst we will start calling vkAllocateDescriptorSets once per set and draw.
2024-04-08 15:40:25 +02:00
Casey Bowman 49e9ea5f5a [dxgi] Force vendor ID change when XeSS is detected on an Intel GPU
Games using libxess.dll or wrapper modules will crash.
To work around this, we hide the Intel GPU's vendor ID to avoid using the
XeSS module.
2024-04-03 20:32:04 +02:00
Blisto91 198bd3a4b8 [d3d11] Remove missed Shared Keyedmutex warning
D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX is implemented.
2024-04-03 20:31:52 +02:00
Philip Rebohle f06c646315 [dxbc] Remove broken atomic counter subgroup optimization
This is not a legal optimization inside non-uniform control flow due
to Vulkan's extremely permissive convergence rules, and apparently
breaks on Nvidia as a result.

Mesa drivers already do the same thing internally anyway.
2024-04-03 14:55:43 +02:00
Philip Rebohle 855b2746b6 [util] Remove TRAHA Global config
This game apparently no longer exists.
2024-03-26 13:42:55 +01:00
Blisto91 28c7c09bf5 [dxgi] Remove useMonitorFallback option
QueryDisplayConfig optimization is now in Proton 9 Wine
2024-03-21 17:23:38 +01:00
Philip Rebohle 2742486540 [dxvk] Don't query color space support for null surfaces
Fixes a crash in games with the dxgi.deferSurfaceCreation workaround set.
Note that this potentially breaks HDR.
2024-03-21 15:32:48 +01:00
Philip Rebohle 037d0fa1ad [meta] Release 2.3.1 2024-03-20 13:48:30 +01:00
Philip Rebohle cbf51a7a25 [d3d11] Enable copy usage for typeless images as necessary 2024-03-20 13:30:31 +01:00
Philip Rebohle 70e34dc31c [dxvk] Support arbitrary source formats for color<->depth copies
Fixes rendering bugs in War Thunder.
2024-03-20 13:29:59 +01:00
Philip Rebohle c5aeb0f87a [dxvk] Get rid of separate depth shaders for shader-based copies
We can export both depth and color in a single shader instead.
2024-03-19 19:32:12 +01:00
Philip Rebohle a163082770 [dxvk] Align index buffer size to index size
Fixes validation errors in FFXIV.
2024-03-19 19:32:12 +01:00
Blisto91 2e1a19c7fd [util] Cap Dark Void to 60fps
Game crashes in certain places like specific cutscenes unless capped at 60fps.
2024-03-18 12:56:27 +01:00
Joshua Ashton 0beb18ef73 [d3d9] Wait for submission when calling ReturnUnderlyingResource 2024-03-16 19:11:11 +00:00
Joshua Ashton ef4428ab8c [d3d9] Improve ReturnUnderlyingResource stub for 9on12 2024-03-16 18:59:03 +00:00
Philip Rebohle 1085ba713e [dxgi] Implicitly set HDR color space for RGBA16_FLOAT swap chains 2024-03-16 18:56:41 +00:00
Philip Rebohle e857b09432 [dxgi] Change default behaviour of hideNvkGpu option 2024-03-15 22:48:57 +01:00
Kaitlyn 538f1d13d4 Fix UAV as well 2024-03-15 15:22:13 +01:00
Kaitlyn 783c9d4591 Fix MiscFlags check in GetDescFromResource 2024-03-15 15:22:13 +01:00
Kaitlyn 1a685b1c67 Implement D3D11DXGIDevice::EnqueueSetEvent 2024-03-15 13:47:28 +01:00
Robin Kertels 8b8be7c2bf [d3d9] Fix stream count in Reset 2024-03-10 17:12:22 +01:00
Billy Laws 0776d764a4
build: Support building for ARM64EC
When targeting ARM64EC, both __x86_64__ and _M_X86_64 are defined but
not all x86 intrinsics are present, treat EC as regular ARM64 so the
native intrinsics are used instead.
2024-03-09 05:43:46 +00:00
Robin Kertels 15ddadc4de [d3d9] Fix number of streams 2024-03-08 18:42:15 +01:00
Philip Rebohle 69a52b3da0 [dxbc] Do not emit depth compare for unsupported image types
Fixes invalid SPIR-V.
2024-03-07 16:11:23 +01:00
Philip Rebohle 707ad6f328 [spirv] Add OpConstantNull 2024-03-07 16:11:23 +01:00
Philip Rebohle 3a6992ea97 [dxbc] Enable depth compare types for 1D images
Used by Renderdoc internal shaders.
2024-03-07 16:11:23 +01:00
Robin Kertels 72c86b8229 [d3d9] Only unbind in EndScene if the game cleared the binding 2024-03-06 22:58:48 +01:00
Robin Kertels 85215b10d6 [d3d9] Respect vertex buffer offset when dynamically uploading geometry 2024-03-06 18:13:26 +01:00
Philip Rebohle fd3fbf6607 [dxvk] Remove old memory budget code
Obsolete since we removed the Nvidia HVV workaround for old drivers.

Closes #3877.
2024-03-06 15:48:34 +01:00
Minelelol 0a699fddb6 Update config.cpp
Insane Performance increase
2024-03-06 15:25:16 +01:00
Blisto91 afec5cce88 [util] Remove some unneeded built in configs
Dirt 5 does not crash without working ags anymore and Ethan Carter Redux also starts fine without a spoof.
This allows the built in AMD ags in Proton 9 to be used for these games.

The Hitman 3 config is redundant as it doesn't allow RT to be enabled without Nvapi anyway.
2024-03-06 15:24:54 +01:00
Ethan Lee 4b0e3111d1 meson: Check for bundled Vulkan/SPIR-V headers before adding them to the include list.
This feature requires Meson 0.58 or newer.
2024-03-06 15:21:15 +01:00
Philip Rebohle 0414bbe2d5 [dxgi] Add separate option to override vendor IDs for NVK 2024-03-06 14:46:21 +01:00
Robin Kertels 20490b678f [d3d9] Fix missing else brackets in ResetSwapchain 2024-03-06 12:08:45 +01:00
Blisto91 428c98bc63 [util] Disable countLosableResources for all d3d9 Supreme Ruler games
All the d3d9 Supreme ruler games have this issue.
2024-03-05 15:28:11 +01:00
Robin Kertels a0e39e94fa [d3d9] Use most recently used swapchain for GetFrontBufferData 2024-03-05 13:54:15 +00:00
Robin Kertels eaa732d0b3 [d3d9] Place GetFrontBufferData screenshot at window position 2024-03-05 13:54:15 +00:00
Robin Kertels 49b18f03fe [d3d9] Unbind buffers in EndScene & Reset 2024-03-05 13:52:51 +00:00
Philip Rebohle c9cea93b7b [dxbc] Use raw access chains for buffer loads and stores
Maps more or less perfectly to D3D raw and structured buffers.
2024-03-05 14:41:18 +01:00
Philip Rebohle 69d74a46a0 [dxbc] Remove emitRawBuffer{Load,Store}
And factor these into the callers. We need to preserve the raw
index and offset parameters to use raw access chains.
2024-03-05 14:41:18 +01:00
Philip Rebohle 94098aa97d [dxbc] Enable SPV_NV_raw_access_chains 2024-03-05 14:41:18 +01:00
Philip Rebohle c677ba9b3e [dxvk] Enable VK_NV_raw_access_chains if available 2024-03-05 14:41:18 +01:00
Philip Rebohle 77c7396ee1 [spirv] Add support for OpRawAccessChainNV 2024-03-05 14:41:18 +01:00
Philip Rebohle f07e5f9eaa [include] Update SPIR-V headers 2024-03-05 14:41:18 +01:00
Philip Rebohle d5c3011f54 [include] Update Vulkan headers 2024-03-05 14:41:18 +01:00
Blisto91 6b3b934471 [util] Clarify maxDeviceMemory and maxSharedMemory
This config often leads to confusion as people expect applications to honor the limit.
2024-03-02 20:41:19 +01:00
Philip Rebohle 9004c132ed [dxbc] Declare dynamically indexed UBOs with the maximum possible size
Fixes #3861.
2024-02-23 13:39:29 +01:00
Philip Rebohle 24d4c9c938 [util] Disable command lists for Granblue Fantasy Relink
The uses deferred contexts for rendering if driver command lists are enabled,
but when AMDAGS is loaded, it will also unconditionally use MultiDrawIndirect
functions. Since the AGS version in use does not support deferred contexts,
this breaks rendering, so we will have to force it into the immediate context
path.

Testing also shows slightly higher performance (~3-5%) with this path in
CPU-bound scenarios.
2024-02-22 16:07:24 +01:00
Philip Rebohle 5ded7d67f0 [d3d11] Implement UpdateSubresource bug if native command lists are disabled 2024-02-22 16:07:24 +01:00
Philip Rebohle 234f3ea071 [d3d11] Add option to hide native command list support 2024-02-22 16:07:24 +01:00
58 changed files with 1218 additions and 779 deletions

View File

@ -1 +1 @@
2.3
2.3.1

View File

@ -62,7 +62,7 @@
# Report Nvidia GPUs as AMD GPUs. Unless NVAPI support is explicitly
# enabled through proton, this is done by default in order to work
# enabled through Proton, this is done by default in order to work
# around crashes or low performance with Nvidia-speciic code paths
# in games, especially Unreal Engine.
#
@ -71,6 +71,13 @@
# dxgi.hideNvidiaGpu = Auto
# Report Nvidia GPUs running on NVK as AMD GPUs.
#
# Supported values: Auto, True, False
# dxgi.hideNvkGpu = Auto
# Report AMD GPUs as Nvidia GPUs. This is only done for games that are
# known to have issues with AMDAGS or other AMD-specific code paths.
#
@ -90,6 +97,7 @@
# Override maximum amount of device memory and shared system memory
# reported to the application. This may fix texture streaming issues
# in games that do not support cards with large amounts of VRAM.
# This is not a hard cap and applications can choose to ignore it.
#
# Supported values: Any number in Megabytes.
@ -292,6 +300,18 @@
# d3d11.enableContextLock = False
# Exposes or hides support for driver command lists
#
# Some games use the feature flag to decide whether to use deferred
# contexts or not. We enable this by default, but in some situations
# this can lead to issues if games detect an AMD GPU where command
# lists are not natively supported on Windows.
#
# Supported values: True, False
# d3d11.exposeDriverCommandLists = True
# Sets number of pipeline compiler threads.
#
# If the graphics pipeline library feature is enabled, the given
@ -624,18 +644,6 @@
# d3d9.textureMemory = 100
# Always enumerate all monitors on each dxgi output
#
# Used to avoid performance degradation in some games
# (will be deprecated once QueryDisplayConfig optimization
# is in Proton Wine).
#
# Supported values:
# - True/False
# dxgi.useMonitorFallback = False
# Hide integrated graphics from applications
#
# Only has an effect when dedicated GPUs are present on the system. It is

@ -1 +1 @@
Subproject commit 0bcc624926a25a2a273d07877fd25a6ff5ba1cfb
Subproject commit 8b246ff75c6615ba4532fe4fde20f1be090c3764

@ -1 +1 @@
Subproject commit 85c2334e92e215cce34e8e0ed8b2dce4700f4a50
Subproject commit 46dc0f6e514f5730784bb2cac2a7c731636839e8

View File

@ -1,7 +1,8 @@
project('dxvk', ['c', 'cpp'], version : 'v2.3', meson_version : '>= 0.49', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
project('dxvk', ['c', 'cpp'], version : 'v2.3.1', meson_version : '>= 0.58', default_options : [ 'cpp_std=c++17', 'warning_level=2' ])
cpu_family = target_machine.cpu_family()
platform = target_machine.system()
fs = import('fs')
cpp = meson.get_compiler('cpp')
cc = meson.get_compiler('c')
@ -33,11 +34,17 @@ if get_option('build_id')
]
endif
dxvk_include_dirs = [
'./include',
'./include/vulkan/include',
'./include/spirv/include'
]
dxvk_include_dirs = ['./include']
if fs.is_dir('./include/vulkan/include')
dxvk_include_dirs += ['./include/vulkan/include']
elif not cpp.check_header('vulkan/vulkan.h')
error('Missing Vulkan-Headers')
endif
if fs.is_dir('./include/spirv/include')
dxvk_include_dirs += ['./include/spirv/include']
elif not cpp.check_header('spirv/unified1/spirv.hpp')
error('Missing SPIRV-Headers')
endif
dep_displayinfo = dependency(
'libdisplay-info',
@ -153,7 +160,7 @@ def_spec_ext = '.def'
glsl_compiler = find_program('glslang', 'glslangValidator')
glsl_args = [
'--quiet',
'--target-env', 'vulkan1.2',
'--target-env', 'vulkan1.3',
'--vn', '@BASENAME@',
'--depfile', '@DEPFILE@',
'@INPUT@',

View File

@ -928,6 +928,34 @@ namespace dxvk {
const void* pSrcData,
UINT SrcRowPitch,
UINT SrcDepthPitch) {
if (IsDeferred && unlikely(pDstBox != nullptr) && unlikely(!m_parent->GetOptions()->exposeDriverCommandLists)) {
// If called from a deferred context and native command list support is not
// exposed, we need to apply the destination box to the source pointer. This
// only applies to UpdateSubresource, not to UpdateSubresource1. See MSDN:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
size_t srcOffset = pDstBox->left;
// For textures, the offset logic needs to take the format into account.
// Ignore that multi-planar images exist, this is hairy enough already.
D3D11CommonTexture* dstTexture = GetCommonTexture(pDstResource);
if (dstTexture) {
auto dstFormat = dstTexture->GetPackedFormat();
auto dstFormatInfo = lookupFormatInfo(dstFormat);
size_t blockSize = dstFormatInfo->elementSize;
VkOffset3D offset;
offset.x = pDstBox->left / dstFormatInfo->blockSize.width;
offset.y = pDstBox->top / dstFormatInfo->blockSize.height;
offset.z = pDstBox->front / dstFormatInfo->blockSize.depth;
srcOffset = offset.x * blockSize + offset.y * SrcRowPitch + offset.z * SrcDepthPitch;
}
pSrcData = reinterpret_cast<const char*>(pSrcData) + srcOffset;
}
UpdateResource(pDstResource, DstSubresource, pDstBox,
pSrcData, SrcRowPitch, SrcDepthPitch, 0);
}

View File

@ -45,10 +45,10 @@ namespace dxvk {
m_dxvkDevice (pContainer->GetDXVKDevice()),
m_dxvkAdapter (m_dxvkDevice->adapter()),
m_d3d11Formats (m_dxvkDevice),
m_d3d11Options (m_dxvkDevice->instance()->config(), m_dxvkDevice),
m_d3d11Options (m_dxvkDevice->instance()->config()),
m_dxbcOptions (m_dxvkDevice, m_d3d11Options),
m_maxFeatureLevel (GetMaxFeatureLevel(m_dxvkDevice->instance(), m_dxvkDevice->adapter())),
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_featureLevel) {
m_deviceFeatures (m_dxvkDevice->instance(), m_dxvkDevice->adapter(), m_d3d11Options, m_featureLevel) {
m_initializer = new D3D11Initializer(this);
m_context = new D3D11ImmediateContext(this, m_dxvkDevice);
m_d3d10Device = new D3D10Device(this, m_context.ptr());
@ -1348,7 +1348,7 @@ namespace dxvk {
m_deviceFeatures = D3D11DeviceFeatures(
m_dxvkDevice->instance(),
m_dxvkDevice->adapter(),
m_featureLevel);
m_d3d11Options, m_featureLevel);
}
if (pChosenFeatureLevel)
@ -3411,8 +3411,9 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D11DXGIDevice::EnqueueSetEvent(HANDLE hEvent) {
Logger::err("D3D11DXGIDevice::EnqueueSetEvent: Not implemented");
return DXGI_ERROR_UNSUPPORTED;
auto immediateContext = m_d3d11Device.GetContext();
immediateContext->Flush1(D3D11_CONTEXT_TYPE_ALL, hEvent);
return S_OK;
}

View File

@ -12,6 +12,7 @@ namespace dxvk {
D3D11DeviceFeatures::D3D11DeviceFeatures(
const Rc<DxvkInstance>& Instance,
const Rc<DxvkAdapter>& Adapter,
const D3D11Options& Options,
D3D_FEATURE_LEVEL FeatureLevel)
: m_features (Adapter->features()),
m_properties (Adapter->devicePropertiesExt()) {
@ -118,11 +119,11 @@ namespace dxvk {
m_shaderMinPrecision.PixelShaderMinPrecision = 0;
m_shaderMinPrecision.AllOtherShaderStagesMinPrecision = 0;
// Report native support for command lists here so that we do not actually have
// to re-implement the UpdateSubresource bug from the D3D11 runtime, see MSDN:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476486(v=vs.85).aspx)
// Report native support for command lists by default. Deferred context
// usage can be beneficial for us as ExecuteCommandList has low overhead,
// and we avoid having to deal with known UpdateSubresource bugs this way.
m_threading.DriverConcurrentCreates = TRUE;
m_threading.DriverCommandLists = TRUE;
m_threading.DriverCommandLists = Options.exposeDriverCommandLists;
}
@ -182,7 +183,8 @@ namespace dxvk {
D3D_FEATURE_LEVEL D3D11DeviceFeatures::GetMaxFeatureLevel(
const Rc<DxvkInstance>& Instance,
const Rc<DxvkAdapter>& Adapter) {
D3D11DeviceFeatures features(Instance, Adapter, D3D_FEATURE_LEVEL_12_1);
D3D11Options options(Instance->config());
D3D11DeviceFeatures features(Instance, Adapter, options, D3D_FEATURE_LEVEL_12_1);
return features.GetMaxFeatureLevel();
}

View File

@ -1,6 +1,7 @@
#pragma once
#include "d3d11_include.h"
#include "d3d11_options.h"
#include "../dxvk/dxvk_adapter.h"
#include "../dxvk/dxvk_instance.h"
@ -21,6 +22,7 @@ namespace dxvk {
D3D11DeviceFeatures(
const Rc<DxvkInstance>& Instance,
const Rc<DxvkAdapter>& Adapter,
const D3D11Options& Options,
D3D_FEATURE_LEVEL FeatureLevel);
~D3D11DeviceFeatures();

View File

@ -12,7 +12,7 @@ namespace dxvk {
#endif
}
D3D11Options::D3D11Options(const Config& config, const Rc<DxvkDevice>& device) {
D3D11Options::D3D11Options(const Config& config) {
this->dcSingleUseMode = config.getOption<bool>("d3d11.dcSingleUseMode", true);
this->zeroInitWorkgroupMemory = config.getOption<bool>("d3d11.zeroInitWorkgroupMemory", false);
this->forceVolatileTgsmAccess = config.getOption<bool>("d3d11.forceVolatileTgsmAccess", false);
@ -31,6 +31,7 @@ namespace dxvk {
this->numBackBuffers = config.getOption<int32_t>("dxgi.numBackBuffers", 0);
this->maxFrameLatency = config.getOption<int32_t>("dxgi.maxFrameLatency", 0);
this->maxFrameRate = config.getOption<int32_t>("dxgi.maxFrameRate", 0);
this->exposeDriverCommandLists = config.getOption<bool>("d3d11.exposeDriverCommandLists", true);
// Clamp LOD bias so that people don't abuse this in unintended ways
this->samplerLodBias = dxvk::fclamp(this->samplerLodBias, -2.0f, 1.0f);

View File

@ -11,7 +11,7 @@
namespace dxvk {
struct D3D11Options {
D3D11Options(const Config& config, const Rc<DxvkDevice>& device);
D3D11Options(const Config& config);
/// Enables speed hack for mapping on deferred contexts
///
@ -113,6 +113,11 @@ namespace dxvk {
/// race conditions.
bool enableContextLock;
/// Whether to expose the driver command list feature. Enabled by
/// default and generally beneficial, but some games may assume that
/// this is not supported when running on an AMD GPU.
bool exposeDriverCommandLists;
/// Shader dump path
std::string shaderDumpPath;
};

View File

@ -58,9 +58,6 @@ namespace dxvk {
"\n MiscFlags: ", m_desc.MiscFlags,
"\n FeatureLevel: ", pDevice->GetFeatureLevel()));
if (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX)
Logger::warn("D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX: not supported.");
imageInfo.shared = true;
imageInfo.sharing.mode = hSharedHandle == INVALID_HANDLE_VALUE ? DxvkSharedHandleMode::Export : DxvkSharedHandleMode::Import;
imageInfo.sharing.type = (m_desc.MiscFlags & D3D11_RESOURCE_MISC_SHARED_NTHANDLE)
@ -214,9 +211,12 @@ namespace dxvk {
// For some formats, we need to enable sampled and/or
// render target capabilities if available, but these
// should in no way affect the default image layout
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
imageInfo.usage |= EnableMetaPackUsage(imageInfo.format, m_desc.CPUAccessFlags);
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.format, imageInfo.tiling);
for (uint32_t i = 0; i < imageInfo.viewFormatCount; i++)
imageInfo.usage |= EnableMetaCopyUsage(imageInfo.viewFormats[i], imageInfo.tiling);
// Check if we can actually create the image
if (!CheckImageSupport(&imageInfo, imageInfo.tiling)) {
throw DxvkError(str::format(

View File

@ -298,7 +298,7 @@ namespace dxvk {
D3D11_BUFFER_DESC bufferDesc;
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
pDesc->Format = DXGI_FORMAT_UNKNOWN;
pDesc->ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
pDesc->Buffer.FirstElement = 0;

View File

@ -214,7 +214,7 @@ namespace dxvk {
D3D11_BUFFER_DESC bufferDesc;
static_cast<D3D11Buffer*>(pResource)->GetDesc(&bufferDesc);
if (bufferDesc.MiscFlags == D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
if (bufferDesc.MiscFlags & D3D11_RESOURCE_MISC_BUFFER_STRUCTURED) {
pDesc->Format = DXGI_FORMAT_UNKNOWN;
pDesc->ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
pDesc->Buffer.FirstElement = 0;

View File

@ -481,6 +481,14 @@ namespace dxvk {
return hr;
}
// Unbind all buffers that were still bound to the backend to avoid leaks.
EmitCs([](DxvkContext* ctx) {
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
ctx->bindVertexBuffer(i, DxvkBufferSlice(), 0);
}
});
Flush();
SynchronizeCsThread(DxvkCsThread::SynchronizeAll);
@ -1085,7 +1093,12 @@ namespace dxvk {
if (unlikely(iSwapChain != 0))
return D3DERR_INVALIDCALL;
return m_implicitSwapchain->GetFrontBufferData(pDestSurface);
D3D9DeviceLock lock = LockDevice();
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
// We use the last used swapchain as a workaround.
// Total War: Medieval 2 relies on this.
return m_mostRecentlyUsedSwapchain->GetFrontBufferData(pDestSurface);
}
@ -1603,6 +1616,23 @@ namespace dxvk {
m_flags.clr(D3D9DeviceFlag::InScene);
// D3D9 resets the internally bound vertex buffers and index buffer in EndScene if they were unbound in the meantime.
// We have to ignore unbinding those buffers because of Operation Flashpoint Red River,
// so we should also clear the bindings here, to avoid leaks.
if (m_state.indices == nullptr) {
EmitCs([](DxvkContext* ctx) {
ctx->bindIndexBuffer(DxvkBufferSlice(), VK_INDEX_TYPE_UINT32);
});
}
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
if (m_state.vertexBuffers[i].vertexBuffer == nullptr) {
EmitCs([cIndex = i](DxvkContext* ctx) {
ctx->bindVertexBuffer(cIndex, DxvkBufferSlice(), 0);
});
}
}
return D3D_OK;
}
@ -5223,7 +5253,7 @@ namespace dxvk {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
const uint32_t vertexStride = m_state.vertexDecl->GetSize(i);
uint32_t offset = (BaseVertexIndex + FirstVertexIndex) * vertexStride;
uint32_t offset = (BaseVertexIndex + FirstVertexIndex) * vertexStride + m_state.vertexBuffers[i].offset;
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + vboUPBufferOffsets[i];
uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + offset;
@ -5325,7 +5355,7 @@ namespace dxvk {
// Round to nearest
_controlfp(_RC_NEAR, _MCW_RC);
#elif (defined(__GNUC__) || defined(__MINGW32__)) && (defined(__i386__) || defined(__x86_64__) || defined(__ia64))
#elif (defined(__GNUC__) || defined(__MINGW32__)) && (defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) || defined(__ia64))
// For GCC/MinGW we can use inline asm to set it.
// This only works for x86 and x64 processors however.
@ -5642,10 +5672,13 @@ namespace dxvk {
}
void D3D9DeviceEx::Flush() {
template <bool Synchronize9On12>
void D3D9DeviceEx::ExecuteFlush() {
D3D9DeviceLock lock = LockDevice();
if constexpr (Synchronize9On12)
m_submitStatus.result = VK_NOT_READY;
m_initializer->Flush();
m_converter->Flush();
@ -5657,16 +5690,32 @@ namespace dxvk {
EmitCs<false>([
cSubmissionFence = m_submissionFence,
cSubmissionId = submissionId
cSubmissionId = submissionId,
cSubmissionStatus = Synchronize9On12 ? &m_submitStatus : nullptr
] (DxvkContext* ctx) {
ctx->signal(cSubmissionFence, cSubmissionId);
ctx->flushCommandList(nullptr);
ctx->flushCommandList(cSubmissionStatus);
});
FlushCsChunk();
m_flushSeqNum = m_csSeqNum;
m_flushTracker.notifyFlush(m_flushSeqNum, submissionId);
// If necessary, block calling thread until the
// Vulkan queue submission is performed.
if constexpr (Synchronize9On12)
m_dxvkDevice->waitForSubmission(&m_submitStatus);
}
void D3D9DeviceEx::Flush() {
ExecuteFlush<false>();
}
void D3D9DeviceEx::FlushAndSync9On12() {
ExecuteFlush<true>();
}
@ -7819,8 +7868,10 @@ namespace dxvk {
if (FAILED(hr))
return hr;
}
else
else {
m_implicitSwapchain = new D3D9SwapChainEx(this, pPresentationParameters, pFullscreenDisplayMode);
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
}
if (pPresentationParameters->EnableAutoDepthStencil) {
D3D9_COMMON_TEXTURE_DESC desc;

View File

@ -793,6 +793,7 @@ namespace dxvk {
void SynchronizeCsThread(uint64_t SequenceNumber);
void Flush();
void FlushAndSync9On12();
void EndFrame();
@ -1059,6 +1060,9 @@ namespace dxvk {
return std::exchange(m_deviceHasBeenReset, false);
}
template <bool Synchronize9On12>
void ExecuteFlush();
void DetermineConstantLayouts(bool canSWVP);
D3D9BufferSlice AllocUPBuffer(VkDeviceSize size);
@ -1241,6 +1245,34 @@ namespace dxvk {
uint64_t GetCurrentSequenceNumber();
/**
* @brief Get the swapchain that was used the most recently for presenting
* Has to be externally synchronized.
*
* @return D3D9SwapChainEx* Swapchain
*/
D3D9SwapChainEx* GetMostRecentlyUsedSwapchain() {
return m_mostRecentlyUsedSwapchain;
}
/**
* @brief Set the swapchain that was used the most recently for presenting
* Has to be externally synchronized.
*
* @param swapchain Swapchain
*/
void SetMostRecentlyUsedSwapchain(D3D9SwapChainEx* swapchain) {
m_mostRecentlyUsedSwapchain = swapchain;
}
/**
* @brief Reset the most recently swapchain back to the implicit one
* Has to be externally synchronized.
*/
void ResetMostRecentlyUsedSwapchain() {
m_mostRecentlyUsedSwapchain = m_implicitSwapchain.ptr();
}
Com<D3D9InterfaceEx> m_parent;
D3DDEVTYPE m_deviceType;
HWND m_window;
@ -1393,6 +1425,8 @@ namespace dxvk {
Rc<sync::Fence> m_submissionFence;
uint64_t m_submissionId = 0ull;
DxvkSubmitStatus m_submitStatus;
uint64_t m_flushSeqNum = 0ull;
GpuFlushTracker m_flushTracker;
@ -1403,6 +1437,8 @@ namespace dxvk {
HWND m_fullscreenWindow = NULL;
std::atomic<uint32_t> m_losableResourceCounter = { 0 };
D3D9SwapChainEx* m_mostRecentlyUsedSwapchain = nullptr;
#ifdef D3D9_ALLOW_UNMAPPING
lru_list<D3D9CommonTexture*> m_mappedTextures;
#endif

View File

@ -30,8 +30,11 @@ namespace dxvk {
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE D3D9On12::ReturnUnderlyingResource(IDirect3DResource9* resource, UINT num_sync, UINT64* signal_values, ID3D12Fence** fences) {
Logger::err("D3D9On12::GetD3D12Device: ReturnUnderlyingResource: Stub");
return E_NOINTERFACE;
if (num_sync)
Logger::err("D3D9On12::GetD3D12Device: ReturnUnderlyingResource: Stub");
m_device->FlushAndSync9On12();
return S_OK;
}
}

View File

@ -41,11 +41,6 @@ namespace dxvk {
case D3DQUERYTYPE_TIMESTAMPFREQ:
break;
case D3DQUERYTYPE_VERTEXSTATS:
m_query[0] = dxvkDevice->createGpuQuery(
VK_QUERY_TYPE_PIPELINE_STATISTICS, 0, 0);
break;
default:
throw DxvkError(str::format("D3D9Query: Unsupported query type ", m_queryType));
}
@ -246,11 +241,6 @@ namespace dxvk {
m_dataCache.TimestampFreq = GetTimestampQueryFrequency();
break;
case D3DQUERYTYPE_VERTEXSTATS:
m_dataCache.VertexStats.NumRenderedTriangles = queryData[0].statistic.iaPrimitives;
m_dataCache.VertexStats.NumExtraClippingTriangles = queryData[0].statistic.clipPrimitives;
break;
default:
break;
}
@ -276,7 +266,6 @@ namespace dxvk {
void D3D9Query::Begin(DxvkContext* ctx) {
switch (m_queryType) {
case D3DQUERYTYPE_OCCLUSION:
case D3DQUERYTYPE_VERTEXSTATS:
ctx->beginQuery(m_query[0]);
break;
@ -296,7 +285,6 @@ namespace dxvk {
ctx->writeTimestamp(m_query[0]);
break;
case D3DQUERYTYPE_VERTEXSTATS:
case D3DQUERYTYPE_OCCLUSION:
ctx->endQuery(m_query[0]);
break;
@ -314,7 +302,6 @@ namespace dxvk {
bool D3D9Query::QueryBeginnable(D3DQUERYTYPE QueryType) {
return QueryType == D3DQUERYTYPE_OCCLUSION
|| QueryType == D3DQUERYTYPE_VERTEXSTATS
|| QueryType == D3DQUERYTYPE_TIMESTAMPDISJOINT;
}
@ -338,7 +325,6 @@ namespace dxvk {
case D3DQUERYTYPE_TIMESTAMP:
case D3DQUERYTYPE_TIMESTAMPDISJOINT:
case D3DQUERYTYPE_TIMESTAMPFREQ:
case D3DQUERYTYPE_VERTEXSTATS:
return D3D_OK;
default:

View File

@ -65,6 +65,16 @@ namespace dxvk {
if (this_thread::isInModuleDetachment())
return;
{
// Locking here and in Device::GetFrontBufferData
// ensures that other threads don't accidentally access a stale pointer.
D3D9DeviceLock lock = m_parent->LockDevice();
if (m_parent->GetMostRecentlyUsedSwapchain() == this) {
m_parent->ResetMostRecentlyUsedSwapchain();
}
}
DestroyBackBuffers();
ResetWindowProc(m_window);
@ -112,6 +122,8 @@ namespace dxvk {
DWORD dwFlags) {
D3D9DeviceLock lock = m_parent->LockDevice();
m_parent->SetMostRecentlyUsedSwapchain(this);
if (unlikely(m_parent->IsDeviceLost()))
return D3DERR_DEVICELOST;
@ -382,6 +394,20 @@ namespace dxvk {
blitInfo.srcOffsets[0] = VkOffset3D{ 0, 0, 0 };
blitInfo.srcOffsets[1] = VkOffset3D{ int32_t(srcExtent.width), int32_t(srcExtent.height), 1 };
#ifdef _WIN32
if (m_presentParams.Windowed) {
// In windowed mode, GetFrontBufferData takes a screenshot of the entire screen.
// So place the copy of the front buffer at the position of the window.
POINT point = { 0, 0 };
if (ClientToScreen(m_window, &point) != 0) {
blitInfo.dstOffsets[0].x = point.x;
blitInfo.dstOffsets[0].y = point.y;
blitInfo.dstOffsets[1].x += point.x;
blitInfo.dstOffsets[1].y += point.y;
}
}
#endif
m_parent->EmitCs([
cDstImage = blittedSrc,
cDstMap = dstTexInfo->GetMapping().Swizzle,

View File

@ -87,9 +87,9 @@ namespace dxvk {
}
for (uint32_t i = 0; i < ins.dstCount; i++) {
if (ins.dst[0].type == DxbcOperandType::IndexableTemp) {
uint32_t index = ins.dst[0].idx[0].offset;
m_analysis->xRegMasks[index] |= ins.dst[0].mask;
if (ins.dst[i].type == DxbcOperandType::IndexableTemp) {
uint32_t index = ins.dst[i].idx[0].offset;
m_analysis->xRegMasks[index] |= ins.dst[i].mask;
}
}
}

View File

@ -23,7 +23,11 @@ namespace dxvk {
entry.systemValue = static_cast<DxbcSystemValue>(reader.readu32());
entry.componentType = componentTypes.at(reader.readu32());
entry.registerId = reader.readu32();
entry.componentMask = bit::extract(reader.readu32(), 0, 3);
uint32_t mask = reader.readu32();
entry.componentMask = bit::extract(mask, 0, 3);
entry.componentUsed = bit::extract(mask, 8, 11);
if (hasPrecision)
reader.readu32();

View File

@ -20,6 +20,7 @@ namespace dxvk {
uint32_t semanticIndex;
uint32_t registerId;
DxbcRegMask componentMask;
DxbcRegMask componentUsed;
DxbcScalarType componentType;
DxbcSystemValue systemValue;
uint32_t streamId;

File diff suppressed because it is too large Load Diff

View File

@ -512,6 +512,7 @@ namespace dxvk {
// Entry point description - we'll need to declare
// the function ID and all input/output variables.
uint32_t m_entryPointId = 0;
bool m_hasRawAccessChains = false;
////////////////////////////////////////////
// Inter-stage shader interface slots. Also
@ -944,19 +945,6 @@ namespace dxvk {
const DxbcRegister& operand,
const DxbcRegister& address);
///////////////////////////////
// Resource load/store methods
DxbcRegisterValue emitRawBufferLoad(
const DxbcRegister& operand,
DxbcRegisterValue elementIndex,
DxbcRegMask writeMask,
uint32_t& sparseFeedbackId);
void emitRawBufferStore(
const DxbcRegister& operand,
DxbcRegisterValue elementIndex,
DxbcRegisterValue value);
//////////////////////////
// Resource query methods
DxbcRegisterValue emitQueryBufferSize(
@ -1233,6 +1221,9 @@ namespace dxvk {
uint32_t getUavCoherence(
uint32_t registerId,
DxbcUavFlags flags);
bool ignoreInputSystemValue(
DxbcSystemValue sv) const;
///////////////////////////
// Type definition methods

View File

@ -149,6 +149,10 @@ namespace dxvk {
: m_mask((x ? 0x1 : 0) | (y ? 0x2 : 0)
| (z ? 0x4 : 0) | (w ? 0x8 : 0)) { }
uint32_t raw() const {
return m_mask;
}
bool operator [] (uint32_t id) const {
return (m_mask >> id) & 1;
}

View File

@ -17,9 +17,6 @@ namespace dxvk {
useDepthClipWorkaround
= !devFeatures.extDepthClipEnable.depthClipEnable;
useSubgroupOpsForAtomicCounters
= (devInfo.vk11.subgroupSupportedStages & VK_SHADER_STAGE_COMPUTE_BIT)
&& (devInfo.vk11.subgroupSupportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT);
VkFormatFeatureFlags2 r32Features
= device->getFormatFeatures(VK_FORMAT_R32_SFLOAT).optimal
@ -27,6 +24,7 @@ namespace dxvk {
& device->getFormatFeatures(VK_FORMAT_R32_SINT).optimal;
supportsTypedUavLoadR32 = (r32Features & VK_FORMAT_FEATURE_2_STORAGE_READ_WITHOUT_FORMAT_BIT);
supportsRawAccessChains = device->features().nvRawAccessChains.shaderRawAccessChains;
switch (device->config().useRawSsbo) {
case Tristate::Auto: minSsboAlignment = devInfo.core.properties.limits.minStorageBufferOffsetAlignment; break;

View File

@ -27,9 +27,8 @@ namespace dxvk {
/// on typed UAV loads are required
bool supportsTypedUavLoadR32 = false;
/// Use subgroup operations to reduce the number of
/// atomic operations for append/consume buffers.
bool useSubgroupOpsForAtomicCounters = false;
/// Determines whether raw access chains are supported
bool supportsRawAccessChains = false;
/// Clear thread-group shared memory to zero
bool zeroInitWorkgroupMemory = false;

View File

@ -272,7 +272,8 @@ namespace dxvk {
auto deviceProp = m_adapter->deviceProperties();
auto memoryProp = m_adapter->memoryProperties();
auto vk11 = m_adapter->devicePropertiesExt().vk11;
auto vk12 = m_adapter->devicePropertiesExt().vk12;
// Custom Vendor / Device ID
if (options->customVendorId >= 0)
deviceProp.vendorID = options->customVendorId;
@ -298,7 +299,10 @@ namespace dxvk {
fallbackDevice = 0x2487;
}
bool hideGpu = (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia) && options->hideNvidiaGpu)
bool hideNvidiaGpu = vk12.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY
? options->hideNvidiaGpu : options->hideNvkGpu;
bool hideGpu = (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Nvidia) && hideNvidiaGpu)
|| (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Amd) && options->hideAmdGpu)
|| (deviceProp.vendorID == uint16_t(DxvkGpuVendor::Intel) && options->hideIntelGpu);

View File

@ -124,13 +124,10 @@ namespace dxvk {
}
}
// If any monitors are left on the list, enable the
// fallback to always enumerate all monitors.
if ((m_monitorFallback = !monitors.empty()))
Logger::warn("DXGI: Found monitors not associated with any adapter, using fallback");
else
m_monitorFallback = m_options.useMonitorFallback;
}
@ -233,7 +230,7 @@ namespace dxvk {
descFs.Windowed = pDesc->Windowed;
IDXGISwapChain1* swapChain = nullptr;
HRESULT hr = CreateSwapChainForHwnd(
HRESULT hr = CreateSwapChainForHwndBase(
pDevice, pDesc->OutputWindow,
&desc, &descFs, nullptr,
&swapChain);
@ -247,6 +244,19 @@ namespace dxvk {
IUnknown* pDevice,
HWND hWnd,
const DXGI_SWAP_CHAIN_DESC1* pDesc,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
IDXGIOutput* pRestrictToOutput,
IDXGISwapChain1** ppSwapChain) {
return CreateSwapChainForHwndBase(
pDevice, hWnd,
pDesc, pFullscreenDesc, pRestrictToOutput,
ppSwapChain);
}
HRESULT STDMETHODCALLTYPE DxgiFactory::CreateSwapChainForHwndBase(
IUnknown* pDevice,
HWND hWnd,
const DXGI_SWAP_CHAIN_DESC1* pDesc,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
IDXGIOutput* pRestrictToOutput,
IDXGISwapChain1** ppSwapChain) {

View File

@ -200,6 +200,14 @@ namespace dxvk {
UINT m_flags;
BOOL m_monitorFallback;
HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndBase(
IUnknown* pDevice,
HWND hWnd,
const DXGI_SWAP_CHAIN_DESC1* pDesc,
const DXGI_SWAP_CHAIN_FULLSCREEN_DESC* pFullscreenDesc,
IDXGIOutput* pRestrictToOutput,
IDXGISwapChain1** ppSwapChain);
};
}

View File

@ -26,6 +26,21 @@ namespace dxvk {
return id;
}
/* First generation XeSS causes crash on proton for Intel due to missing
* Intel interface. Avoid crash by pretending to be non-Intel if the
* libxess.dll module is loaded by an application.
*/
static bool isXessUsed() {
#ifdef _WIN32
if (GetModuleHandleA("libxess") != nullptr ||
GetModuleHandleA("libxess_dx11") != nullptr)
return true;
else
return false;
#else
return false;
#endif
}
static bool isNvapiEnabled() {
return env::getEnvVar("DXVK_ENABLE_NVAPI") == "1";
@ -82,15 +97,12 @@ namespace dxvk {
// Expose Nvidia GPUs properly if NvAPI is enabled in environment
this->hideNvidiaGpu = !isNvapiEnabled();
applyTristate(this->hideNvidiaGpu, config.getOption<Tristate>("dxgi.hideNvidiaGpu", Tristate::Auto));
Tristate hideNvidiaGpuOption = config.getOption<Tristate>("dxgi.hideNvidiaGpu", Tristate::Auto);
if (hideNvidiaGpuOption == Tristate::Auto && !config.getOption<bool>("dxgi.nvapiHack", true)) {
Logger::warn("dxgi.nvapiHack is deprecated, please set dxgi.hideNvidiaGpu instead.");
hideNvidiaGpuOption = Tristate::False;
}
applyTristate(this->hideNvidiaGpu, hideNvidiaGpuOption);
// Treat NVK adapters the same as Nvidia cards on the proprietary by
// default, but provide an override in case something isn't working.
this->hideNvkGpu = this->hideNvidiaGpu;
applyTristate(this->hideNvkGpu, config.getOption<Tristate>("dxgi.hideNvkGpu", Tristate::Auto));
// Expose AMD and Intel GPU by default, unless a config override is active.
// Implement as a tristate so that we have the option to introduce similar
@ -98,15 +110,17 @@ namespace dxvk {
this->hideAmdGpu = config.getOption<Tristate>("dxgi.hideAmdGpu", Tristate::Auto) == Tristate::True;
this->hideIntelGpu = config.getOption<Tristate>("dxgi.hideIntelGpu", Tristate::Auto) == Tristate::True;
/* Force vendor ID to non-Intel ID when XeSS is in use */
if (isXessUsed()) {
Logger::info(str::format("Detected XeSS usage, hiding Intel GPU Vendor"));
this->hideIntelGpu = true;
}
this->enableHDR = config.getOption<bool>("dxgi.enableHDR", env::getEnvVar("DXVK_HDR") == "1");
if (this->enableHDR && isHDRDisallowed()) {
Logger::info("HDR was configured to be enabled, but has been force disabled as a UE4 DX11 game was detected.");
this->enableHDR = false;
}
this->useMonitorFallback = config.getOption<bool>("dxgi.useMonitorFallback", env::getEnvVar("DXVK_MONITOR_FALLBACK") == "1");
if (this->useMonitorFallback)
Logger::info("Enabled useMonitorFallback option");
}
}

View File

@ -33,9 +33,13 @@ namespace dxvk {
/// Emulate UMA
bool emulateUMA;
/// Reports Nvidia GPUs as a different vendor (usually AMD)
/// Reports Nvidia GPUs running on the proprietary driver as a different
/// vendor (usually AMD). Proton will generally disable this option.
bool hideNvidiaGpu;
/// Reports Nvidia GPUs running on NVK as a different vendor (usually AMD)
bool hideNvkGpu;
/// Reports AMD GPUs as a different vendor (usually Nvidia)
bool hideAmdGpu;
@ -45,9 +49,6 @@ namespace dxvk {
/// Enable HDR
bool enableHDR;
/// Use monitor fallback to enumerating all monitors per output
bool useMonitorFallback;
/// Sync interval. Overrides the value
/// passed to IDXGISwapChain::Present.
int32_t syncInterval;

View File

@ -32,6 +32,9 @@ namespace dxvk {
// Apply initial window mode and fullscreen state
if (!m_descFs.Windowed && FAILED(EnterFullscreenMode(nullptr)))
throw DxvkError("DXGI: Failed to set initial fullscreen state");
// Ensure that RGBA16 swap chains are scRGB if supported
UpdateColorSpace(m_desc.Format, m_colorSpace);
}
@ -300,15 +303,22 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present(UINT SyncInterval, UINT Flags) {
return Present1(SyncInterval, Flags, nullptr);
return PresentBase(SyncInterval, Flags, nullptr);
}
HRESULT STDMETHODCALLTYPE DxgiSwapChain::Present1(
UINT SyncInterval,
UINT PresentFlags,
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
return PresentBase(SyncInterval, PresentFlags, pPresentParameters);
}
HRESULT STDMETHODCALLTYPE DxgiSwapChain::PresentBase(
UINT SyncInterval,
UINT PresentFlags,
const DXGI_PRESENT_PARAMETERS* pPresentParameters) {
if (SyncInterval > 4)
return DXGI_ERROR_INVALID_CALL;
@ -398,7 +408,13 @@ namespace dxvk {
if (Format != DXGI_FORMAT_UNKNOWN)
m_desc.Format = Format;
return m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue);
HRESULT hr = m_presenter->ChangeProperties(&m_desc, pCreationNodeMask, ppPresentQueue);
if (FAILED(hr))
return hr;
UpdateColorSpace(m_desc.Format, m_colorSpace);
return hr;
}
@ -572,36 +588,31 @@ namespace dxvk {
if (!pColorSpaceSupport)
return E_INVALIDARG;
// Don't expose any color spaces other than standard
// sRGB if the enableHDR option is not set.
//
// If we ever have a use for the non-SRGB non-HDR colorspaces
// some day, we may want to revisit this.
if (ColorSpace != DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709
&& !m_factory->GetOptions()->enableHDR) {
*pColorSpaceSupport = 0;
return S_OK;
}
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
if (ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
*pColorSpaceSupport = DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT;
else
*pColorSpaceSupport = 0;
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace);
*pColorSpaceSupport = support;
return S_OK;
}
HRESULT STDMETHODCALLTYPE DxgiSwapChain::SetColorSpace1(DXGI_COLOR_SPACE_TYPE ColorSpace) {
UINT support = m_presenter->CheckColorSpaceSupport(ColorSpace);
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
if (!support)
if (!ValidateColorSpaceSupport(m_desc.Format, ColorSpace))
return E_INVALIDARG;
std::lock_guard<dxvk::mutex> lock(m_lockBuffer);
HRESULT hr = m_presenter->SetColorSpace(ColorSpace);
if (SUCCEEDED(hr)) {
// If this was a colorspace other than our current one,
// punt us into that one on the DXGI output.
m_monitorInfo->PuntColorSpace(ColorSpace);
}
// Write back color space if setting it up succeeded. This way, we preserve
// the current color space even if the swap chain temporarily switches to a
// back buffer format which does not support it.
HRESULT hr = UpdateColorSpace(m_desc.Format, ColorSpace);
if (SUCCEEDED(hr))
m_colorSpace = ColorSpace;
return hr;
}
@ -869,6 +880,7 @@ namespace dxvk {
m_monitorInfo->ReleaseMonitorData();
}
void DxgiSwapChain::UpdateGlobalHDRState() {
// Update the global HDR state if called from the legacy NVAPI
// interfaces, etc.
@ -893,4 +905,51 @@ namespace dxvk {
}
}
bool DxgiSwapChain::ValidateColorSpaceSupport(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace) {
// RGBA16 swap chains are treated as scRGB even on SDR displays,
// and regular sRGB is not exposed when this format is used.
if (Format == DXGI_FORMAT_R16G16B16A16_FLOAT)
return ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
// For everything else, we will always expose plain sRGB
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709)
return true;
// Only expose HDR10 color space if HDR option is enabled
if (ColorSpace == DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020)
return m_factory->GetOptions()->enableHDR && m_presenter->CheckColorSpaceSupport(ColorSpace);
return false;
}
HRESULT DxgiSwapChain::UpdateColorSpace(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace) {
// Don't do anything if the explicitly sepected color space
// is compatible with the back buffer format already
if (!ValidateColorSpaceSupport(Format, ColorSpace)) {
ColorSpace = Format == DXGI_FORMAT_R16G16B16A16_FLOAT
? DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709
: DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
}
// Ensure that we pick a supported color space. This is relevant for
// mapping scRGB to sRGB on SDR setups, matching Windows behaviour.
if (!m_presenter->CheckColorSpaceSupport(ColorSpace))
ColorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
HRESULT hr = m_presenter->SetColorSpace(ColorSpace);
// If this was a colorspace other than our current one,
// punt us into that one on the DXGI output.
if (SUCCEEDED(hr))
m_monitorInfo->PuntColorSpace(ColorSpace);
return hr;
}
}

View File

@ -193,6 +193,8 @@ namespace dxvk {
bool m_frameStatisticsDisjoint = true;
wsi::DxvkWindowState m_windowState;
DXGI_COLOR_SPACE_TYPE m_colorSpace = DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709;
uint32_t m_globalHDRStateSerial = 0;
HRESULT EnterFullscreenMode(
@ -223,6 +225,18 @@ namespace dxvk {
void UpdateGlobalHDRState();
bool ValidateColorSpaceSupport(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace);
HRESULT UpdateColorSpace(
DXGI_FORMAT Format,
DXGI_COLOR_SPACE_TYPE ColorSpace);
HRESULT STDMETHODCALLTYPE PresentBase(
UINT SyncInterval,
UINT PresentFlags,
const DXGI_PRESENT_PARAMETERS* pPresentParameters);
};
}

View File

@ -346,6 +346,11 @@ namespace dxvk {
enabledFeatures.vk13.synchronization2 = VK_TRUE;
enabledFeatures.vk13.dynamicRendering = VK_TRUE;
// Maintenance4 may cause performance problems on amdvlk in some cases
if (m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_OPEN_SOURCE
&& m_deviceInfo.vk12.driverID != VK_DRIVER_ID_AMD_PROPRIETARY)
enabledFeatures.vk13.maintenance4 = VK_TRUE;
// We expose depth clip rather than depth clamp to client APIs
enabledFeatures.extDepthClipEnable.depthClipEnable =
m_deviceFeatures.extDepthClipEnable.depthClipEnable;
@ -415,6 +420,10 @@ namespace dxvk {
enabledFeatures.khrPresentWait.presentWait = VK_FALSE;
}
// Enable raw access chains for shader backends
enabledFeatures.nvRawAccessChains.shaderRawAccessChains =
m_deviceFeatures.nvRawAccessChains.shaderRawAccessChains;
// Create pNext chain for additional device features
initFeatureChain(enabledFeatures, devExtensions, instance->extensions());
@ -606,6 +615,10 @@ namespace dxvk {
enabledFeatures.khrPresentWait = *reinterpret_cast<const VkPhysicalDevicePresentWaitFeaturesKHR*>(f);
break;
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV:
enabledFeatures.nvRawAccessChains = *reinterpret_cast<const VkPhysicalDeviceRawAccessChainsFeaturesNV*>(f);
break;
default:
// Ignore any unknown feature structs
break;
@ -927,6 +940,11 @@ namespace dxvk {
m_deviceFeatures.khrPresentWait.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrPresentWait);
}
if (m_deviceExtensions.supports(VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME)) {
m_deviceFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
m_deviceFeatures.nvRawAccessChains.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.nvRawAccessChains);
}
if (m_deviceExtensions.supports(VK_NVX_BINARY_IMPORT_EXTENSION_NAME))
m_deviceFeatures.nvxBinaryImport = VK_TRUE;
@ -994,6 +1012,7 @@ namespace dxvk {
&devExtensions.khrPresentWait,
&devExtensions.khrSwapchain,
&devExtensions.khrWin32KeyedMutex,
&devExtensions.nvRawAccessChains,
&devExtensions.nvxBinaryImport,
&devExtensions.nvxImageViewHandle,
}};
@ -1133,6 +1152,11 @@ namespace dxvk {
enabledFeatures.khrPresentWait.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrPresentWait);
}
if (devExtensions.nvRawAccessChains) {
enabledFeatures.nvRawAccessChains.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAW_ACCESS_CHAINS_FEATURES_NV;
enabledFeatures.nvRawAccessChains.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.nvRawAccessChains);
}
if (devExtensions.nvxBinaryImport)
enabledFeatures.nvxBinaryImport = VK_TRUE;
@ -1279,6 +1303,8 @@ namespace dxvk {
"\n presentId : ", features.khrPresentId.presentId ? "1" : "0",
"\n", VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
"\n presentWait : ", features.khrPresentWait.presentWait ? "1" : "0",
"\n", VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME,
"\n shaderRawAccessChains : ", features.nvRawAccessChains.shaderRawAccessChains ? "1" : "0",
"\n", VK_NVX_BINARY_IMPORT_EXTENSION_NAME,
"\n extension supported : ", features.nvxBinaryImport ? "1" : "0",
"\n", VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME,

View File

@ -1997,7 +1997,7 @@ namespace dxvk {
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_LOAD;
depthOp.loadLayout = imageView->imageInfo().layout;
depthOp.storeLayout = imageView->imageInfo().layout;
if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT)
colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT)
@ -2010,7 +2010,7 @@ namespace dxvk {
if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR;
else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT)
else if (discardAspects & VK_IMAGE_ASPECT_STENCIL_BIT)
depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
if (attachmentIndex >= 0 && !m_state.om.framebufferInfo.isWritable(attachmentIndex, clearAspects | discardAspects)) {
@ -2041,6 +2041,8 @@ namespace dxvk {
}
if (attachmentIndex < 0) {
bool hasViewFormatMismatch = imageView->info().format != imageView->imageInfo().format;
if (m_execBarriers.isImageDirty(imageView->image(), imageView->imageSubresources(), DxvkAccess::Write))
m_execBarriers.recordCommands(m_cmd);
@ -2075,6 +2077,11 @@ namespace dxvk {
attachmentInfo.loadOp = colorOp.loadOp;
// We can't use LOAD_OP_CLEAR if the view format does not match the
// underlying image format, so just discard here and use clear later.
if (hasViewFormatMismatch && attachmentInfo.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &attachmentInfo;
@ -2110,6 +2117,20 @@ namespace dxvk {
}
m_cmd->cmdBeginRendering(&renderingInfo);
if (hasViewFormatMismatch) {
VkClearAttachment clearInfo = { };
clearInfo.aspectMask = imageView->info().aspect;
clearInfo.clearValue = clearValue;
VkClearRect clearRect = { };
clearRect.rect.extent.width = extent.width;
clearRect.rect.extent.height = extent.height;
clearRect.layerCount = imageView->info().numLayers;
m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect);
}
m_cmd->cmdEndRendering();
m_execBarriers.accessImage(
@ -3563,69 +3584,90 @@ namespace dxvk {
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkExtent3D extent) {
VkFormat viewFormat = m_common->metaCopy().getCopyDestinationFormat(
dstSubresource.aspectMask,
srcSubresource.aspectMask,
srcImage->info().format);
DxvkMetaCopyFormats viewFormats = m_common->metaCopy().getFormats(
dstImage->info().format, dstSubresource.aspectMask,
srcImage->info().format, srcSubresource.aspectMask);
if (!viewFormat) {
Logger::err("DxvkContext: copyImageFb: Unsupported format");
return;
}
// Usually we should be able to draw directly to the destination image,
// but in some cases this might not be possible, e.g. if when copying
// from something like D32_SFLOAT to RGBA8_UNORM. In those situations,
// create a temporary image to draw to, and then copy to the actual
// destination image using a regular Vulkan transfer function.
bool useDirectCopy = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
&& (dstImage->isViewCompatible(viewFormat));
bool dstIsCompatible = (dstImage->info().usage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT))
&& (dstImage->isViewCompatible(viewFormats.dstFormat));
bool srcIsCompatible = (srcImage->info().usage & (VK_IMAGE_USAGE_SAMPLED_BIT))
&& (srcImage->isViewCompatible(viewFormats.srcFormat));
if (useDirectCopy) {
if (dstIsCompatible && srcIsCompatible) {
this->copyImageFbDirect(
dstImage, dstSubresource, dstOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);
} else {
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
} else if (dstIsCompatible || srcIsCompatible) {
DxvkImageCreateInfo imageInfo = dstImage->info();
imageInfo.format = viewFormat;
imageInfo.flags = 0;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.extent = extent;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.mipLevels = 1;
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
imageInfo.viewFormatCount = 0;
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
} else {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
if (!dstIsCompatible) {
imageInfo.format = viewFormats.dstFormat;
imageInfo.numLayers = dstSubresource.layerCount;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_READ_BIT;
if (dstImage->formatInfo()->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
imageInfo.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
imageInfo.access |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
} else {
imageInfo.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.stages |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
| VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
imageInfo.access |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
} else /* if (!srcIsCompatible) */ {
imageInfo.format = viewFormats.srcFormat;
imageInfo.numLayers = srcSubresource.layerCount;
imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageInfo.layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageInfo.stages = VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
imageInfo.access = VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_READ_BIT;
}
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
Rc<DxvkImage> tmpImage = m_device->createImage(imageInfo, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VkImageSubresourceLayers tmpSubresource = dstSubresource;
VkImageSubresourceLayers tmpSubresource = { };
tmpSubresource.aspectMask = tmpImage->formatInfo()->aspectMask;
tmpSubresource.mipLevel = 0;
tmpSubresource.baseArrayLayer = 0;
tmpSubresource.layerCount = imageInfo.numLayers;
VkOffset3D tmpOffset = { 0, 0, 0 };
this->copyImageFbDirect(
tmpImage, tmpSubresource, tmpOffset, viewFormat,
srcImage, srcSubresource, srcOffset, extent);
if (!dstIsCompatible) {
this->copyImageFbDirect(
tmpImage, tmpSubresource, tmpOffset, viewFormats.dstFormat,
srcImage, srcSubresource, srcOffset, viewFormats.srcFormat, extent);
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset, extent);
this->copyImageHw(
dstImage, dstSubresource, dstOffset,
tmpImage, tmpSubresource, tmpOffset, extent);
} else /* if (!srcIsCompatible) */ {
this->copyImageHw(
tmpImage, tmpSubresource, tmpOffset,
srcImage, srcSubresource, srcOffset, extent);
this->copyImageFbDirect(
dstImage, dstSubresource, dstOffset, viewFormats.dstFormat,
tmpImage, tmpSubresource, tmpOffset, viewFormats.srcFormat, extent);
}
} else {
Logger::err(str::format("DxvkContext: copyImageFb: Unsupported operation:\n"
" srcFormat = ", srcImage->info().format, " (aspect ", srcSubresource.aspectMask, ")\n",
" dstFormat = ", dstImage->info().format, " (aspect ", dstSubresource.aspectMask, ")"));
}
}
@ -3638,6 +3680,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent) {
this->invalidateState();
@ -3701,8 +3744,6 @@ namespace dxvk {
m_execAcquires.recordCommands(m_cmd);
// Create source and destination image views
VkFormat srcFormat = srcImage->info().format;
Rc<DxvkMetaCopyViews> views = new DxvkMetaCopyViews(m_device->vkd(),
dstImage, dstSubresource, dstFormat,
srcImage, srcSubresource, srcFormat);
@ -4721,8 +4762,10 @@ namespace dxvk {
this->renderPassEmitPostBarriers(framebufferInfo, ops);
uint32_t colorInfoCount = 0;
uint32_t lateClearCount = 0;
std::array<VkRenderingAttachmentInfo, MaxNumRenderTargets> colorInfos;
std::array<VkClearAttachment, MaxNumRenderTargets> lateClears;
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
const auto& colorTarget = framebufferInfo.getColorTarget(i);
@ -4734,9 +4777,21 @@ namespace dxvk {
colorInfos[i].loadOp = ops.colorOps[i].loadOp;
colorInfos[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR)
if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
colorInfos[i].clearValue.color = ops.colorOps[i].clearValue;
// We can't use LOAD_OP_CLEAR if the view format does not match the
// underlying image format, so just discard here and use clear later.
if (colorTarget.view->info().format != colorTarget.view->imageInfo().format) {
colorInfos[i].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
auto& clear = lateClears[lateClearCount++];
clear.colorAttachment = i;
clear.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
clear.clearValue.color = ops.colorOps[i].clearValue;
}
}
colorInfoCount = i + 1;
}
}
@ -4784,6 +4839,15 @@ namespace dxvk {
m_cmd->cmdBeginRendering(&renderingInfo);
if (lateClearCount) {
VkClearRect clearRect = { };
clearRect.rect.extent.width = fbSize.width;
clearRect.rect.extent.height = fbSize.height;
clearRect.layerCount = fbSize.layers;
m_cmd->cmdClearAttachments(lateClearCount, lateClears.data(), 1, &clearRect);
}
for (uint32_t i = 0; i < framebufferInfo.numAttachments(); i++) {
m_cmd->trackResource<DxvkAccess::None> (framebufferInfo.getAttachment(i).view);
m_cmd->trackResource<DxvkAccess::Write>(framebufferInfo.getAttachment(i).view->image());
@ -5594,11 +5658,13 @@ namespace dxvk {
auto bufferInfo = m_state.vi.indexBuffer.getDescriptor();
if (m_features.test(DxvkContextFeature::IndexBufferRobustness)) {
VkDeviceSize align = m_state.vi.indexType == VK_INDEX_TYPE_UINT16 ? 2 : 4;
VkDeviceSize range = bufferInfo.buffer.range & ~(align - 1);
m_cmd->cmdBindIndexBuffer2(
bufferInfo.buffer.buffer,
bufferInfo.buffer.offset,
bufferInfo.buffer.range,
m_state.vi.indexType);
range, m_state.vi.indexType);
} else {
m_cmd->cmdBindIndexBuffer(
bufferInfo.buffer.buffer,

View File

@ -1506,6 +1506,7 @@ namespace dxvk {
const Rc<DxvkImage>& srcImage,
VkImageSubresourceLayers srcSubresource,
VkOffset3D srcOffset,
VkFormat srcFormat,
VkExtent3D extent);
bool copyImageClear(

View File

@ -72,7 +72,7 @@ namespace dxvk {
// memory bloat. This may be necessary for off-screen
// rendering applications, or in situations where games
// pre-render a lot of images without presenting in between.
return m_descriptorPools.size() >= 8;
return m_descriptorPools.size() > MaxDesiredPoolCount;
}
@ -100,29 +100,25 @@ namespace dxvk {
void DxvkDescriptorPool::reset() {
// As a heuristic to save memory, check how many descriptors
// have actively been used in the past couple of submissions.
bool isLowUsageFrame = false;
// As a heuristic to save memory, check how many descriptor
// sets were actually being used in past submissions.
size_t poolCount = m_descriptorPools.size();
bool needsReset = poolCount > MaxDesiredPoolCount;
if (poolCount > 1 || m_setsAllocated > m_manager->getMaxSetCount() / 2) {
double factor = std::max(11.0 / 3.0 - double(poolCount) / 3.0, 1.0);
isLowUsageFrame = double(m_setsUsed) * factor < double(m_setsAllocated);
needsReset = double(m_setsUsed) * factor < double(m_setsAllocated);
}
m_lowUsageFrames = isLowUsageFrame
? m_lowUsageFrames + 1
: 0;
m_setsUsed = 0;
if (m_lowUsageFrames < 16) {
if (!needsReset) {
for (auto& entry : m_setLists)
entry.second.reset();
} else {
// If most sets are no longer being used, reset and destroy
// descriptor pools and reset all lookup tables in order to
// accomodate more descriptors of different layouts.
// If most sets are no longer needed, reset and destroy
// descriptor pools and reset all lookup tables in order
// to accomodate more descriptors of different layouts.
for (auto pool : m_descriptorPools)
m_manager->recycleVulkanDescriptorPool(pool);
@ -131,7 +127,6 @@ namespace dxvk {
m_setMaps.clear();
m_setsAllocated = 0;
m_lowUsageFrames = 0;
}
m_cachedEntry = { nullptr, nullptr };

View File

@ -80,7 +80,7 @@ namespace dxvk {
* to be updated.
*/
class DxvkDescriptorPool : public RcObject {
constexpr static uint32_t MaxDesiredPoolCount = 2;
public:
DxvkDescriptorPool(
@ -155,8 +155,6 @@ namespace dxvk {
uint32_t m_prevSetsAllocated = 0;
uint32_t m_lowUsageFrames = 0;
DxvkDescriptorSetMap* getSetMapCached(
const DxvkBindingLayoutObjects* layout);

View File

@ -68,6 +68,7 @@ namespace dxvk {
VkPhysicalDeviceMaintenance5FeaturesKHR khrMaintenance5;
VkPhysicalDevicePresentIdFeaturesKHR khrPresentId;
VkPhysicalDevicePresentWaitFeaturesKHR khrPresentWait;
VkPhysicalDeviceRawAccessChainsFeaturesNV nvRawAccessChains;
VkBool32 nvxBinaryImport;
VkBool32 nvxImageViewHandle;
VkBool32 khrWin32KeyedMutex;

View File

@ -325,6 +325,7 @@ namespace dxvk {
DxvkExt khrPresentWait = { VK_KHR_PRESENT_WAIT_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
DxvkExt khrWin32KeyedMutex = { VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt nvRawAccessChains = { VK_NV_RAW_ACCESS_CHAINS_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt nvxBinaryImport = { VK_NVX_BINARY_IMPORT_EXTENSION_NAME, DxvkExtMode::Disabled };
DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled };
};

View File

@ -177,7 +177,7 @@ namespace dxvk {
appInfo.pApplicationName = appName.c_str();
appInfo.applicationVersion = flags.raw();
appInfo.pEngineName = "DXVK";
appInfo.engineVersion = VK_MAKE_VERSION(2, 3, 0);
appInfo.engineVersion = VK_MAKE_VERSION(2, 3, 1);
appInfo.apiVersion = VK_MAKE_VERSION(1, 3, 0);
VkInstanceCreateInfo info = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };

View File

@ -188,7 +188,6 @@ namespace dxvk {
for (uint32_t i = 0; i < m_memProps.memoryHeapCount; i++) {
m_memHeaps[i].properties = m_memProps.memoryHeaps[i];
m_memHeaps[i].stats = DxvkMemoryStats { 0, 0 };
m_memHeaps[i].budget = 0;
}
for (uint32_t i = 0; i < m_memProps.memoryTypeCount; i++) {
@ -385,9 +384,6 @@ namespace dxvk {
bool useMemoryPriority = (info.flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
&& (m_device->features().extMemoryPriority.memoryPriority);
if (type->heap->budget && type->heap->stats.memoryAllocated + size > type->heap->budget)
return DxvkDeviceMemory();
float priority = 0.0f;
if (hints.test(DxvkMemoryFlag::GpuReadable))
@ -547,11 +543,7 @@ namespace dxvk {
bool DxvkMemoryAllocator::shouldFreeEmptyChunks(
const DxvkMemoryHeap* heap,
VkDeviceSize allocationSize) const {
VkDeviceSize budget = heap->budget;
if (!budget)
budget = (heap->properties.size * 4) / 5;
VkDeviceSize budget = (heap->properties.size * 4) / 5;
return heap->stats.memoryAllocated + allocationSize > budget;
}

View File

@ -66,7 +66,6 @@ namespace dxvk {
struct DxvkMemoryHeap {
VkMemoryHeap properties;
DxvkMemoryStats stats;
VkDeviceSize budget;
};

View File

@ -9,9 +9,6 @@
#include <dxvk_copy_color_1d.h>
#include <dxvk_copy_color_2d.h>
#include <dxvk_copy_color_ms.h>
#include <dxvk_copy_depth_1d.h>
#include <dxvk_copy_depth_2d.h>
#include <dxvk_copy_depth_ms.h>
#include <dxvk_copy_depth_stencil_1d.h>
#include <dxvk_copy_depth_stencil_2d.h>
#include <dxvk_copy_depth_stencil_ms.h>
@ -84,11 +81,7 @@ namespace dxvk {
m_color {
createShaderModule(dxvk_copy_color_1d),
createShaderModule(dxvk_copy_color_2d),
createShaderModule(dxvk_copy_color_ms) },
m_depth {
createShaderModule(dxvk_copy_depth_1d),
createShaderModule(dxvk_copy_depth_2d),
createShaderModule(dxvk_copy_depth_ms) } {
createShaderModule(dxvk_copy_color_ms) } {
if (device->features().vk12.shaderOutputLayer) {
m_shaderVert = createShaderModule(dxvk_fullscreen_layer_vert);
} else {
@ -119,9 +112,6 @@ namespace dxvk {
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.fragMs, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.frag2D, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depthStencil.frag1D, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.fragMs, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.frag2D, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_depth.frag1D, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.fragMs, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag2D, nullptr);
m_vkd->vkDestroyShaderModule(m_vkd->device(), m_color.frag1D, nullptr);
@ -130,32 +120,29 @@ namespace dxvk {
}
VkFormat DxvkMetaCopyObjects::getCopyDestinationFormat(
DxvkMetaCopyFormats DxvkMetaCopyObjects::getFormats(
VkFormat dstFormat,
VkImageAspectFlags dstAspect,
VkImageAspectFlags srcAspect,
VkFormat srcFormat) const {
if (srcAspect == dstAspect)
return srcFormat;
if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT
&& srcAspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
VkFormat srcFormat,
VkImageAspectFlags srcAspect) const {
if (dstAspect == srcAspect)
return { dstFormat, srcFormat };
if (dstAspect == VK_IMAGE_ASPECT_COLOR_BIT && srcAspect == VK_IMAGE_ASPECT_DEPTH_BIT) {
switch (srcFormat) {
case VK_FORMAT_D16_UNORM: return VK_FORMAT_R16_UNORM;
case VK_FORMAT_D32_SFLOAT: return VK_FORMAT_R32_SFLOAT;
default: return VK_FORMAT_UNDEFINED;
case VK_FORMAT_D16_UNORM: return { VK_FORMAT_R16_UNORM, VK_FORMAT_D16_UNORM };
case VK_FORMAT_D32_SFLOAT: return { VK_FORMAT_R32_SFLOAT, VK_FORMAT_D32_SFLOAT };
default: return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED };
}
} else if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT && srcAspect == VK_IMAGE_ASPECT_COLOR_BIT) {
switch (dstFormat) {
case VK_FORMAT_D16_UNORM: return { VK_FORMAT_D16_UNORM, VK_FORMAT_R16_UNORM };
case VK_FORMAT_D32_SFLOAT: return { VK_FORMAT_D32_SFLOAT, VK_FORMAT_R32_SFLOAT };
default: return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED };
}
}
if (dstAspect == VK_IMAGE_ASPECT_DEPTH_BIT
&& srcAspect == VK_IMAGE_ASPECT_COLOR_BIT) {
switch (srcFormat) {
case VK_FORMAT_R16_UNORM: return VK_FORMAT_D16_UNORM;
case VK_FORMAT_R32_SFLOAT: return VK_FORMAT_D32_SFLOAT;
default: return VK_FORMAT_UNDEFINED;
}
}
return VK_FORMAT_UNDEFINED;
return { VK_FORMAT_UNDEFINED, VK_FORMAT_UNDEFINED };
}
@ -313,7 +300,7 @@ namespace dxvk {
std::array<std::pair<const FragShaders*, VkImageAspectFlags>, 3> shaderSets = {{
{ &m_color, VK_IMAGE_ASPECT_COLOR_BIT },
{ &m_depth, VK_IMAGE_ASPECT_DEPTH_BIT },
{ &m_color, VK_IMAGE_ASPECT_DEPTH_BIT },
{ &m_depthStencil, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT },
}};

View File

@ -25,6 +25,14 @@ namespace dxvk {
VkExtent2D srcSize;
};
/**
* \brief Pair of view formats for copy operation
*/
struct DxvkMetaCopyFormats {
VkFormat dstFormat;
VkFormat srcFormat;
};
/**
* \brief Copy pipeline
*
@ -122,13 +130,17 @@ namespace dxvk {
* Returns the color format that we need to use
* as the destination image view format in case
* of depth to color image copies.
* \param [in] format Depth format
* \param [in] dstFormat Destination image format
* \param [in] dstAspect Destination aspect mask
* \param [in] srcFormat Source image format
* \param [in] srcAspect Source aspect mask
* \returns Corresponding color format
*/
VkFormat getCopyDestinationFormat(
DxvkMetaCopyFormats getFormats(
VkFormat dstFormat,
VkImageAspectFlags dstAspect,
VkImageAspectFlags srcAspect,
VkFormat srcFormat) const;
VkFormat srcFormat,
VkImageAspectFlags srcAspect) const;
/**
* \brief Creates pipeline for meta copy operation

View File

@ -382,6 +382,9 @@ namespace dxvk {
bool Presenter::supportsColorSpace(VkColorSpaceKHR colorspace) {
if (!m_surface)
return false;
std::vector<VkSurfaceFormatKHR> surfaceFormats;
getSupportedFormats(surfaceFormats, VK_FULL_SCREEN_EXCLUSIVE_DEFAULT_EXT);

View File

@ -20,9 +20,6 @@ dxvk_shaders = files([
'shaders/dxvk_copy_color_1d.frag',
'shaders/dxvk_copy_color_2d.frag',
'shaders/dxvk_copy_color_ms.frag',
'shaders/dxvk_copy_depth_1d.frag',
'shaders/dxvk_copy_depth_2d.frag',
'shaders/dxvk_copy_depth_ms.frag',
'shaders/dxvk_copy_depth_stencil_1d.frag',
'shaders/dxvk_copy_depth_stencil_2d.frag',
'shaders/dxvk_copy_depth_stencil_ms.frag',

View File

@ -13,6 +13,8 @@ uniform u_info_t {
} u_info;
void main() {
o_color = texelFetch(s_image,
vec4 color = texelFetch(s_image,
ivec2(gl_FragCoord.x + u_info.offset.x, gl_Layer), 0);
}
o_color = color;
gl_FragDepth = color.r;
}

View File

@ -13,6 +13,8 @@ uniform u_info_t {
} u_info;
void main() {
o_color = texelFetch(s_image,
vec4 color = texelFetch(s_image,
ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer), 0);
}
o_color = color;
gl_FragDepth = color.r;
}

View File

@ -13,7 +13,9 @@ uniform u_info_t {
} u_info;
void main() {
o_color = texelFetch(s_image,
vec4 color = texelFetch(s_image,
ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer),
gl_SampleID);
}
o_color = color;
gl_FragDepth = color.r;
}

View File

@ -1,16 +0,0 @@
#version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0)
uniform texture1DArray s_image;
layout(push_constant)
uniform u_info_t {
ivec2 offset;
} u_info;
void main() {
gl_FragDepth = texelFetch(s_image,
ivec2(gl_FragCoord.x + u_info.offset.x, gl_Layer), 0).r;
}

View File

@ -1,16 +0,0 @@
#version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0)
uniform texture2DArray s_image;
layout(push_constant)
uniform u_info_t {
ivec2 offset;
} u_info;
void main() {
gl_FragDepth = texelFetch(s_image,
ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer), 0).r;
}

View File

@ -1,17 +0,0 @@
#version 450
#extension GL_EXT_samplerless_texture_functions : require
layout(set = 0, binding = 0)
uniform texture2DMSArray s_image;
layout(push_constant)
uniform u_info_t {
ivec2 offset;
} u_info;
void main() {
gl_FragDepth = texelFetch(s_image,
ivec3(gl_FragCoord.xy + u_info.offset, gl_Layer),
gl_SampleID).r;
}

View File

@ -470,6 +470,13 @@ namespace dxvk {
}
uint32_t SpirvModule::constNull(
uint32_t typeId) {
return this->defConst(spv::OpConstantNull,
typeId, 0, nullptr);
}
uint32_t SpirvModule::lateConst32(
uint32_t typeId) {
uint32_t resultId = this->allocateId();
@ -2697,6 +2704,30 @@ namespace dxvk {
}
uint32_t SpirvModule::opRawAccessChain(
uint32_t resultType,
uint32_t base,
uint32_t stride,
uint32_t index,
uint32_t offset,
uint32_t operand) {
uint32_t resultId = this->allocateId();
m_code.putIns (spv::OpRawAccessChainNV, operand ? 8 : 7);
m_code.putWord(resultType);
m_code.putWord(resultId);
m_code.putWord(base);
m_code.putWord(stride);
m_code.putWord(index);
m_code.putWord(offset);
if (operand)
m_code.putWord(operand);
return resultId;
}
uint32_t SpirvModule::opReflect(
uint32_t resultType,
uint32_t incident,

View File

@ -217,6 +217,9 @@ namespace dxvk {
uint32_t constUndef(
uint32_t typeId);
uint32_t constNull(
uint32_t typeId);
uint32_t lateConst32(
uint32_t typeId);
@ -951,6 +954,14 @@ namespace dxvk {
uint32_t resultType,
uint32_t operand);
uint32_t opRawAccessChain(
uint32_t resultType,
uint32_t base,
uint32_t stride,
uint32_t index,
uint32_t offset,
uint32_t operand);
uint32_t opReflect(
uint32_t resultType,
uint32_t incident,

View File

@ -13,7 +13,10 @@
namespace dxvk {
const static std::vector<std::pair<const char*, Config>> g_appDefaults = {{
using ProfileList = std::vector<std::pair<const char*, Config>>;
const static ProfileList g_profiles = {{
/* Assassin's Creed Syndicate: amdags issues */
{ R"(\\ACS\.exe$)", {{
{ "dxgi.customVendorId", "10de" },
@ -26,10 +29,6 @@ namespace dxvk {
* when running on AMD hardware */
{ R"(\\EliteDangerous64\.exe$)", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* The Vanishing of Ethan Carter Redux */
{ R"(\\EthanCarter-Win64-Shipping\.exe$)", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* EVE Online: Needs this to expose D3D12 *
* otherwise D3D12 option on launcher is *
@ -126,8 +125,6 @@ namespace dxvk {
}} },
/* NieR Replicant */
{ R"(\\NieR Replicant ver\.1\.22474487139\.exe)", {{
{ "dxgi.syncInterval", "1" },
{ "dxgi.maxFrameRate", "60" },
{ "d3d11.cachedDynamicResources", "vi" },
}} },
/* SteamVR performance test */
@ -234,11 +231,6 @@ namespace dxvk {
{ R"(\\nioh2\.exe$)", {{
{ "dxgi.deferSurfaceCreation", "True" },
}} },
/* DIRT 5 - uses amd_ags_x64.dll when it *
* detects an AMD GPU */
{ R"(\\DIRT5\.exe$)", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* Crazy Machines 3 - crashes on long device *
* descriptions */
{ R"(\\cm3\.exe$)", {{
@ -340,11 +332,6 @@ namespace dxvk {
{ R"(\\SonicFrontiers\.exe$)", {{
{ "dxgi.maxFrameLatency", "1" },
}} },
/* TRAHA Global *
* Shadow issues when it sees AMD/Nvidia */
{ R"(\\RapaNui-Win64-Shipping\.exe$)", {{
{ "dxgi.customVendorId", "8086" },
}} },
/* SpellForce 3 Reforced & expansions *
* Greatly improves CPU bound performance */
{ R"(\\SF3ClientFinal\.exe$)", {{
@ -420,20 +407,18 @@ namespace dxvk {
{ R"(\\RidersRepublic(_BE)?\.exe$)", {{
{ "dxgi.hideAmdGpu", "True" },
}} },
/* HoloCure - Save the Fans!
Same as Cyberpunk 2077 */
{ R"(\\HoloCure\.exe$)", {{
{ "dxgi.useMonitorFallback", "True" },
}} },
/* Kenshi *
* Helps CPU bound performance */
{ R"(\\kenshi_x64\.exe$)", {{
{ "d3d11.cachedDynamicResources", "v" },
}} },
/* Granblue Relink: Spams pixel shader UAVs *
* like crazy, much like God of War */
* and assumes that AMD GPUs do not expose *
* native command lists for AGS usage */
{ R"(\\granblue_fantasy_relink\.exe$)", {{
{ "d3d11.ignoreGraphicsBarriers", "True" },
{ "d3d11.ignoreGraphicsBarriers", "True" },
{ "d3d11.exposeDriverCommandLists", "False" },
{ "dxgi.hideNvidiaGpu", "False" },
}} },
/**********************************************/
@ -811,6 +796,7 @@ namespace dxvk {
* Black textures */
{ R"(\\eldorado\.exe$)", {{
{ "d3d9.floatEmulation", "Strict" },
{ "d3d9.allowDirectBufferMapping", "False" },
}} },
/* Injustice: Gods Among Us *
* Locks a buffer that's still in use */
@ -867,10 +853,10 @@ namespace dxvk {
{ R"(\\UK Truck Simulator\\bin\\win_x86\\game\.exe$)", {{
{ "d3d9.floatEmulation", "Strict" },
}} },
/* Supreme Ruler Ultimate *
/* d3d9 Supreme Ruler games *
* Leaks a StateBlock leading *
* to Reset calls failing */
{ R"(\\SupremeRulerUltimate\.exe$)", {{
{ R"(\\SupremeRuler(Ultimate|GreatWar|1936|CW)\.exe$)", {{
{ "d3d9.countLosableResources", "False" },
}} },
/* Operation Flashpoint: Red River *
@ -878,6 +864,16 @@ namespace dxvk {
{ R"(\\RedRiver\.exe$)", {{
{ "d3d9.floatEmulation", "Strict" },
}} },
/* Dark Void - Crashes above 60fps in places */
{ R"(\\ShippingPC-SkyGame\.exe$)", {{
{ "d3d9.maxFrameRate", "60" },
}} },
/* 9th Dawn II *
* OpenGL game that also spins up d3d9 *
* Black screens without config */
{ R"(\\ninthdawnii\.exe$)", {{
{ "d3d9.deferSurfaceCreation", "True" },
}} },
/**********************************************/
@ -902,17 +898,6 @@ namespace dxvk {
{ R"(\\RiftApart\.exe$)", {{
{ "dxgi.hideNvidiaGpu", "False" },
}} },
/* CP2077 enumerates display outputs each frame.
* Avoid using QueryDisplayConfig to avoid
* performance degradation until the
* optimization of that function is in Proton. */
{ R"(\\Cyberpunk2077\.exe$)", {{
{ "dxgi.useMonitorFallback", "True" },
}} },
/* Hitman 3 - Ray Tracing */
{ R"(\\HITMAN3\.exe$)", {{
{ "dxgi.hideNvidiaGpu", "False" },
}} },
/* Metro Exodus Enhanced Edition picks GPU adapters
* by available VRAM, which causes issues on some
* systems with integrated graphics. */
@ -927,6 +912,28 @@ namespace dxvk {
}};
const static ProfileList g_deckProfiles = {{
/* Fallout 4: Defaults to 45 FPS on OLED, but also breaks above 60 FPS */
{ R"(\\Fallout4\.exe$)", {{
{ "dxgi.syncInterval", "1" },
{ "dxgi.maxFrameRate", "60" },
}} },
}};
const Config* findProfile(const ProfileList& profiles, const std::string& appName) {
auto appConfig = std::find_if(profiles.begin(), profiles.end(),
[&appName] (const std::pair<const char*, Config>& pair) {
std::regex expr(pair.first, std::regex::extended | std::regex::icase);
return std::regex_search(appName, expr);
});
return appConfig != profiles.end()
? &appConfig->second
: nullptr;
}
static bool isWhitespace(char ch) {
return ch == ' ' || ch == '\x9' || ch == '\r';
}
@ -1176,20 +1183,22 @@ namespace dxvk {
Config Config::getAppConfig(const std::string& appName) {
auto appConfig = std::find_if(g_appDefaults.begin(), g_appDefaults.end(),
[&appName] (const std::pair<const char*, Config>& pair) {
std::regex expr(pair.first, std::regex::extended | std::regex::icase);
return std::regex_search(appName, expr);
});
const Config* config = nullptr;
if (appConfig != g_appDefaults.end()) {
if (env::getEnvVar("SteamDeck") == "1")
config = findProfile(g_deckProfiles, appName);
if (!config)
config = findProfile(g_profiles, appName);
if (config) {
// Inform the user that we loaded a default config
Logger::info(str::format("Found built-in config:"));
for (auto& pair : appConfig->second.m_options)
for (auto& pair : config->m_options)
Logger::info(str::format(" ", pair.first, " = ", pair.second));
return appConfig->second;
return *config;
}
return Config();

View File

@ -1,11 +1,12 @@
#pragma once
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86) || defined(__e2k__)
#if (defined(__x86_64__) && !defined(__arm64ec__)) || (defined(_M_X64) && !defined(_M_ARM64EC)) \
|| defined(__i386__) || defined(_M_IX86) || defined(__e2k__)
#define DXVK_ARCH_X86
#if defined(__x86_64__) || defined(_M_X64) || defined(__e2k__)
#define DXVK_ARCH_X86_64
#endif
#elif defined(__aarch64__) || defined(_M_ARM64)
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC)
#define DXVK_ARCH_ARM64
#else
#error "Unknown CPU Architecture"