Compare commits

...

37 Commits

Author SHA1 Message Date
Philip Rebohle e4fd5e9e8d
[meta] Release 1.10.3 2022-08-02 14:52:09 +02:00
Philip Rebohle 257b075600
[dxvk] Add feature check for external semaphores 2022-08-02 14:36:37 +02:00
Derek Lesho 73b27a7eab [d3d11] Add support for shared ID3D11Fence resources 2022-07-29 00:12:12 +02:00
Derek Lesho 89ab338762 [dxvk] Add shared handle access to DxvkFence 2022-07-29 00:12:12 +02:00
Derek Lesho 215369900d [dxvk] Enable VK_KHR_external_semaphore_win32 if available 2022-07-29 00:12:12 +02:00
Philip Rebohle 513a2610e1 [d3d11] Implement ID3D11Fence
No interop support just yet.

Co-authored-by: Derek Lesho <dlesho@codeweavers.com>
2022-07-29 00:12:12 +02:00
Philip Rebohle 3bbcacf687 [dxvk] Add fence support to command list
Co-authored-by: Derek Lesho <dlesho@codeweavers.com>
2022-07-29 00:12:12 +02:00
Philip Rebohle f925560f82 [dxvk] Refactor queue submission info
Co-authored-by: Derek Lesho <dlesho@codeweavers.com>
2022-07-29 00:12:12 +02:00
Philip Rebohle 7264b1164c [dxvk] Add DxvkFence
Co-authored-by: Derek Lesho <dlesho@codeweavers.com>
2022-07-29 00:12:12 +02:00
Philip Rebohle 87b23ff9a0 [dxvk] Enable VK_KHR_timeline_semaphore if supported 2022-07-29 00:12:12 +02:00
Joshua Ashton f5fe2596e3 [build] Use arch-mingw-github-action v8
Fixes generated version info.
2022-07-26 18:52:56 +01:00
Blisto91 97ce782c9f
[util] set maxFrameLatency to 1 for YS Origin 2022-07-25 16:21:09 +02:00
Krzysztof Dobrowolski 93ea382c3e
[dxvk] Add Direct3D9ForceHybridEnumeration empty export function. 2022-07-25 16:21:00 +02:00
Philip Rebohle 990b43d51d
[util] Set ignoreGraphicsBarriers option for Stray 2022-07-23 21:22:35 +02:00
Blisto91 de626a7e35
[util] enable alphaTestWiggleRoom for Ninja Blade 2022-07-23 21:22:29 +02:00
Blisto91 bc5a4d3f6d
[util] enable dialog mode for NFS 3 modern patch 2022-07-22 19:48:09 +02:00
Philip Rebohle 5aa943f475
[d3d11] Fix render target validation (again)
This behaviour is rather obscure and undocumented, but testing shows
that DSV <-> RTV mismatches are allowed under some circumstances.

Fixes #2555.
2022-07-14 12:43:17 +02:00
Philip Rebohle 40e4ea1fce
[meta] Release 1.10.2 2022-07-13 14:47:29 +02:00
Philip Rebohle 7d2c2207fa
[d3d9] Fix up unsupported sample counts 2022-07-13 14:23:31 +02:00
Robin Kertels 2c40d49337
[d3d9] Allow POOL_SCRATCH targets in GetFrontBufferData 2022-07-13 14:01:01 +02:00
Blisto91 5f67d0fc89
[d3d9] add D3DFMT_UNKNOWN to windowed BackBufferFormat 2022-07-13 13:04:44 +02:00
Philip Rebohle 05416c3731
[d3d9] Explicitly check for Unknown in CheckDeviceFormatConversion 2022-07-13 13:04:43 +02:00
Philip Rebohle 8513ab4d77
[util] Work around silly compiler warnings on GCC 12.1
No, we're not actually reading 64 bytes from a 1-byte area.
2022-07-11 19:24:36 +02:00
Matej Dian 74abd7b525
[util] Enable cached dynamic resources for DayZ (#2709) 2022-07-10 15:19:30 +02:00
Blisto91 6a33c5d4f0
[util] Add workaround for Garden Warfare 2 (#2700) 2022-07-10 15:19:27 +02:00
Philip Rebohle 310d70bbf8
[d3d11] Ignore OMSetRenderTargets calls with incompatible view sizes
Fixes #2701.
2022-07-10 15:17:19 +02:00
Blisto91 e37bdcf348
[util] disable allowDoNotWait for Port Royale 3 (#2668) 2022-07-09 01:03:39 +02:00
Philip Rebohle aaf0db4c79
[dxvk] Remove in-memory pipeline cache
Lazy port of the changes in current development branches.
2022-07-08 19:29:07 +02:00
Trevonn 653f00d846
[util] Limit Dead Space to 60fps and fix vsync
https://www.pcgamingwiki.com/wiki/Dead_Space#Issues_fixed

The game has mouse acceleration and physics issues above 60 FPS.

Also the game locks to 30 FPS using the built-in vsync. 
Setting presentInterval to 1 blocks this and the game continues to run at 60 FPS
2022-07-07 16:15:47 +02:00
Georg Lehmann 96b3897fd9
[d3d9] Add an config option to disable non seamless cube maps. 2022-07-07 16:15:41 +02:00
Georg Lehmann b40a4286e4
[d3d9] Use non seamless samplers if supported. 2022-07-07 16:15:30 +02:00
Georg Lehmann cb76b02675
[dxvk] Enable VK_EXT_non_seamless_cube_map if requested. 2022-07-07 16:15:12 +02:00
Georg Lehmann 33f83e9561
[dxvk] Allow non seamless samplers. 2022-07-07 16:12:56 +02:00
Georg Lehmann 11b94088ad
[include] Update Vulkan headers to 1.3.217. 2022-07-07 16:12:44 +02:00
WinterSnowfall 7ae6564e0d
[util] Add workaround to fix missing sun & light shafts in Beyond Good And Evil 2022-07-07 16:11:58 +02:00
Philip Rebohle 2f6306815e
[dxvk] Fix opening state cache files for writing
operator bool() only checks if errors have occured in previous writes,
so we'd be missing out on the first cache entry written.
2022-07-03 15:38:53 +02:00
Philip Rebohle d1f57e13b7
[d3d9] Don't use VK_RESOLVE_MODE_AVERAGE_BIT_KHR for stencil resolves
Doesn't work, always write sample zero instead.
2022-07-02 16:48:23 +02:00
50 changed files with 2832 additions and 940 deletions

View File

@ -19,7 +19,7 @@ jobs:
- name: Build release
id: build-release
uses: Joshua-Ashton/arch-mingw-github-action@v7
uses: Joshua-Ashton/arch-mingw-github-action@v8
with:
command: |
export VERSION_NAME="${GITHUB_REF##*/}-${GITHUB_SHA##*/}"

View File

@ -1 +1 @@
1.10.1
1.10.3

View File

@ -548,6 +548,16 @@
# d3d9.apitraceMode = False
# Seamless Cubes
#
# Don't use non seamless cube maps even if they are supported.
# Non seamless cubes are correct d3d9 behavior, but can produce worse looking edges.
#
# Supported values:
# - True/False
# d3d9.seamlessCubes = False
# Debug Utils
#
# Enables debug utils as this is off by default, this enables user annotations like BeginEvent()/EndEvent().

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
project('dxvk', ['c', 'cpp'], version : 'v1.10.1', meson_version : '>= 0.49', default_options : [ 'cpp_std=c++17' ])
project('dxvk', ['c', 'cpp'], version : 'v1.10.3', meson_version : '>= 0.49', default_options : [ 'cpp_std=c++17' ])
cpu_family = target_machine.cpu_family()

View File

@ -4413,20 +4413,28 @@ namespace dxvk {
ID3D11RenderTargetView* const* ppRenderTargetViews,
ID3D11DepthStencilView* pDepthStencilView) {
Rc<DxvkImageView> refView;
VkExtent3D dsvExtent = { 0u, 0u, 0u };
VkExtent3D rtvExtent = { 0u, 0u, 0u };
if (pDepthStencilView != nullptr) {
refView = static_cast<D3D11DepthStencilView*>(
pDepthStencilView)->GetImageView();
dsvExtent = refView->mipLevelExtent(0);
}
for (uint32_t i = 0; i < NumViews; i++) {
if (ppRenderTargetViews[i] != nullptr) {
auto curView = static_cast<D3D11RenderTargetView*>(
ppRenderTargetViews[i])->GetImageView();
if (!rtvExtent.width)
rtvExtent = curView->mipLevelExtent(0);
if (refView != nullptr) {
// Render target views must all have the same
// size, sample count, layer count, and type
// Render target views must all have the same sample count,
// layer count, and type. The size can mismatch under certain
// conditions, the D3D11 documentation is wrong here.
if (curView->info().type != refView->info().type
|| curView->info().numLayers != refView->info().numLayers)
return false;
@ -4434,6 +4442,13 @@ namespace dxvk {
if (curView->imageInfo().sampleCount
!= refView->imageInfo().sampleCount)
return false;
// Color targets must all be the same size
VkExtent3D curExtent = curView->mipLevelExtent(0);
if (curExtent.width != rtvExtent.width
|| curExtent.height != rtvExtent.height)
return false;
} else {
// Set reference view. All remaining views
// must be compatible to the reference view.
@ -4441,7 +4456,15 @@ namespace dxvk {
}
}
}
// Based on testing, the depth-stencil target is allowed
// to be larger than all color targets, but not smaller
if (rtvExtent.width && dsvExtent.width) {
if (rtvExtent.width > dsvExtent.width
|| rtvExtent.height > dsvExtent.height)
return false;
}
return true;
}

View File

@ -1,6 +1,7 @@
#include "d3d11_cmdlist.h"
#include "d3d11_context_imm.h"
#include "d3d11_device.h"
#include "d3d11_fence.h"
#include "d3d11_texture.h"
constexpr static uint32_t MinFlushIntervalUs = 750;
@ -185,16 +186,41 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Signal(
ID3D11Fence* pFence,
UINT64 Value) {
Logger::err("D3D11ImmediateContext::Signal: Not implemented");
return E_NOTIMPL;
auto fence = static_cast<D3D11Fence*>(pFence);
if (!fence)
return E_INVALIDARG;
EmitCs([
cFence = fence->GetFence(),
cValue = Value
] (DxvkContext* ctx) {
ctx->signalFence(cFence, cValue);
});
Flush();
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D11ImmediateContext::Wait(
ID3D11Fence* pFence,
UINT64 Value) {
Logger::err("D3D11ImmediateContext::Wait: Not implemented");
return E_NOTIMPL;
auto fence = static_cast<D3D11Fence*>(pFence);
if (!fence)
return E_INVALIDARG;
Flush();
EmitCs([
cFence = fence->GetFence(),
cValue = Value
] (DxvkContext* ctx) {
ctx->waitFence(cFence, cValue);
});
return S_OK;
}

View File

@ -12,6 +12,7 @@
#include "d3d11_context_def.h"
#include "d3d11_context_imm.h"
#include "d3d11_device.h"
#include "d3d11_fence.h"
#include "d3d11_input_layout.h"
#include "d3d11_interop.h"
#include "d3d11_query.h"
@ -1347,16 +1348,17 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE D3D11Device::CreateFence(
UINT64 InitialValue,
D3D11_FENCE_FLAG Flags,
REFIID ReturnedInterface,
REFIID riid,
void** ppFence) {
InitReturnPtr(ppFence);
static bool s_errorShown = false;
if (!std::exchange(s_errorShown, true))
Logger::err("D3D11Device::CreateFence: Not implemented");
return E_NOTIMPL;
try {
Com<D3D11Fence> fence = new D3D11Fence(this, InitialValue, Flags, INVALID_HANDLE_VALUE);
return fence->QueryInterface(riid, ppFence);
} catch (const DxvkError& e) {
Logger::err(e.message());
return E_FAIL;
}
}
@ -1422,8 +1424,16 @@ namespace dxvk {
void** ppFence) {
InitReturnPtr(ppFence);
Logger::err("D3D11Device::OpenSharedFence: Not implemented");
return E_NOTIMPL;
if (ppFence == nullptr)
return S_FALSE;
try {
Com<D3D11Fence> fence = new D3D11Fence(this, 0, D3D11_FENCE_FLAG_SHARED, hFence);
return fence->QueryInterface(ReturnedInterface, ppFence);
} catch (const DxvkError& e) {
Logger::err(e.message());
return E_FAIL;
}
}
@ -1927,6 +1937,8 @@ namespace dxvk {
enabled.shaderDrawParameters.shaderDrawParameters = VK_TRUE;
enabled.khrTimelineSemaphore.timelineSemaphore = supported.khrTimelineSemaphore.timelineSemaphore;
enabled.extMemoryPriority.memoryPriority = supported.extMemoryPriority.memoryPriority;
enabled.extRobustness2.robustBufferAccess2 = supported.extRobustness2.robustBufferAccess2;

View File

@ -260,7 +260,7 @@ namespace dxvk {
HRESULT STDMETHODCALLTYPE CreateFence(
UINT64 InitialValue,
D3D11_FENCE_FLAG Flags,
REFIID ReturnedInterface,
REFIID riid,
void** ppFence);
void STDMETHODCALLTYPE ReadFromSubresource(

101
src/d3d11/d3d11_fence.cpp Normal file
View File

@ -0,0 +1,101 @@
#include "d3d11_fence.h"
#include "d3d11_device.h"
namespace dxvk {
D3D11Fence::D3D11Fence(
D3D11Device* pDevice,
UINT64 InitialValue,
D3D11_FENCE_FLAG Flags,
HANDLE hFence)
: D3D11DeviceChild<ID3D11Fence>(pDevice) {
DxvkFenceCreateInfo fenceInfo;
fenceInfo.initialValue = InitialValue;
m_flags = Flags;
if (Flags & D3D11_FENCE_FLAG_SHARED) {
fenceInfo.sharedType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D11_FENCE_BIT;
if (hFence == nullptr)
hFence = INVALID_HANDLE_VALUE;
fenceInfo.sharedHandle = hFence;
}
if (Flags & ~D3D11_FENCE_FLAG_SHARED)
Logger::err(str::format("Fence flags 0x", std::hex, Flags, " not supported"));
m_fence = pDevice->GetDXVKDevice()->createFence(fenceInfo);
}
D3D11Fence::~D3D11Fence() {
}
HRESULT STDMETHODCALLTYPE D3D11Fence::QueryInterface(
REFIID riid,
void** ppvObject) {
if (ppvObject == nullptr)
return E_POINTER;
*ppvObject = nullptr;
if (riid == __uuidof(IUnknown)
|| riid == __uuidof(ID3D11DeviceChild)
|| riid == __uuidof(ID3D11Fence)) {
*ppvObject = ref(this);
return S_OK;
}
Logger::warn("D3D11Fence: Unknown interface query");
Logger::warn(str::format(riid));
return E_NOINTERFACE;
}
HRESULT STDMETHODCALLTYPE D3D11Fence::CreateSharedHandle(
const SECURITY_ATTRIBUTES* pAttributes,
DWORD dwAccess,
LPCWSTR lpName,
HANDLE* pHandle) {
if (!(m_flags & D3D11_FENCE_FLAG_SHARED))
return E_INVALIDARG;
if (pAttributes)
Logger::warn(str::format("CreateSharedHandle: attributes ", pAttributes, " not handled"));
if (dwAccess)
Logger::warn(str::format("CreateSharedHandle: access ", dwAccess, " not handled"));
if (lpName)
Logger::warn(str::format("CreateSharedHandle: name ", dxvk::str::fromws(lpName), " not handled"));
HANDLE sharedHandle = m_fence->sharedHandle();
if (sharedHandle == INVALID_HANDLE_VALUE)
return E_INVALIDARG;
*pHandle = sharedHandle;
return S_OK;
}
HRESULT STDMETHODCALLTYPE D3D11Fence::SetEventOnCompletion(
UINT64 Value,
HANDLE hEvent) {
// TODO in case of rewinds, the stored value may be higher.
// For shared fences, calling vkWaitSemaphores here could alleviate the issue.
m_fence->enqueueWait(Value, [hEvent] {
SetEvent(hEvent);
});
return S_OK;
}
UINT64 STDMETHODCALLTYPE D3D11Fence::GetCompletedValue() {
// TODO in the case of rewinds, the stored value may be higher.
// For shared fences, calling vkGetSemaphoreCounterValue here could alleviate the issue.
return m_fence->getValue();
}
}

49
src/d3d11/d3d11_fence.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include "../dxvk/dxvk_fence.h"
#include "../dxvk/dxvk_gpu_query.h"
#include "d3d11_device_child.h"
namespace dxvk {
class D3D11Fence : public D3D11DeviceChild<ID3D11Fence> {
public:
D3D11Fence(
D3D11Device* pDevice,
UINT64 InitialValue,
D3D11_FENCE_FLAG Flags,
HANDLE hFence);
~D3D11Fence();
HRESULT STDMETHODCALLTYPE QueryInterface(
REFIID riid,
void** ppvObject);
HRESULT STDMETHODCALLTYPE CreateSharedHandle(
const SECURITY_ATTRIBUTES* pAttributes,
DWORD dwAccess,
LPCWSTR lpName,
HANDLE* pHandle);
HRESULT STDMETHODCALLTYPE SetEventOnCompletion(
UINT64 Value,
HANDLE hEvent);
UINT64 STDMETHODCALLTYPE GetCompletedValue();
Rc<DxvkFence> GetFence() const {
return m_fence;
}
private:
Rc<DxvkFence> m_fence;
D3D11_FENCE_FLAG m_flags;
};
}

View File

@ -38,6 +38,7 @@ namespace dxvk {
info.borderColor.float32[i] = desc.BorderColor[i];
info.usePixelCoord = VK_FALSE; // Not supported in D3D11
info.nonSeamless = VK_FALSE;
// Make sure to use a valid anisotropy value
if (desc.MaxAnisotropy < 1) info.maxAnisotropy = 1.0f;

View File

@ -365,6 +365,7 @@ namespace dxvk {
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.borderColor = VkClearColorValue();
samplerInfo.usePixelCoord = VK_FALSE;
samplerInfo.nonSeamless = VK_FALSE;
m_sampler = Device->createSampler(samplerInfo);
DxvkBufferCreateInfo bufferInfo;

View File

@ -37,6 +37,7 @@ d3d11_src = [
'd3d11_depth_stencil.cpp',
'd3d11_device.cpp',
'd3d11_enums.cpp',
'd3d11_fence.cpp',
'd3d11_gdi.cpp',
'd3d11_initializer.cpp',
'd3d11_input_layout.cpp',

View File

@ -23,3 +23,5 @@ EXPORTS
DXVK_RegisterAnnotation @ 28257 NONAME
DXVK_UnRegisterAnnotation @ 28258 NONAME
Direct3D9ForceHybridEnumeration @16 NONAME PRIVATE

View File

@ -236,7 +236,8 @@ namespace dxvk {
D3DDEVTYPE DeviceType,
D3D9Format SourceFormat,
D3D9Format TargetFormat) {
bool sourceSupported = IsSupportedBackBufferFormat(D3D9Format::Unknown, SourceFormat, TRUE);
bool sourceSupported = SourceFormat != D3D9Format::Unknown
&& IsSupportedBackBufferFormat(SourceFormat);
bool targetSupported = TargetFormat == D3D9Format::X1R5G5B5
|| TargetFormat == D3D9Format::A1R5G5B5
|| TargetFormat == D3D9Format::R5G6B5

View File

@ -134,7 +134,7 @@ namespace dxvk {
if (pDesc->Width == 0 || pDesc->Height == 0 || pDesc->Depth == 0)
return D3DERR_INVALIDCALL;
if (FAILED(DecodeMultiSampleType(pDesc->MultiSample, pDesc->MultisampleQuality, nullptr)))
if (FAILED(DecodeMultiSampleType(pDevice->GetDXVKDevice(), pDesc->MultiSample, pDesc->MultisampleQuality, nullptr)))
return D3DERR_INVALIDCALL;
// Using MANAGED pool with DYNAMIC usage is illegal
@ -258,7 +258,7 @@ namespace dxvk {
imageInfo.stages |= VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
}
DecodeMultiSampleType(m_desc.MultiSample, m_desc.MultisampleQuality, &imageInfo.sampleCount);
DecodeMultiSampleType(m_device->GetDXVKDevice(), m_desc.MultiSample, m_desc.MultisampleQuality, &imageInfo.sampleCount);
// The image must be marked as mutable if it can be reinterpreted
// by a view with a different format. Depth-stencil formats cannot

View File

@ -1066,7 +1066,7 @@ namespace dxvk {
ctx->resolveDepthStencilImage(
cDstImage, cSrcImage, cRegion,
VK_RESOLVE_MODE_AVERAGE_BIT_KHR,
VK_RESOLVE_MODE_AVERAGE_BIT_KHR);
VK_RESOLVE_MODE_SAMPLE_ZERO_BIT_KHR);
}
});
};
@ -3947,6 +3947,8 @@ namespace dxvk {
enabled.extCustomBorderColor.customBorderColorWithoutFormat = VK_TRUE;
}
enabled.extNonSeamlessCubeMap.nonSeamlessCubeMap = supported.extNonSeamlessCubeMap.nonSeamlessCubeMap;
return enabled;
}
@ -5952,6 +5954,7 @@ namespace dxvk {
info.mipmapLodMin = mipFilter.MipsEnabled ? float(cKey.MaxMipLevel) : 0;
info.mipmapLodMax = mipFilter.MipsEnabled ? FLT_MAX : 0;
info.usePixelCoord = VK_FALSE;
info.nonSeamless = m_dxvkDevice->features().extNonSeamlessCubeMap.nonSeamlessCubeMap && !m_d3d9Options.seamlessCubes;
DecodeD3DCOLOR(cKey.BorderColor, info.borderColor.float32);
@ -6955,7 +6958,7 @@ namespace dxvk {
const D3D9_COMMON_TEXTURE_DESC* dstDesc = dstTextureInfo->Desc();
VkSampleCountFlagBits dstSampleCount;
DecodeMultiSampleType(dstDesc->MultiSample, dstDesc->MultisampleQuality, &dstSampleCount);
DecodeMultiSampleType(m_dxvkDevice, dstDesc->MultiSample, dstDesc->MultisampleQuality, &dstSampleCount);
if (unlikely(dstSampleCount != VK_SAMPLE_COUNT_1_BIT)) {
Logger::warn("D3D9DeviceEx::ResolveZ: dstSampleCount != 1. Discarding.");
@ -6987,7 +6990,7 @@ namespace dxvk {
srcSubresource.arrayLayer, 1 };
VkSampleCountFlagBits srcSampleCount;
DecodeMultiSampleType(srcDesc->MultiSample, srcDesc->MultisampleQuality, &srcSampleCount);
DecodeMultiSampleType(m_dxvkDevice, srcDesc->MultiSample, srcDesc->MultisampleQuality, &srcSampleCount);
if (srcSampleCount == VK_SAMPLE_COUNT_1_BIT) {
EmitCs([

View File

@ -98,4 +98,7 @@ extern "C" {
dxvk::D3D9GlobalAnnotationList::Instance().UnregisterAnnotator(annotation);
}
DLLEXPORT void __stdcall Direct3D9ForceHybridEnumeration(UINT uHybrid) {
}
}

View File

@ -57,7 +57,8 @@ namespace dxvk {
|| BackBufferFormat == D3D9Format::X8R8G8B8
|| BackBufferFormat == D3D9Format::A1R5G5B5
|| BackBufferFormat == D3D9Format::X1R5G5B5
|| BackBufferFormat == D3D9Format::R5G6B5;
|| BackBufferFormat == D3D9Format::R5G6B5
|| BackBufferFormat == D3D9Format::Unknown;
}
}

View File

@ -73,6 +73,7 @@ namespace dxvk {
this->apitraceMode = config.getOption<bool> ("d3d9.apitraceMode", false);
this->deviceLocalConstantBuffers = config.getOption<bool> ("d3d9.deviceLocalConstantBuffers", false);
this->allowDirectBufferMapping = config.getOption<bool> ("d3d9.allowDirectBufferMapping", true);
this->seamlessCubes = config.getOption<bool> ("d3d9.seamlessCubes", false);
// If we are not Nvidia, enable general hazards.
this->generalHazards = adapter != nullptr

View File

@ -157,6 +157,9 @@ namespace dxvk {
/// Disable direct buffer mapping
bool allowDirectBufferMapping;
/// Don't use non seamless cube maps
bool seamlessCubes;
};
}

View File

@ -333,7 +333,7 @@ namespace dxvk {
D3D9CommonTexture* dstTexInfo = dst->GetCommonTexture();
D3D9CommonTexture* srcTexInfo = m_backBuffers.back()->GetCommonTexture();
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM))
if (unlikely(dstTexInfo->Desc()->Pool != D3DPOOL_SYSTEMMEM && dstTexInfo->Desc()->Pool != D3DPOOL_SCRATCH))
return D3DERR_INVALIDCALL;
Rc<DxvkBuffer> dstBuffer = dstTexInfo->GetBuffer(dst->GetSubresource());

View File

@ -37,9 +37,10 @@ namespace dxvk {
HRESULT DecodeMultiSampleType(
const Rc<DxvkDevice>& pDevice,
D3DMULTISAMPLE_TYPE MultiSample,
DWORD MultisampleQuality,
VkSampleCountFlagBits* pCount) {
VkSampleCountFlagBits* pSampleCount) {
uint32_t sampleCount = std::max<uint32_t>(MultiSample, 1u);
// Check if this is a power of two...
@ -49,8 +50,14 @@ namespace dxvk {
if (MultiSample == D3DMULTISAMPLE_NONMASKABLE)
sampleCount = 1u << MultisampleQuality;
if (pCount != nullptr)
*pCount = VkSampleCountFlagBits(sampleCount);
const auto& limits = pDevice->properties().core.properties.limits;
VkSampleCountFlags supportedSampleCounts = limits.framebufferColorSampleCounts & limits.framebufferDepthSampleCounts;
while (sampleCount > supportedSampleCounts)
sampleCount >>= 1;
if (pSampleCount)
*pSampleCount = VkSampleCountFlagBits(sampleCount);
return D3D_OK;
}

View File

@ -95,9 +95,10 @@ namespace dxvk {
ID3DBlob** ppDisassembly);
HRESULT DecodeMultiSampleType(
D3DMULTISAMPLE_TYPE MultiSample,
DWORD MultisampleQuality,
VkSampleCountFlagBits* pCount);
const Rc<DxvkDevice>& pDevice,
D3DMULTISAMPLE_TYPE MultiSample,
DWORD MultisampleQuality,
VkSampleCountFlagBits* pSampleCount);
VkFormat GetPackedDepthStencilFormat(D3D9Format Format);

View File

@ -238,6 +238,8 @@ namespace dxvk {
|| !required.extHostQueryReset.hostQueryReset)
&& (m_deviceFeatures.extMemoryPriority.memoryPriority
|| !required.extMemoryPriority.memoryPriority)
&& (m_deviceFeatures.extNonSeamlessCubeMap.nonSeamlessCubeMap
|| !required.extNonSeamlessCubeMap.nonSeamlessCubeMap)
&& (m_deviceFeatures.extRobustness2.robustBufferAccess2
|| !required.extRobustness2.robustBufferAccess2)
&& (m_deviceFeatures.extRobustness2.robustImageAccess2
@ -249,7 +251,9 @@ namespace dxvk {
&& (m_deviceFeatures.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor
|| !required.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor)
&& (m_deviceFeatures.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor
|| !required.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor);
|| !required.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor)
&& (m_deviceFeatures.khrTimelineSemaphore.timelineSemaphore
|| !required.khrTimelineSemaphore.timelineSemaphore);
}
@ -263,7 +267,7 @@ namespace dxvk {
DxvkDeviceFeatures enabledFeatures) {
DxvkDeviceExtensions devExtensions;
std::array<DxvkExt*, 29> devExtensionList = {{
std::array<DxvkExt*, 32> devExtensionList = {{
&devExtensions.amdMemoryOverallocationBehaviour,
&devExtensions.amdShaderFragmentMask,
&devExtensions.ext4444Formats,
@ -275,6 +279,7 @@ namespace dxvk {
&devExtensions.extHostQueryReset,
&devExtensions.extMemoryBudget,
&devExtensions.extMemoryPriority,
&devExtensions.extNonSeamlessCubeMap,
&devExtensions.extRobustness2,
&devExtensions.extShaderDemoteToHelperInvocation,
&devExtensions.extShaderStencilExport,
@ -287,10 +292,12 @@ namespace dxvk {
&devExtensions.khrDrawIndirectCount,
&devExtensions.khrDriverProperties,
&devExtensions.khrExternalMemoryWin32,
&devExtensions.khrExternalSemaphoreWin32,
&devExtensions.khrImageFormatList,
&devExtensions.khrSamplerMirrorClampToEdge,
&devExtensions.khrShaderFloatControls,
&devExtensions.khrSwapchain,
&devExtensions.khrTimelineSemaphore,
&devExtensions.nvxBinaryImport,
&devExtensions.nvxImageViewHandle,
}};
@ -377,6 +384,11 @@ namespace dxvk {
enabledFeatures.extMemoryPriority.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extMemoryPriority);
}
if (devExtensions.extNonSeamlessCubeMap) {
enabledFeatures.extNonSeamlessCubeMap.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT;
enabledFeatures.extNonSeamlessCubeMap.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extNonSeamlessCubeMap);
}
if (devExtensions.extShaderDemoteToHelperInvocation) {
enabledFeatures.extShaderDemoteToHelperInvocation.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DEMOTE_TO_HELPER_INVOCATION_FEATURES_EXT;
enabledFeatures.extShaderDemoteToHelperInvocation.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.extShaderDemoteToHelperInvocation);
@ -402,6 +414,11 @@ namespace dxvk {
enabledFeatures.khrBufferDeviceAddress.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrBufferDeviceAddress);
}
if (devExtensions.khrTimelineSemaphore) {
enabledFeatures.khrTimelineSemaphore.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR;
enabledFeatures.khrTimelineSemaphore.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrTimelineSemaphore);
}
// Report the desired overallocation behaviour to the driver
VkDeviceMemoryOverallocationCreateInfoAMD overallocInfo;
overallocInfo.sType = VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD;
@ -621,6 +638,11 @@ namespace dxvk {
m_deviceInfo.khrShaderFloatControls.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.khrShaderFloatControls);
}
if (m_deviceExtensions.supports(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME)) {
m_deviceInfo.khrTimelineSemaphore.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_PROPERTIES_KHR;
m_deviceInfo.khrTimelineSemaphore.pNext = std::exchange(m_deviceInfo.core.pNext, &m_deviceInfo.khrTimelineSemaphore);
}
// Query full device properties for all enabled extensions
m_vki->vkGetPhysicalDeviceProperties2(m_handle, &m_deviceInfo.core);
@ -682,6 +704,11 @@ namespace dxvk {
m_deviceFeatures.extMemoryPriority.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extMemoryPriority);
}
if (m_deviceExtensions.supports(VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME)) {
m_deviceFeatures.extNonSeamlessCubeMap.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_NON_SEAMLESS_CUBE_MAP_FEATURES_EXT;
m_deviceFeatures.extNonSeamlessCubeMap.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extNonSeamlessCubeMap);
}
if (m_deviceExtensions.supports(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME)) {
m_deviceFeatures.extRobustness2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT;
m_deviceFeatures.extRobustness2.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.extRobustness2);
@ -707,6 +734,11 @@ namespace dxvk {
m_deviceFeatures.khrBufferDeviceAddress.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrBufferDeviceAddress);
}
if (m_deviceExtensions.supports(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME)) {
m_deviceFeatures.khrTimelineSemaphore.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR;
m_deviceFeatures.khrTimelineSemaphore.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrTimelineSemaphore);
}
m_vki->vkGetPhysicalDeviceFeatures2(m_handle, &m_deviceFeatures.core);
}
@ -787,6 +819,8 @@ namespace dxvk {
"\n hostQueryReset : ", features.extHostQueryReset.hostQueryReset ? "1" : "0",
"\n", VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME,
"\n memoryPriority : ", features.extMemoryPriority.memoryPriority ? "1" : "0",
"\n", VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME,
"\n nonSeamlessCubeMap : ", features.extNonSeamlessCubeMap.nonSeamlessCubeMap ? "1" : "0",
"\n", VK_EXT_ROBUSTNESS_2_EXTENSION_NAME,
"\n robustBufferAccess2 : ", features.extRobustness2.robustBufferAccess2 ? "1" : "0",
"\n robustImageAccess2 : ", features.extRobustness2.robustImageAccess2 ? "1" : "0",
@ -800,7 +834,9 @@ namespace dxvk {
"\n vertexAttributeInstanceRateDivisor : ", features.extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor ? "1" : "0",
"\n vertexAttributeInstanceRateZeroDivisor : ", features.extVertexAttributeDivisor.vertexAttributeInstanceRateZeroDivisor ? "1" : "0",
"\n", VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
"\n bufferDeviceAddress : ", features.khrBufferDeviceAddress.bufferDeviceAddress));
"\n bufferDeviceAddress : ", features.khrBufferDeviceAddress.bufferDeviceAddress,
"\n", VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME,
"\n timelineSemaphore : ", features.khrTimelineSemaphore.timelineSemaphore));
}

View File

@ -85,40 +85,43 @@ namespace dxvk {
const auto& graphics = m_device->queues().graphics;
const auto& transfer = m_device->queues().transfer;
DxvkQueueSubmission info = DxvkQueueSubmission();
m_submission.reset();
if (m_cmdBuffersUsed.test(DxvkCmdBuffer::SdmaBuffer)) {
info.cmdBuffers[info.cmdBufferCount++] = m_sdmaBuffer;
m_submission.cmdBuffers.push_back(m_sdmaBuffer);
if (m_device->hasDedicatedTransferQueue()) {
info.wakeSync[info.wakeCount++] = m_sdmaSemaphore;
VkResult status = submitToQueue(transfer.queueHandle, VK_NULL_HANDLE, info);
m_submission.addWakeSemaphore(m_sdmaSemaphore, 0);
VkResult status = submitToQueue(transfer.queueHandle, VK_NULL_HANDLE, m_submission);
if (status != VK_SUCCESS)
return status;
info = DxvkQueueSubmission();
info.waitSync[info.waitCount] = m_sdmaSemaphore;
info.waitMask[info.waitCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
info.waitCount += 1;
m_submission.reset();
m_submission.addWaitSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
}
}
if (m_cmdBuffersUsed.test(DxvkCmdBuffer::InitBuffer))
info.cmdBuffers[info.cmdBufferCount++] = m_initBuffer;
m_submission.cmdBuffers.push_back(m_initBuffer);
if (m_cmdBuffersUsed.test(DxvkCmdBuffer::ExecBuffer))
info.cmdBuffers[info.cmdBufferCount++] = m_execBuffer;
m_submission.cmdBuffers.push_back(m_execBuffer);
if (waitSemaphore) {
info.waitSync[info.waitCount] = waitSemaphore;
info.waitMask[info.waitCount] = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
info.waitCount += 1;
}
if (waitSemaphore)
m_submission.addWaitSemaphore(waitSemaphore, 0, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
if (wakeSemaphore)
info.wakeSync[info.wakeCount++] = wakeSemaphore;
m_submission.addWakeSemaphore(wakeSemaphore, 0);
return submitToQueue(graphics.queueHandle, m_fence, info);
for (const auto& entry : m_waitSemaphores) {
m_submission.addWaitSemaphore(entry.fence->handle(), entry.value, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
}
for (const auto& entry : m_signalSemaphores) {
m_submission.addWakeSemaphore(entry.fence->handle(), entry.value);
}
return submitToQueue(graphics.queueHandle, m_fence, m_submission);
}
@ -186,6 +189,9 @@ namespace dxvk {
// Less important stuff
m_signalTracker.reset();
m_statCounters.reset();
m_waitSemaphores.clear();
m_signalSemaphores.clear();
}
@ -193,16 +199,23 @@ namespace dxvk {
VkQueue queue,
VkFence fence,
const DxvkQueueSubmission& info) {
VkSubmitInfo submitInfo;
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = nullptr;
submitInfo.waitSemaphoreCount = info.waitCount;
submitInfo.pWaitSemaphores = info.waitSync;
submitInfo.pWaitDstStageMask = info.waitMask;
submitInfo.commandBufferCount = info.cmdBufferCount;
submitInfo.pCommandBuffers = info.cmdBuffers;
submitInfo.signalSemaphoreCount = info.wakeCount;
submitInfo.pSignalSemaphores = info.wakeSync;
VkTimelineSemaphoreSubmitInfoKHR timelineInfo = { VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR };
timelineInfo.waitSemaphoreValueCount = info.waitValues.size();
timelineInfo.pWaitSemaphoreValues = info.waitValues.data();
timelineInfo.signalSemaphoreValueCount = info.wakeValues.size();
timelineInfo.pSignalSemaphoreValues = info.wakeValues.data();
VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
submitInfo.waitSemaphoreCount = info.waitSync.size();
submitInfo.pWaitSemaphores = info.waitSync.data();
submitInfo.pWaitDstStageMask = info.waitMask.data();
submitInfo.commandBufferCount = info.cmdBuffers.size();
submitInfo.pCommandBuffers = info.cmdBuffers.data();
submitInfo.signalSemaphoreCount = info.wakeSync.size();
submitInfo.pSignalSemaphores = info.wakeSync.data();
if (m_device->features().khrTimelineSemaphore.timelineSemaphore)
submitInfo.pNext = &timelineInfo;
return m_vkd->vkQueueSubmit(queue, 1, &submitInfo, fence);
}

View File

@ -5,6 +5,7 @@
#include "dxvk_bind_mask.h"
#include "dxvk_buffer.h"
#include "dxvk_descriptor.h"
#include "dxvk_fence.h"
#include "dxvk_gpu_event.h"
#include "dxvk_gpu_query.h"
#include "dxvk_lifetime.h"
@ -38,13 +39,32 @@ namespace dxvk {
* only, array sizes are based on need.
*/
struct DxvkQueueSubmission {
uint32_t waitCount;
VkSemaphore waitSync[2];
VkPipelineStageFlags waitMask[2];
uint32_t wakeCount;
VkSemaphore wakeSync[2];
uint32_t cmdBufferCount;
VkCommandBuffer cmdBuffers[4];
std::vector<VkSemaphore> waitSync;
std::vector<VkPipelineStageFlags> waitMask;
std::vector<uint64_t> waitValues;
std::vector<VkSemaphore> wakeSync;
std::vector<uint64_t> wakeValues;
std::vector<VkCommandBuffer> cmdBuffers;
void addWaitSemaphore(VkSemaphore semaphore, uint64_t value, VkPipelineStageFlags stageMask) {
waitSync.push_back(semaphore);
waitMask.push_back(stageMask);
waitValues.push_back(value);
}
void addWakeSemaphore(VkSemaphore semaphore, uint64_t value) {
wakeSync.push_back(semaphore);
wakeValues.push_back(value);
}
void reset() {
waitSync.clear();
waitMask.clear();
waitValues.clear();
wakeSync.clear();
wakeValues.clear();
cmdBuffers.clear();
}
};
/**
@ -201,6 +221,26 @@ namespace dxvk {
m_signalTracker.notify();
}
/**
* \brief Waits for fence
*
* \param [in] fence Fence to wait on
* \param [in] value Value to wait for
*/
void waitFence(Rc<DxvkFence> fence, uint64_t value) {
m_waitSemaphores.emplace_back(std::move(fence), value);
}
/**
* \brief Signals fence
*
* \param [in] fence Fence to signal
* \param [in] value Value to signal to
*/
void signalFence(Rc<DxvkFence> fence, uint64_t value) {
m_signalSemaphores.emplace_back(std::move(fence), value);
}
/**
* \brief Resets the command list
*
@ -765,7 +805,7 @@ namespace dxvk {
VkCommandBuffer m_sdmaBuffer = VK_NULL_HANDLE;
VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE;
DxvkCmdBufferFlags m_cmdBuffersUsed;
DxvkLifetimeTracker m_resources;
DxvkDescriptorPoolTracker m_descriptorPoolTracker;
@ -774,6 +814,10 @@ namespace dxvk {
DxvkGpuQueryTracker m_gpuQueryTracker;
DxvkBufferTracker m_bufferTracker;
DxvkStatCounters m_statCounters;
DxvkQueueSubmission m_submission;
std::vector<DxvkFenceValuePair> m_waitSemaphores;
std::vector<DxvkFenceValuePair> m_signalSemaphores;
VkCommandBuffer getCmdBuffer(DxvkCmdBuffer cmdBuffer) const {
if (cmdBuffer == DxvkCmdBuffer::ExecBuffer) return m_execBuffer;

View File

@ -2574,6 +2574,16 @@ namespace dxvk {
}
void DxvkContext::waitFence(const Rc<DxvkFence>& fence, uint64_t value) {
m_cmd->waitFence(fence, value);
}
void DxvkContext::signalFence(const Rc<DxvkFence>& fence, uint64_t value) {
m_cmd->signalFence(fence, value);
}
void DxvkContext::beginDebugLabel(VkDebugUtilsLabelEXT *label) {
if (!m_device->instance()->extensions().extDebugUtils)
return;

View File

@ -989,7 +989,27 @@ namespace dxvk {
void signal(
const Rc<sync::Signal>& signal,
uint64_t value);
/**
* \brief Waits for fence
*
* Stalls current command list execution until
* the fence reaches the given value or higher.
* \param [in] fence Fence to wait on
* \param [in] value Value to wait on
*/
void waitFence(const Rc<DxvkFence>& fence, uint64_t value);
/**
* \brief Signals fence
*
* Signals fence to the given value once the current
* command list execution completes on the GPU.
* \param [in] fence Fence to signal
* \param [in] value Value to signal
*/
void signalFence(const Rc<DxvkFence>& fence, uint64_t value);
/**
* \brief Begins a debug label region
* \param [in] label The debug label

View File

@ -112,6 +112,12 @@ namespace dxvk {
}
Rc<DxvkFence> DxvkDevice::createFence(
const DxvkFenceCreateInfo& fenceInfo) {
return new DxvkFence(this, fenceInfo);
}
Rc<DxvkFramebuffer> DxvkDevice::createFramebuffer(
const DxvkFramebufferInfo& info) {
return new DxvkFramebuffer(m_vkd, info);

View File

@ -6,6 +6,7 @@
#include "dxvk_constant_state.h"
#include "dxvk_context.h"
#include "dxvk_extensions.h"
#include "dxvk_fence.h"
#include "dxvk_framebuffer.h"
#include "dxvk_image.h"
#include "dxvk_instance.h"
@ -266,6 +267,15 @@ namespace dxvk {
VkQueryType type,
VkQueryControlFlags flags,
uint32_t index);
/**
* \brief Creates new fence
*
* \param [in] info Fence create info
* \returns The fence
*/
Rc<DxvkFence> createFence(
const DxvkFenceCreateInfo& fenceInfo);
/**
* \brief Creates framebuffer for a set of render targets
@ -515,4 +525,4 @@ namespace dxvk {
};
}
}

View File

@ -24,6 +24,7 @@ namespace dxvk {
VkPhysicalDeviceDepthStencilResolvePropertiesKHR khrDepthStencilResolve;
VkPhysicalDeviceDriverPropertiesKHR khrDeviceDriverProperties;
VkPhysicalDeviceFloatControlsPropertiesKHR khrShaderFloatControls;
VkPhysicalDeviceTimelineSemaphorePropertiesKHR khrTimelineSemaphore;
};
@ -43,11 +44,13 @@ namespace dxvk {
VkPhysicalDeviceExtendedDynamicStateFeaturesEXT extExtendedDynamicState;
VkPhysicalDeviceHostQueryResetFeaturesEXT extHostQueryReset;
VkPhysicalDeviceMemoryPriorityFeaturesEXT extMemoryPriority;
VkPhysicalDeviceNonSeamlessCubeMapFeaturesEXT extNonSeamlessCubeMap;
VkPhysicalDeviceRobustness2FeaturesEXT extRobustness2;
VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT extShaderDemoteToHelperInvocation;
VkPhysicalDeviceTransformFeedbackFeaturesEXT extTransformFeedback;
VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT extVertexAttributeDivisor;
VkPhysicalDeviceBufferDeviceAddressFeaturesKHR khrBufferDeviceAddress;
VkPhysicalDeviceTimelineSemaphoreFeaturesKHR khrTimelineSemaphore;
};
}

View File

@ -287,6 +287,7 @@ namespace dxvk {
DxvkExt extHostQueryReset = { VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt extMemoryBudget = { VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, DxvkExtMode::Passive };
DxvkExt extMemoryPriority = { VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt extNonSeamlessCubeMap = { VK_EXT_NON_SEAMLESS_CUBE_MAP_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt extRobustness2 = { VK_EXT_ROBUSTNESS_2_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt extShaderDemoteToHelperInvocation = { VK_EXT_SHADER_DEMOTE_TO_HELPER_INVOCATION_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt extShaderStencilExport = { VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, DxvkExtMode::Optional };
@ -299,10 +300,12 @@ namespace dxvk {
DxvkExt khrDrawIndirectCount = { VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrDriverProperties = { VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrExternalMemoryWin32 = { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrExternalSemaphoreWin32 = { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrImageFormatList = { VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, DxvkExtMode::Required };
DxvkExt khrSamplerMirrorClampToEdge = { VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrShaderFloatControls = { VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, DxvkExtMode::Optional };
DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
DxvkExt khrTimelineSemaphore = { VK_KHR_TIMELINE_SEMAPHORE_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 };
};

152
src/dxvk/dxvk_fence.cpp Normal file
View File

@ -0,0 +1,152 @@
#include "dxvk_device.h"
#include "dxvk_fence.h"
namespace dxvk {
DxvkFence::DxvkFence(
DxvkDevice* device,
const DxvkFenceCreateInfo& info)
: m_vkd(device->vkd()), m_info(info) {
if (!device->features().khrTimelineSemaphore.timelineSemaphore)
throw DxvkError("Timeline semaphores not supported");
VkSemaphoreTypeCreateInfoKHR typeInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO_KHR };
typeInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE_KHR;
typeInfo.initialValue = info.initialValue;
VkExportSemaphoreCreateInfo exportInfo = { VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO };
exportInfo.handleTypes = info.sharedType;
VkExternalSemaphoreFeatureFlags externalFeatures = 0;
if (info.sharedType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM) {
auto vki = device->adapter()->vki();
VkPhysicalDeviceExternalSemaphoreInfo externalInfo = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, &typeInfo };
externalInfo.handleType = info.sharedType;
VkExternalSemaphoreProperties externalProperties = { };
vki->vkGetPhysicalDeviceExternalSemaphoreProperties(
device->adapter()->handle(), &externalInfo, &externalProperties);
externalFeatures = externalProperties.externalSemaphoreFeatures;
if (externalFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT)
typeInfo.pNext = &exportInfo;
else
Logger::warn(str::format("Exporting semaphores of type ", info.sharedType, " not supported by device"));
}
VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, &typeInfo };
VkResult vr = m_vkd->vkCreateSemaphore(m_vkd->device(),
&semaphoreInfo, nullptr, &m_semaphore);
if (vr != VK_SUCCESS)
throw DxvkError("Failed to create timeline semaphore");
if (info.sharedHandle != INVALID_HANDLE_VALUE) {
if (externalFeatures & VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT) {
VkImportSemaphoreWin32HandleInfoKHR importInfo = { VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR };
importInfo.semaphore = m_semaphore;
importInfo.handleType = info.sharedType;
importInfo.handle = info.sharedHandle;
vr = m_vkd->vkImportSemaphoreWin32HandleKHR(m_vkd->device(), &importInfo);
if (vr != VK_SUCCESS)
throw DxvkError("Failed to import timeline semaphore");
} else {
Logger::warn(str::format("Importing semaphores of type ", info.sharedType, " not supported by device"));
}
}
m_thread = dxvk::thread([this] { run(); });
}
DxvkFence::~DxvkFence() {
m_stop.store(true);
m_thread.join();
m_vkd->vkDestroySemaphore(m_vkd->device(), m_semaphore, nullptr);
}
void DxvkFence::enqueueWait(uint64_t value, DxvkFenceEvent&& event) {
std::unique_lock<dxvk::mutex> lock(m_mutex);
if (value > m_lastValue.load())
m_queue.emplace(value, std::move(event));
else
event();
}
void DxvkFence::run() {
uint64_t value = 0ull;
VkSemaphoreWaitInfoKHR waitInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO_KHR };
waitInfo.semaphoreCount = 1;
waitInfo.pSemaphores = &m_semaphore;
waitInfo.pValues = &value;
while (!m_stop.load()) {
std::unique_lock<dxvk::mutex> lock(m_mutex);
// Query actual semaphore value and start from there, so that
// we can skip over large increments in the semaphore value
VkResult vr = m_vkd->vkGetSemaphoreCounterValueKHR(m_vkd->device(), m_semaphore, &value);
if (vr != VK_SUCCESS) {
Logger::err(str::format("Failed to query semaphore value: ", vr));
return;
}
m_lastValue.store(value);
// Signal all enqueued events whose value is not greater than
// the current semaphore value
while (!m_queue.empty() && m_queue.top().value <= value) {
m_queue.top().event();
m_queue.pop();
}
if (m_stop)
return;
lock.unlock();
// Wait for the semaphore to be singaled again and update state.
// The timeout is unfortunate, but we can't always know when a
// signal operation has been recorded, and the alternative would
// be to create a teardown semaphore and use WAIT_ANY, which may
// be fall back to a busy-wait loop on some drivers.
value += 1;
vr = m_vkd->vkWaitSemaphoresKHR(
m_vkd->device(), &waitInfo, 10'000'000ull);
if (vr != VK_SUCCESS && vr != VK_TIMEOUT) {
Logger::err(str::format("Failed to wait for semaphore: ", vr));
return;
}
}
}
HANDLE DxvkFence::sharedHandle() const {
if (m_info.sharedType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM)
return INVALID_HANDLE_VALUE;
VkSemaphoreGetWin32HandleInfoKHR win32HandleInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR };
win32HandleInfo.semaphore = m_semaphore;
win32HandleInfo.handleType = m_info.sharedType;
HANDLE sharedHandle = INVALID_HANDLE_VALUE;
VkResult vr = m_vkd->vkGetSemaphoreWin32HandleKHR(m_vkd->device(), &win32HandleInfo, &sharedHandle);
if (vr != VK_SUCCESS)
Logger::err(str::format("Failed to get semaphore handle: ", vr));
return sharedHandle;
}
}

129
src/dxvk/dxvk_fence.h Normal file
View File

@ -0,0 +1,129 @@
#pragma once
#include <functional>
#include <queue>
#include <utility>
#include <vector>
#include "dxvk_resource.h"
#include "../util/thread.h"
namespace dxvk {
class DxvkDevice;
class DxvkFence;
using DxvkFenceEvent = std::function<void ()>;
/**
* \brief Fence create info
*/
struct DxvkFenceCreateInfo {
uint64_t initialValue;
VkExternalSemaphoreHandleTypeFlagBits sharedType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
union {
#ifdef _WIN32
HANDLE sharedHandle = INVALID_HANDLE_VALUE;
#else
// Placeholder for other handle types, such as FD
void *dummy;
#endif
};
};
/**
* \brief Fence-value pair
*/
struct DxvkFenceValuePair {
DxvkFenceValuePair() { }
DxvkFenceValuePair(Rc<DxvkFence>&& fence_, uint64_t value_)
: fence(std::move(fence_)), value(value_) { }
DxvkFenceValuePair(const Rc<DxvkFence>& fence_, uint64_t value_)
: fence(fence_), value(value_) { }
Rc<DxvkFence> fence;
uint64_t value;
};
/**
* \brief Fence
*
* Wrapper around Vulkan timeline semaphores that
* can signal an event when the value changes.
*/
class DxvkFence : public RcObject {
public:
DxvkFence(
DxvkDevice* device,
const DxvkFenceCreateInfo& info);
~DxvkFence();
/**
* \brief Semaphore handle
*/
VkSemaphore handle() const {
return m_semaphore;
}
/**
* \brief Retrieves current semaphore value
* \returns Current semaphore value
*/
uint64_t getValue() {
return m_lastValue.load();
}
/**
* \brief Enqueues semaphore wait
*
* Signals the given event when the
* semaphore reaches the given value.
* \param [in] value Enqueue value
* \param [in] event Callback
*/
void enqueueWait(uint64_t value, DxvkFenceEvent&& event);
/**
* \brief Create a new shared handle to timeline semaphore backing the fence
* \returns The shared handle with the type given by DxvkFenceCreateInfo::sharedType
*/
HANDLE sharedHandle() const;
private:
struct QueueItem {
QueueItem() { }
QueueItem(uint32_t v, DxvkFenceEvent&& e)
: value(v), event(std::move(e)) { }
uint64_t value;
DxvkFenceEvent event;
bool operator == (const QueueItem& item) const { return value == item.value; }
bool operator != (const QueueItem& item) const { return value != item.value; }
bool operator < (const QueueItem& item) const { return value < item.value; }
bool operator <= (const QueueItem& item) const { return value <= item.value; }
bool operator > (const QueueItem& item) const { return value > item.value; }
bool operator >= (const QueueItem& item) const { return value >= item.value; }
};
Rc<vk::DeviceFn> m_vkd;
DxvkFenceCreateInfo m_info;
VkSemaphore m_semaphore;
std::priority_queue<QueueItem> m_queue;
std::atomic<uint64_t> m_lastValue = { 0ull };
std::atomic<bool> m_stop = { false };
dxvk::mutex m_mutex;
dxvk::thread m_thread;
void run();
};
}

View File

@ -128,7 +128,7 @@ namespace dxvk {
appInfo.pApplicationName = appName.c_str();
appInfo.applicationVersion = 0;
appInfo.pEngineName = "DXVK";
appInfo.engineVersion = VK_MAKE_VERSION(1, 10, 1);
appInfo.engineVersion = VK_MAKE_VERSION(1, 10, 3);
appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
VkInstanceCreateInfo info;

View File

@ -2,25 +2,4 @@
namespace dxvk {
DxvkPipelineCache::DxvkPipelineCache(
const Rc<vk::DeviceFn>& vkd)
: m_vkd(vkd) {
VkPipelineCacheCreateInfo info;
info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
info.pNext = nullptr;
info.flags = 0;
info.initialDataSize = 0;
info.pInitialData = nullptr;
if (m_vkd->vkCreatePipelineCache(m_vkd->device(),
&info, nullptr, &m_handle) != VK_SUCCESS)
throw DxvkError("DxvkPipelineCache: Failed to create cache");
}
DxvkPipelineCache::~DxvkPipelineCache() {
m_vkd->vkDestroyPipelineCache(
m_vkd->device(), m_handle, nullptr);
}
}

View File

@ -22,22 +22,16 @@ namespace dxvk {
public:
DxvkPipelineCache(const Rc<vk::DeviceFn>& vkd);
~DxvkPipelineCache();
DxvkPipelineCache(const Rc<vk::DeviceFn>& vkd) { }
/**
* \brief Pipeline cache handle
* \returns Pipeline cache handle
*/
VkPipelineCache handle() const {
return m_handle;
return VK_NULL_HANDLE;
}
private:
Rc<vk::DeviceFn> m_vkd;
VkPipelineCache m_handle;
};
}

View File

@ -16,7 +16,7 @@ namespace dxvk {
VkSamplerCreateInfo samplerInfo;
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerInfo.pNext = nullptr;
samplerInfo.flags = 0;
samplerInfo.flags = info.nonSeamless ? VK_SAMPLER_CREATE_NON_SEAMLESS_CUBE_MAP_BIT_EXT : 0;
samplerInfo.magFilter = info.magFilter;
samplerInfo.minFilter = info.minFilter;
samplerInfo.mipmapMode = info.mipmapMode;

View File

@ -38,6 +38,9 @@ namespace dxvk {
/// Enables unnormalized coordinates
VkBool32 usePixelCoord;
/// Enables non seamless cube map filtering
VkBool32 nonSeamless;
};

View File

@ -962,8 +962,8 @@ namespace dxvk {
m_writerQueue.pop();
}
if (!file) {
file = std::ofstream(getCacheFileName().c_str(),
if (!file.is_open()) {
file.open(getCacheFileName().c_str(),
std::ios_base::binary |
std::ios_base::app);
}

View File

@ -302,6 +302,7 @@ namespace dxvk {
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
samplerInfo.borderColor = VkClearColorValue();
samplerInfo.usePixelCoord = VK_TRUE;
samplerInfo.nonSeamless = VK_FALSE;
m_samplerPresent = m_device->createSampler(samplerInfo);
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;

View File

@ -53,6 +53,7 @@ namespace dxvk {
info.compareOp = VK_COMPARE_OP_NEVER;
info.borderColor = VkClearColorValue();
info.usePixelCoord = VK_FALSE;
info.nonSeamless = VK_FALSE;
return dev->createSampler(info);
}

View File

@ -311,6 +311,7 @@ namespace dxvk::hud {
info.compareOp = VK_COMPARE_OP_NEVER;
info.borderColor = VkClearColorValue();
info.usePixelCoord = VK_TRUE;
info.nonSeamless = VK_FALSE;
return m_device->createSampler(info);
}

View File

@ -71,6 +71,7 @@ dxvk_src = files([
'dxvk_device.cpp',
'dxvk_device_filter.cpp',
'dxvk_extensions.cpp',
'dxvk_fence.cpp',
'dxvk_format.cpp',
'dxvk_framebuffer.cpp',
'dxvk_gpu_event.cpp',

View File

@ -296,6 +296,21 @@ namespace dxvk {
{ R"(\\AWayOut(_friend)?\.exe$)", {{
{ "dxgi.maxFrameLatency", "1" },
}} },
/* Garden Warfare 2
Won't start on amd Id without atiadlxx */
{ R"(\\GW2.Main_Win64_Retail\.exe$)", {{
{ "dxgi.customVendorId", "10de" },
}} },
/* DayZ */
{ R"(\\DayZ_x64\.exe$)", {{
{ "d3d11.cachedDynamicResources", "cr" },
}} },
/* Stray - writes to the same UAV every draw, *
* presumably for culling, which doesn't play *
* nicely with D3D11 without vendor libraries */
{ R"(\\Stray-Win64-Shipping\.exe$)", {{
{ "d3d11.ignoreGraphicsBarriers", "True" },
}} },
/**********************************************/
/* D3D9 GAMES */
@ -342,9 +357,13 @@ namespace dxvk {
{ "d3d9.memoryTrackTest", "True" },
}} },
/* Dead Space uses the a NULL render target instead
of a 1x1 one if DF24 is NOT supported */
of a 1x1 one if DF24 is NOT supported
Mouse and physics issues above 60 FPS
Built-in Vsync Locks the game to 30 FPS */
{ R"(\\Dead Space\.exe$)", {{
{ "d3d9.supportDFFormats", "False" },
{ "d3d9.maxFrameRate", "60" },
{ "d3d9.presentInterval", "1" },
}} },
/* Halo CE/HaloPC */
{ R"(\\halo(ce)?\.exe$)", {{
@ -565,6 +584,11 @@ namespace dxvk {
{ R"(\\eoa\.exe$)", {{
{ "d3d9.customVendorId", "10de" },
}} },
/* Beyond Good And Evil *
* Fixes missing sun and light shafts */
{ R"(\\BGE\.exe$)", {{
{ "d3d9.allowDoNotWait", "False" },
}} },
/* Supreme Commander & Forged Alliance Forever */
{ R"(\\(SupremeCommander|ForgedAlliance)\.exe$)", {{
{ "d3d9.floatEmulation", "Strict" },
@ -573,6 +597,30 @@ namespace dxvk {
{ R"(\\swtor\.exe$)", {{
{ "d3d9.forceSamplerTypeSpecConstants", "True" },
}} },
/* Bionic Commando
Physics break at high fps */
{ R"(\\bionic_commando\.exe$)", {{
{ "d3d9.maxFrameRate", "60" },
}} },
/* Port Royale 3 *
* Fixes infinite loading screens */
{ R"(\\PortRoyale3\.exe$)", {{
{ "d3d9.allowDoNotWait", "False" },
}} },
/* Need For Speed 3 modern patch */
{ R"(\\nfs3\.exe$)", {{
{ "d3d9.enableDialogMode", "True" },
}} },
/* Ninja Blade *
* Transparent main character on Nvidia */
{ R"(\\NinjaBlade\.exe$)", {{
{ "d3d9.alphaTestWiggleRoom", "True" },
}} },
/* YS Origin *
* Helps very bad frametimes in some areas */
{ R"(\\yso_win\.exe$)", {{
{ "d3d9.maxFrameLatency", "1" },
}} },
}};

View File

@ -48,7 +48,7 @@ typedef union {
* Hash a single 512-bit block. This is the core of the algorithm.
*/
void
SHA1Transform(uint32_t state[5], const uint8_t buffer[SHA1_BLOCK_LENGTH])
SHA1Transform(uint32_t state[5], const uint8_t* buffer)
{
uint32_t a, b, c, d, e;
uint8_t workspace[SHA1_BLOCK_LENGTH];

View File

@ -28,7 +28,7 @@ typedef struct _SHA1_CTX {
void SHA1Init(SHA1_CTX *);
void SHA1Pad(SHA1_CTX *);
void SHA1Transform(uint32_t [5], const uint8_t [SHA1_BLOCK_LENGTH]);
void SHA1Transform(uint32_t [5], const uint8_t*);
void SHA1Update(SHA1_CTX *, const uint8_t *, size_t);
void SHA1Final(uint8_t [SHA1_DIGEST_LENGTH], SHA1_CTX *);

View File

@ -85,6 +85,7 @@ namespace dxvk::vk {
VULKAN_FN(vkDestroyInstance);
VULKAN_FN(vkEnumerateDeviceExtensionProperties);
VULKAN_FN(vkEnumeratePhysicalDevices);
VULKAN_FN(vkGetPhysicalDeviceExternalSemaphoreProperties);
VULKAN_FN(vkGetPhysicalDeviceFeatures);
VULKAN_FN(vkGetPhysicalDeviceFeatures2);
VULKAN_FN(vkGetPhysicalDeviceFormatProperties);
@ -309,6 +310,12 @@ namespace dxvk::vk {
VULKAN_FN(vkQueuePresentKHR);
#endif
#ifdef VK_KHR_timeline_semaphore
VULKAN_FN(vkGetSemaphoreCounterValueKHR);
VULKAN_FN(vkSignalSemaphoreKHR);
VULKAN_FN(vkWaitSemaphoresKHR);
#endif
#ifdef VK_EXT_conditional_rendering
VULKAN_FN(vkCmdBeginConditionalRenderingEXT);
VULKAN_FN(vkCmdEndConditionalRenderingEXT);
@ -369,6 +376,11 @@ namespace dxvk::vk {
VULKAN_FN(vkGetMemoryWin32HandleKHR);
VULKAN_FN(vkGetMemoryWin32HandlePropertiesKHR);
#endif
#ifdef VK_KHR_external_semaphore_win32
VULKAN_FN(vkGetSemaphoreWin32HandleKHR);
VULKAN_FN(vkImportSemaphoreWin32HandleKHR);
#endif
};
}