mirror of https://github.com/doitsujin/dxvk
Compare commits
37 Commits
Author | SHA1 | Date |
---|---|---|
Philip Rebohle | e4fd5e9e8d | |
Philip Rebohle | 257b075600 | |
Derek Lesho | 73b27a7eab | |
Derek Lesho | 89ab338762 | |
Derek Lesho | 215369900d | |
Philip Rebohle | 513a2610e1 | |
Philip Rebohle | 3bbcacf687 | |
Philip Rebohle | f925560f82 | |
Philip Rebohle | 7264b1164c | |
Philip Rebohle | 87b23ff9a0 | |
Joshua Ashton | f5fe2596e3 | |
Blisto91 | 97ce782c9f | |
Krzysztof Dobrowolski | 93ea382c3e | |
Philip Rebohle | 990b43d51d | |
Blisto91 | de626a7e35 | |
Blisto91 | bc5a4d3f6d | |
Philip Rebohle | 5aa943f475 | |
Philip Rebohle | 40e4ea1fce | |
Philip Rebohle | 7d2c2207fa | |
Robin Kertels | 2c40d49337 | |
Blisto91 | 5f67d0fc89 | |
Philip Rebohle | 05416c3731 | |
Philip Rebohle | 8513ab4d77 | |
Matej Dian | 74abd7b525 | |
Blisto91 | 6a33c5d4f0 | |
Philip Rebohle | 310d70bbf8 | |
Blisto91 | e37bdcf348 | |
Philip Rebohle | aaf0db4c79 | |
Trevonn | 653f00d846 | |
Georg Lehmann | 96b3897fd9 | |
Georg Lehmann | b40a4286e4 | |
Georg Lehmann | cb76b02675 | |
Georg Lehmann | 33f83e9561 | |
Georg Lehmann | 11b94088ad | |
WinterSnowfall | 7ae6564e0d | |
Philip Rebohle | 2f6306815e | |
Philip Rebohle | d1f57e13b7 |
|
@ -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##*/}"
|
||||
|
|
10
dxvk.conf
10
dxvk.conf
|
@ -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
|
@ -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()
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -260,7 +260,7 @@ namespace dxvk {
|
|||
HRESULT STDMETHODCALLTYPE CreateFence(
|
||||
UINT64 InitialValue,
|
||||
D3D11_FENCE_FLAG Flags,
|
||||
REFIID ReturnedInterface,
|
||||
REFIID riid,
|
||||
void** ppFence);
|
||||
|
||||
void STDMETHODCALLTYPE ReadFromSubresource(
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -23,3 +23,5 @@ EXPORTS
|
|||
|
||||
DXVK_RegisterAnnotation @ 28257 NONAME
|
||||
DXVK_UnRegisterAnnotation @ 28258 NONAME
|
||||
|
||||
Direct3D9ForceHybridEnumeration @16 NONAME PRIVATE
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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([
|
||||
|
|
|
@ -98,4 +98,7 @@ extern "C" {
|
|||
dxvk::D3D9GlobalAnnotationList::Instance().UnregisterAnnotator(annotation);
|
||||
}
|
||||
|
||||
DLLEXPORT void __stdcall Direct3D9ForceHybridEnumeration(UINT uHybrid) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,7 +57,8 @@ namespace dxvk {
|
|||
|| BackBufferFormat == D3D9Format::X8R8G8B8
|
||||
|| BackBufferFormat == D3D9Format::A1R5G5B5
|
||||
|| BackBufferFormat == D3D9Format::X1R5G5B5
|
||||
|| BackBufferFormat == D3D9Format::R5G6B5;
|
||||
|| BackBufferFormat == D3D9Format::R5G6B5
|
||||
|| BackBufferFormat == D3D9Format::Unknown;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -157,6 +157,9 @@ namespace dxvk {
|
|||
|
||||
/// Disable direct buffer mapping
|
||||
bool allowDirectBufferMapping;
|
||||
|
||||
/// Don't use non seamless cube maps
|
||||
bool seamlessCubes;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
|||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -38,6 +38,9 @@ namespace dxvk {
|
|||
|
||||
/// Enables unnormalized coordinates
|
||||
VkBool32 usePixelCoord;
|
||||
|
||||
/// Enables non seamless cube map filtering
|
||||
VkBool32 nonSeamless;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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" },
|
||||
}} },
|
||||
}};
|
||||
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue