mirror of https://github.com/doitsujin/dxvk
Compare commits
66 Commits
5a5fe29a45
...
f57f084bda
Author | SHA1 | Date |
---|---|---|
Rémi Bernon | f57f084bda | |
Philip Rebohle | 462165da19 | |
Philip Rebohle | 3f27a0ee58 | |
Katharine Chui | aac3396671 | |
Katharine Chui | 92a43ebf65 | |
Blisto91 | 8ba5256dc7 | |
Philip Rebohle | 2b70ba8f77 | |
Philip Rebohle | 9c66c4bf1d | |
Philip Rebohle | 00872e9e4f | |
Philip Rebohle | 35157357dd | |
Philip Rebohle | 617ebf4e05 | |
Philip Rebohle | c2489d5a45 | |
Philip Rebohle | 6ef98c613f | |
Philip Rebohle | 7441137a33 | |
WinterSnowfall | 571948cfc0 | |
Martino Fontana | 133f0794bc | |
Philip Rebohle | 44695f9311 | |
Casey Bowman | 49e9ea5f5a | |
Blisto91 | 198bd3a4b8 | |
Philip Rebohle | f06c646315 | |
Philip Rebohle | 855b2746b6 | |
Blisto91 | 28c7c09bf5 | |
Philip Rebohle | 2742486540 | |
Philip Rebohle | 037d0fa1ad | |
Philip Rebohle | cbf51a7a25 | |
Philip Rebohle | 70e34dc31c | |
Philip Rebohle | c5aeb0f87a | |
Philip Rebohle | a163082770 | |
Blisto91 | 2e1a19c7fd | |
Joshua Ashton | 0beb18ef73 | |
Joshua Ashton | ef4428ab8c | |
Philip Rebohle | 1085ba713e | |
Philip Rebohle | e857b09432 | |
Kaitlyn | 538f1d13d4 | |
Kaitlyn | 783c9d4591 | |
Kaitlyn | 1a685b1c67 | |
Robin Kertels | 8b8be7c2bf | |
Billy Laws | 0776d764a4 | |
Robin Kertels | 15ddadc4de | |
Philip Rebohle | 69a52b3da0 | |
Philip Rebohle | 707ad6f328 | |
Philip Rebohle | 3a6992ea97 | |
Robin Kertels | 72c86b8229 | |
Robin Kertels | 85215b10d6 | |
Philip Rebohle | fd3fbf6607 | |
Minelelol | 0a699fddb6 | |
Blisto91 | afec5cce88 | |
Ethan Lee | 4b0e3111d1 | |
Philip Rebohle | 0414bbe2d5 | |
Robin Kertels | 20490b678f | |
Blisto91 | 428c98bc63 | |
Robin Kertels | a0e39e94fa | |
Robin Kertels | eaa732d0b3 | |
Robin Kertels | 49b18f03fe | |
Philip Rebohle | c9cea93b7b | |
Philip Rebohle | 69d74a46a0 | |
Philip Rebohle | 94098aa97d | |
Philip Rebohle | c677ba9b3e | |
Philip Rebohle | 77c7396ee1 | |
Philip Rebohle | f07e5f9eaa | |
Philip Rebohle | d5c3011f54 | |
Blisto91 | 6b3b934471 | |
Philip Rebohle | 9004c132ed | |
Philip Rebohle | 24d4c9c938 | |
Philip Rebohle | 5ded7d67f0 | |
Philip Rebohle | 234f3ea071 |
34
dxvk.conf
34
dxvk.conf
|
@ -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
|
21
meson.build
21
meson.build
|
@ -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@',
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1506,6 +1506,7 @@ namespace dxvk {
|
|||
const Rc<DxvkImage>& srcImage,
|
||||
VkImageSubresourceLayers srcSubresource,
|
||||
VkOffset3D srcOffset,
|
||||
VkFormat srcFormat,
|
||||
VkExtent3D extent);
|
||||
|
||||
bool copyImageClear(
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ namespace dxvk {
|
|||
VkPhysicalDeviceMaintenance5FeaturesKHR khrMaintenance5;
|
||||
VkPhysicalDevicePresentIdFeaturesKHR khrPresentId;
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR khrPresentWait;
|
||||
VkPhysicalDeviceRawAccessChainsFeaturesNV nvRawAccessChains;
|
||||
VkBool32 nvxBinaryImport;
|
||||
VkBool32 nvxImageViewHandle;
|
||||
VkBool32 khrWin32KeyedMutex;
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,6 @@ namespace dxvk {
|
|||
struct DxvkMemoryHeap {
|
||||
VkMemoryHeap properties;
|
||||
DxvkMemoryStats stats;
|
||||
VkDeviceSize budget;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 },
|
||||
}};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue