Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2518e1c

Browse files
esullivan-nvidiaejsullivan
authored andcommittedOct 24, 2023
Add VK_NV_low_latency2 support
This commit add support for the VK_NV_low_latency2 extension, and implements the ID3DLowLatencyDevice interface.
1 parent e6e806d commit 2518e1c

17 files changed

+563
-46
lines changed
 

‎src/d3d11/d3d11_device.cpp

+153-15
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "d3d11_device.h"
1616
#include "d3d11_fence.h"
1717
#include "d3d11_input_layout.h"
18+
#include "d3d11_interfaces.h"
1819
#include "d3d11_interop.h"
1920
#include "d3d11_query.h"
2021
#include "d3d11_resource.h"
@@ -2469,12 +2470,14 @@ namespace dxvk {
24692470
return deviceFeatures.nvxBinaryImport
24702471
&& deviceFeatures.vk12.bufferDeviceAddress;
24712472

2473+
case D3D11_VK_NV_LOW_LATENCY_2:
2474+
return deviceFeatures.nvLowLatency2;
2475+
24722476
default:
24732477
return false;
24742478
}
24752479
}
2476-
2477-
2480+
24782481
bool STDMETHODCALLTYPE D3D11DeviceExt::GetCudaTextureObjectNVX(uint32_t srvDriverHandle, uint32_t samplerDriverHandle, uint32_t* pCudaTextureHandle) {
24792482
ID3D11ShaderResourceView* srv = HandleToSrvNVX(srvDriverHandle);
24802483

@@ -2783,8 +2786,133 @@ namespace dxvk {
27832786

27842787

27852788

2789+
2790+
D3D11LowLatencyDevice::D3D11LowLatencyDevice(
2791+
D3D11DXGIDevice* pContainer,
2792+
D3D11Device* pDevice)
2793+
: m_container(pContainer), m_device(pDevice) {
2794+
2795+
}
27862796

27872797

2798+
ULONG STDMETHODCALLTYPE D3D11LowLatencyDevice::AddRef() {
2799+
return m_container->AddRef();
2800+
}
2801+
2802+
2803+
ULONG STDMETHODCALLTYPE D3D11LowLatencyDevice::Release() {
2804+
return m_container->Release();
2805+
}
2806+
2807+
2808+
HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::QueryInterface(
2809+
REFIID riid,
2810+
void** ppvObject) {
2811+
return m_container->QueryInterface(riid, ppvObject);
2812+
}
2813+
2814+
BOOL STDMETHODCALLTYPE D3D11LowLatencyDevice::SupportsLowLatency() {
2815+
return m_device->GetDXVKDevice()->features().nvLowLatency2;
2816+
}
2817+
2818+
HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::LatencySleep() {
2819+
if (!m_device->GetDXVKDevice()->features().nvLowLatency2) {
2820+
return E_NOINTERFACE;
2821+
}
2822+
2823+
D3D11SwapChain* pSwapChain = m_device->GetLowLatencySwapChain();
2824+
if (pSwapChain && pSwapChain->LowLatencyEnabled()) {
2825+
VkResult res = pSwapChain->LatencySleep();
2826+
if (res != VK_SUCCESS) {
2827+
return S_FALSE;
2828+
}
2829+
}
2830+
2831+
return S_OK;
2832+
}
2833+
2834+
HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::SetLatencySleepMode(BOOL lowLatencyMode, BOOL lowLatencyBoost, uint32_t minimumIntervalUs) {
2835+
if (!m_device->GetDXVKDevice()->features().nvLowLatency2) {
2836+
return E_NOINTERFACE;
2837+
}
2838+
2839+
D3D11SwapChain* pSwapChain = m_device->GetLowLatencySwapChain();
2840+
if (pSwapChain) {
2841+
VkResult res = pSwapChain->SetLatencySleepMode(lowLatencyMode, lowLatencyBoost, minimumIntervalUs);
2842+
if (res != VK_SUCCESS) {
2843+
return S_FALSE;
2844+
}
2845+
}
2846+
2847+
return S_OK;
2848+
}
2849+
2850+
HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::SetLatencyMarker(uint64_t frameID, uint32_t markerType) {
2851+
if (!m_device->GetDXVKDevice()->features().nvLowLatency2) {
2852+
return E_NOINTERFACE;
2853+
}
2854+
2855+
D3D11SwapChain* pSwapChain = m_device->GetLowLatencySwapChain();
2856+
VkLatencyMarkerNV marker = static_cast<VkLatencyMarkerNV>(markerType);
2857+
uint64_t internalFrameId = frameID + DXGI_MAX_SWAP_CHAIN_BUFFERS;
2858+
2859+
m_device->GetDXVKDevice()->setLatencyMarker(marker, internalFrameId);
2860+
2861+
if (pSwapChain && pSwapChain->LowLatencyEnabled()) {
2862+
pSwapChain->SetLatencyMarker(marker, internalFrameId);
2863+
}
2864+
2865+
return S_OK;
2866+
}
2867+
2868+
HRESULT STDMETHODCALLTYPE D3D11LowLatencyDevice::GetLatencyInfo(D3D11_LATENCY_RESULTS* latencyResults)
2869+
{
2870+
if (!m_device->GetDXVKDevice()->features().nvLowLatency2) {
2871+
return E_NOINTERFACE;
2872+
}
2873+
2874+
constexpr uint32_t frameReportSize = 64;
2875+
D3D11SwapChain* pSwapChain = m_device->GetLowLatencySwapChain();
2876+
2877+
if (pSwapChain && pSwapChain->LowLatencyEnabled()) {
2878+
std::vector<VkLatencyTimingsFrameReportNV> frameReports;
2879+
pSwapChain->GetLatencyTimings(frameReports);
2880+
2881+
if (frameReports.size() >= frameReportSize) {
2882+
for (uint32_t i = 0; i < frameReportSize; i++) {
2883+
VkLatencyTimingsFrameReportNV& frameReport = frameReports[i];
2884+
latencyResults->frame_reports[i].frameID = frameReport.presentID - DXGI_MAX_SWAP_CHAIN_BUFFERS;
2885+
latencyResults->frame_reports[i].inputSampleTime = frameReport.inputSampleTimeUs;
2886+
latencyResults->frame_reports[i].simStartTime = frameReport.simStartTimeUs;
2887+
latencyResults->frame_reports[i].simEndTime = frameReport.simEndTimeUs;
2888+
latencyResults->frame_reports[i].renderSubmitStartTime = frameReport.renderSubmitStartTimeUs;
2889+
latencyResults->frame_reports[i].renderSubmitEndTime = frameReport.renderSubmitEndTimeUs;
2890+
latencyResults->frame_reports[i].presentStartTime = frameReport.presentStartTimeUs;
2891+
latencyResults->frame_reports[i].presentEndTime = frameReport.presentEndTimeUs;
2892+
latencyResults->frame_reports[i].driverStartTime = frameReport.driverStartTimeUs;
2893+
latencyResults->frame_reports[i].driverEndTime = frameReport.driverEndTimeUs;
2894+
latencyResults->frame_reports[i].osRenderQueueStartTime = frameReport.osRenderQueueStartTimeUs;
2895+
latencyResults->frame_reports[i].osRenderQueueEndTime = frameReport.osRenderQueueEndTimeUs;
2896+
latencyResults->frame_reports[i].gpuRenderStartTime = frameReport.gpuRenderStartTimeUs;
2897+
latencyResults->frame_reports[i].gpuRenderEndTime = frameReport.gpuRenderEndTimeUs;
2898+
latencyResults->frame_reports[i].gpuActiveRenderTimeUs =
2899+
frameReport.gpuRenderEndTimeUs - frameReport.gpuRenderStartTimeUs;
2900+
latencyResults->frame_reports[i].gpuFrameTimeUs = 0;
2901+
2902+
if (i) {
2903+
latencyResults->frame_reports[i].gpuFrameTimeUs =
2904+
frameReports[i].gpuRenderEndTimeUs - frameReports[i - 1].gpuRenderEndTimeUs;
2905+
}
2906+
}
2907+
}
2908+
}
2909+
2910+
return S_OK;
2911+
}
2912+
2913+
2914+
2915+
27882916
D3D11VideoDevice::D3D11VideoDevice(
27892917
D3D11DXGIDevice* pContainer,
27902918
D3D11Device* pDevice)
@@ -3021,7 +3149,11 @@ namespace dxvk {
30213149

30223150
Com<D3D11SwapChain> presenter = new D3D11SwapChain(
30233151
m_container, m_device, pSurfaceFactory, pDesc);
3024-
3152+
3153+
if (m_device->GetDXVKDevice()->features().nvLowLatency2) {
3154+
m_device->AddSwapchain(presenter.ref());
3155+
}
3156+
30253157
*ppSwapChain = presenter.ref();
30263158
return S_OK;
30273159
} catch (const DxvkError& e) {
@@ -3078,17 +3210,18 @@ namespace dxvk {
30783210
Rc<DxvkDevice> pDxvkDevice,
30793211
D3D_FEATURE_LEVEL FeatureLevel,
30803212
UINT FeatureFlags)
3081-
: m_dxgiAdapter (pAdapter),
3082-
m_dxvkInstance (pDxvkInstance),
3083-
m_dxvkAdapter (pDxvkAdapter),
3084-
m_dxvkDevice (pDxvkDevice),
3085-
m_d3d11Device (this, FeatureLevel, FeatureFlags),
3086-
m_d3d11DeviceExt(this, &m_d3d11Device),
3087-
m_d3d11Interop (this, &m_d3d11Device),
3088-
m_d3d11Video (this, &m_d3d11Device),
3089-
m_d3d11on12 (this, &m_d3d11Device, pD3D12Device, pD3D12Queue),
3090-
m_metaDevice (this),
3091-
m_dxvkFactory (this, &m_d3d11Device) {
3213+
: m_dxgiAdapter (pAdapter),
3214+
m_dxvkInstance (pDxvkInstance),
3215+
m_dxvkAdapter (pDxvkAdapter),
3216+
m_dxvkDevice (pDxvkDevice),
3217+
m_d3d11Device (this, FeatureLevel, FeatureFlags),
3218+
m_d3d11DeviceExt (this, &m_d3d11Device),
3219+
m_d3d11Interop (this, &m_d3d11Device),
3220+
m_d3dLowLatencyDevice (this, &m_d3d11Device),
3221+
m_d3d11Video (this, &m_d3d11Device),
3222+
m_d3d11on12 (this, &m_d3d11Device, pD3D12Device, pD3D12Queue),
3223+
m_metaDevice (this),
3224+
m_dxvkFactory (this, &m_d3d11Device) {
30923225

30933226
}
30943227

@@ -3142,7 +3275,12 @@ namespace dxvk {
31423275
*ppvObject = ref(&m_d3d11DeviceExt);
31433276
return S_OK;
31443277
}
3145-
3278+
3279+
if (riid == __uuidof(ID3DLowLatencyDevice)) {
3280+
*ppvObject = ref(&m_d3dLowLatencyDevice);
3281+
return S_OK;
3282+
}
3283+
31463284
if (riid == __uuidof(IDXGIDXVKDevice)) {
31473285
*ppvObject = ref(&m_metaDevice);
31483286
return S_OK;

‎src/d3d11/d3d11_device.h

+71-11
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "d3d11_options.h"
2525
#include "d3d11_shader.h"
2626
#include "d3d11_state.h"
27+
#include "d3d11_swapchain.h"
2728
#include "d3d11_util.h"
2829

2930
namespace dxvk {
@@ -428,6 +429,22 @@ namespace dxvk {
428429

429430
bool Is11on12Device() const;
430431

432+
void AddSwapchain(D3D11SwapChain* swapchain) {
433+
m_swapchains.push_back(swapchain);
434+
}
435+
436+
void RemoveSwapchain(D3D11SwapChain* swapchain) {
437+
std::remove(m_swapchains.begin(), m_swapchains.end(), swapchain);
438+
}
439+
440+
UINT GetSwapchainCount() {
441+
return m_swapchains.size();
442+
}
443+
444+
D3D11SwapChain* GetLowLatencySwapChain() {
445+
return (m_swapchains.size()) == 1 ? m_swapchains[0] : nullptr;
446+
}
447+
431448
static D3D_FEATURE_LEVEL GetMaxFeatureLevel(
432449
const Rc<DxvkInstance>& Instance,
433450
const Rc<DxvkAdapter>& Adapter);
@@ -464,6 +481,8 @@ namespace dxvk {
464481
D3D_FEATURE_LEVEL m_maxFeatureLevel;
465482
D3D11DeviceFeatures m_deviceFeatures;
466483

484+
std::vector<D3D11SwapChain*> m_swapchains;
485+
467486
HRESULT CreateShaderModule(
468487
D3D11CommonShader* pShaderModule,
469488
DxvkShaderKey ShaderKey,
@@ -545,28 +564,28 @@ namespace dxvk {
545564
uint64_t* gpuVAStart,
546565
uint64_t* gpuVASize);
547566

548-
bool STDMETHODCALLTYPE CreateUnorderedAccessViewAndGetDriverHandleNVX(
567+
bool STDMETHODCALLTYPE CreateUnorderedAccessViewAndGetDriverHandleNVX(
549568
ID3D11Resource* pResource,
550569
const D3D11_UNORDERED_ACCESS_VIEW_DESC* pDesc,
551570
ID3D11UnorderedAccessView** ppUAV,
552571
uint32_t* pDriverHandle);
553572

554-
bool STDMETHODCALLTYPE CreateShaderResourceViewAndGetDriverHandleNVX(
573+
bool STDMETHODCALLTYPE CreateShaderResourceViewAndGetDriverHandleNVX(
555574
ID3D11Resource* pResource,
556575
const D3D11_SHADER_RESOURCE_VIEW_DESC* pDesc,
557576
ID3D11ShaderResourceView** ppSRV,
558577
uint32_t* pDriverHandle);
559578

560-
bool STDMETHODCALLTYPE CreateSamplerStateAndGetDriverHandleNVX(
579+
bool STDMETHODCALLTYPE CreateSamplerStateAndGetDriverHandleNVX(
561580
const D3D11_SAMPLER_DESC* pSamplerDesc,
562581
ID3D11SamplerState** ppSamplerState,
563582
uint32_t* pDriverHandle);
564-
583+
565584
private:
566585

567586
D3D11DXGIDevice* m_container;
568587
D3D11Device* m_device;
569-
588+
570589
void AddSamplerAndHandleNVX(
571590
ID3D11SamplerState* pSampler,
572591
uint32_t Handle);
@@ -586,6 +605,46 @@ namespace dxvk {
586605
std::unordered_map<uint32_t, ID3D11ShaderResourceView*> m_srvHandleToPtr;
587606
};
588607

608+
/**
609+
* \brief Extended D3D11 device
610+
*/
611+
class D3D11LowLatencyDevice : public ID3DLowLatencyDevice {
612+
613+
public:
614+
615+
D3D11LowLatencyDevice(
616+
D3D11DXGIDevice* pContainer,
617+
D3D11Device* pDevice);
618+
619+
ULONG STDMETHODCALLTYPE AddRef();
620+
621+
ULONG STDMETHODCALLTYPE Release();
622+
623+
HRESULT STDMETHODCALLTYPE QueryInterface(
624+
REFIID riid,
625+
void** ppvObject);
626+
627+
BOOL STDMETHODCALLTYPE SupportsLowLatency();
628+
629+
HRESULT STDMETHODCALLTYPE LatencySleep();
630+
631+
HRESULT STDMETHODCALLTYPE SetLatencySleepMode(
632+
BOOL lowLatencyMode,
633+
BOOL lowLatencyBoost,
634+
uint32_t minimumIntervalUs);
635+
636+
HRESULT STDMETHODCALLTYPE SetLatencyMarker(
637+
uint64_t frameID,
638+
uint32_t markerType);
639+
640+
HRESULT STDMETHODCALLTYPE GetLatencyInfo(
641+
D3D11_LATENCY_RESULTS* latencyResults);
642+
643+
private:
644+
645+
D3D11DXGIDevice* m_container;
646+
D3D11Device* m_device;
647+
};
589648

590649
/**
591650
* \brief D3D11 video device
@@ -856,12 +915,13 @@ namespace dxvk {
856915
Rc<DxvkAdapter> m_dxvkAdapter;
857916
Rc<DxvkDevice> m_dxvkDevice;
858917

859-
D3D11Device m_d3d11Device;
860-
D3D11DeviceExt m_d3d11DeviceExt;
861-
D3D11VkInterop m_d3d11Interop;
862-
D3D11VideoDevice m_d3d11Video;
863-
D3D11on12Device m_d3d11on12;
864-
DXGIDXVKDevice m_metaDevice;
918+
D3D11Device m_d3d11Device;
919+
D3D11DeviceExt m_d3d11DeviceExt;
920+
D3D11VkInterop m_d3d11Interop;
921+
D3D11LowLatencyDevice m_d3dLowLatencyDevice;
922+
D3D11VideoDevice m_d3d11Video;
923+
D3D11on12Device m_d3d11on12;
924+
DXGIDXVKDevice m_metaDevice;
865925

866926
DXGIVkSwapChainFactory m_dxvkFactory;
867927

‎src/d3d11/d3d11_interfaces.h

+57-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ enum D3D11_VK_EXTENSION : uint32_t {
1616
D3D11_VK_EXT_BARRIER_CONTROL = 3,
1717
D3D11_VK_NVX_BINARY_IMPORT = 4,
1818
D3D11_VK_NVX_IMAGE_VIEW_HANDLE = 5,
19+
D3D11_VK_NV_LOW_LATENCY_2 = 6
1920
};
2021

2122

@@ -27,6 +28,33 @@ enum D3D11_VK_BARRIER_CONTROL : uint32_t {
2728
D3D11_VK_BARRIER_CONTROL_IGNORE_GRAPHICS_UAV = 1 << 1,
2829
};
2930

31+
/**
32+
* \brief Frame Report Info
33+
*/
34+
typedef struct D3D11_LATENCY_RESULTS
35+
{
36+
UINT32 version;
37+
struct D3D11_FRAME_REPORT {
38+
UINT64 frameID;
39+
UINT64 inputSampleTime;
40+
UINT64 simStartTime;
41+
UINT64 simEndTime;
42+
UINT64 renderSubmitStartTime;
43+
UINT64 renderSubmitEndTime;
44+
UINT64 presentStartTime;
45+
UINT64 presentEndTime;
46+
UINT64 driverStartTime;
47+
UINT64 driverEndTime;
48+
UINT64 osRenderQueueStartTime;
49+
UINT64 osRenderQueueEndTime;
50+
UINT64 gpuRenderStartTime;
51+
UINT64 gpuRenderEndTime;
52+
UINT32 gpuActiveRenderTimeUs;
53+
UINT32 gpuFrameTimeUs;
54+
UINT8 rsvd[120];
55+
} frame_reports[64];
56+
UINT8 rsvd[32];
57+
} D3D11_LATENCY_RESULTS;
3058

3159
/**
3260
* \brief Extended shader interface
@@ -114,6 +142,33 @@ ID3D11VkExtDevice1 : public ID3D11VkExtDevice {
114142
uint32_t* pCudaTextureHandle) = 0;
115143
};
116144

145+
/**
146+
* \brief Extended extended D3D11 device
147+
*
148+
* Introduces methods to get virtual addresses and driver
149+
* handles for resources, and create and destroy objects
150+
* for D3D11-Cuda interop.
151+
*/
152+
MIDL_INTERFACE("f3112584-41f9-348d-a59b-00b7e1d285d6")
153+
ID3DLowLatencyDevice : public IUnknown {
154+
static const GUID guid;
155+
156+
virtual BOOL STDMETHODCALLTYPE SupportsLowLatency() = 0;
157+
158+
virtual HRESULT STDMETHODCALLTYPE LatencySleep() = 0;
159+
160+
virtual HRESULT STDMETHODCALLTYPE SetLatencySleepMode(
161+
BOOL lowLatencyMode,
162+
BOOL lowLatencyBoost,
163+
uint32_t minimumIntervalUs) = 0;
164+
165+
virtual HRESULT STDMETHODCALLTYPE SetLatencyMarker(
166+
uint64_t frameID,
167+
uint32_t markerType) = 0;
168+
169+
virtual HRESULT STDMETHODCALLTYPE GetLatencyInfo(
170+
D3D11_LATENCY_RESULTS* latencyResults) = 0;
171+
};
117172

118173
/**
119174
* \brief Extended D3D11 context
@@ -182,17 +237,18 @@ ID3D11VkExtContext1 : public ID3D11VkExtContext {
182237
uint32_t numWriteResources) = 0;
183238
};
184239

185-
186240
#ifdef _MSC_VER
187241
struct __declspec(uuid("bb8a4fb9-3935-4762-b44b-35189a26414a")) ID3D11VkExtShader;
188242
struct __declspec(uuid("8a6e3c42-f74c-45b7-8265-a231b677ca17")) ID3D11VkExtDevice;
189243
struct __declspec(uuid("cfcf64ef-9586-46d0-bca4-97cf2ca61b06")) ID3D11VkExtDevice1;
190244
struct __declspec(uuid("fd0bca13-5cb6-4c3a-987e-4750de2ca791")) ID3D11VkExtContext;
191245
struct __declspec(uuid("874b09b2-ae0b-41d8-8476-5f3b7a0e879d")) ID3D11VkExtContext1;
246+
struct __declspec(uuid("f3112584-41f9-348d-a59b-00b7e1d285d6")) ID3DLowLatencyDevice;
192247
#else
193248
__CRT_UUID_DECL(ID3D11VkExtShader, 0xbb8a4fb9,0x3935,0x4762,0xb4,0x4b,0x35,0x18,0x9a,0x26,0x41,0x4a);
194249
__CRT_UUID_DECL(ID3D11VkExtDevice, 0x8a6e3c42,0xf74c,0x45b7,0x82,0x65,0xa2,0x31,0xb6,0x77,0xca,0x17);
195250
__CRT_UUID_DECL(ID3D11VkExtDevice1, 0xcfcf64ef,0x9586,0x46d0,0xbc,0xa4,0x97,0xcf,0x2c,0xa6,0x1b,0x06);
196251
__CRT_UUID_DECL(ID3D11VkExtContext, 0xfd0bca13,0x5cb6,0x4c3a,0x98,0x7e,0x47,0x50,0xde,0x2c,0xa7,0x91);
197252
__CRT_UUID_DECL(ID3D11VkExtContext1, 0x874b09b2,0xae0b,0x41d8,0x84,0x76,0x5f,0x3b,0x7a,0x0e,0x87,0x9d);
253+
__CRT_UUID_DECL(ID3DLowLatencyDevice, 0xf3112584,0x41f9,0x348d,0xa5,0x9b,0x00,0xb7,0xe1,0xd2,0x85,0xd6);
198254
#endif

‎src/d3d11/d3d11_swapchain.cpp

+33-3
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,34 @@ namespace dxvk {
351351
*pFrameStatistics = m_frameStatistics;
352352
}
353353

354+
VkResult D3D11SwapChain::SetLatencySleepMode(
355+
bool lowLatencyMode,
356+
bool lowLatencyBoost,
357+
uint32_t minimumIntervalUs) {
358+
if (lowLatencyMode && !LowLatencyEnabled()) {
359+
RecreateSwapChain();
360+
}
361+
return m_presenter->setLatencySleepMode(lowLatencyMode, lowLatencyBoost, minimumIntervalUs);
362+
}
363+
364+
VkResult D3D11SwapChain::LatencySleep() {
365+
return m_presenter->latencySleep();
366+
}
367+
368+
void D3D11SwapChain::SetLatencyMarker(
369+
VkLatencyMarkerNV marker,
370+
uint64_t presentId) {
371+
m_presenter->setLatencyMarker(marker, presentId);
372+
}
373+
374+
VkResult D3D11SwapChain::GetLatencyTimings(
375+
std::vector<VkLatencyTimingsFrameReportNV>& frameReports) {
376+
return m_presenter->getLatencyTimings(frameReports);
377+
}
378+
379+
bool D3D11SwapChain::LowLatencyEnabled() {
380+
return m_presenter->lowLatencyEnabled();
381+
}
354382

355383
HRESULT D3D11SwapChain::PresentImage(UINT SyncInterval) {
356384
// Flush pending rendering commands before
@@ -410,9 +438,11 @@ namespace dxvk {
410438
uint32_t Repeat) {
411439
auto lock = pContext->LockContext();
412440

413-
// Bump frame ID as necessary
414-
if (!Repeat)
415-
m_frameId += 1;
441+
if (!Repeat) {
442+
m_frameId = (m_presenter->lowLatencyEnabled() && m_device->getLatencyMarkers().present) ?
443+
m_device->getLatencyMarkers().present :
444+
m_frameId + 1;
445+
}
416446

417447
// Present from CS thread so that we don't
418448
// have to synchronize with it first.

‎src/d3d11/d3d11_swapchain.h

+17-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,22 @@ namespace dxvk {
8686
void STDMETHODCALLTYPE GetFrameStatistics(
8787
DXGI_VK_FRAME_STATISTICS* pFrameStatistics);
8888

89+
VkResult SetLatencySleepMode(
90+
bool lowLatencyMode,
91+
bool lowLatencyBoost,
92+
uint32_t minimumIntervalUs);
93+
94+
VkResult LatencySleep();
95+
96+
void SetLatencyMarker(
97+
VkLatencyMarkerNV marker,
98+
uint64_t presentId);
99+
100+
VkResult GetLatencyTimings(
101+
std::vector<VkLatencyTimingsFrameReportNV>& frameReports);
102+
103+
bool LowLatencyEnabled();
104+
89105
private:
90106

91107
enum BindingIds : uint32_t {
@@ -176,4 +192,4 @@ namespace dxvk {
176192

177193
};
178194

179-
}
195+
}

‎src/dxvk/dxvk_adapter.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,9 @@ namespace dxvk {
927927
m_deviceFeatures.khrPresentWait.pNext = std::exchange(m_deviceFeatures.core.pNext, &m_deviceFeatures.khrPresentWait);
928928
}
929929

930+
if (m_deviceExtensions.supports(VK_NV_LOW_LATENCY_2_EXTENSION_NAME))
931+
m_deviceFeatures.nvLowLatency2 = VK_TRUE;
932+
930933
if (m_deviceExtensions.supports(VK_NVX_BINARY_IMPORT_EXTENSION_NAME))
931934
m_deviceFeatures.nvxBinaryImport = VK_TRUE;
932935

@@ -994,6 +997,7 @@ namespace dxvk {
994997
&devExtensions.khrPresentWait,
995998
&devExtensions.khrSwapchain,
996999
&devExtensions.khrWin32KeyedMutex,
1000+
&devExtensions.nvLowLatency2,
9971001
&devExtensions.nvxBinaryImport,
9981002
&devExtensions.nvxImageViewHandle,
9991003
}};
@@ -1133,8 +1137,13 @@ namespace dxvk {
11331137
enabledFeatures.khrPresentWait.pNext = std::exchange(enabledFeatures.core.pNext, &enabledFeatures.khrPresentWait);
11341138
}
11351139

1136-
if (devExtensions.nvxBinaryImport)
1140+
if (devExtensions.nvxBinaryImport) {
11371141
enabledFeatures.nvxBinaryImport = VK_TRUE;
1142+
}
1143+
1144+
if (devExtensions.nvLowLatency2) {
1145+
enabledFeatures.nvLowLatency2 = VK_TRUE;
1146+
}
11381147

11391148
if (devExtensions.nvxImageViewHandle)
11401149
enabledFeatures.nvxImageViewHandle = VK_TRUE;
@@ -1279,6 +1288,8 @@ namespace dxvk {
12791288
"\n presentId : ", features.khrPresentId.presentId ? "1" : "0",
12801289
"\n", VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
12811290
"\n presentWait : ", features.khrPresentWait.presentWait ? "1" : "0",
1291+
"\n", VK_NV_LOW_LATENCY_2_EXTENSION_NAME,
1292+
"\n extension supported : ", features.nvLowLatency2 ? "1" : "0",
12821293
"\n", VK_NVX_BINARY_IMPORT_EXTENSION_NAME,
12831294
"\n extension supported : ", features.nvxBinaryImport ? "1" : "0",
12841295
"\n", VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME,

‎src/dxvk/dxvk_cmdlist.cpp

+12-5
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,12 @@ namespace dxvk {
5656

5757
VkResult DxvkCommandSubmission::submit(
5858
DxvkDevice* device,
59-
VkQueue queue) {
59+
VkQueue queue,
60+
uint64_t frameId) {
6061
auto vk = device->vkd();
6162

6263
VkSubmitInfo2 submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO_2 };
64+
VkLatencySubmissionPresentIdNV latencySubmitInfo = { VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV };
6365

6466
if (!m_semaphoreWaits.empty()) {
6567
submitInfo.waitSemaphoreInfoCount = m_semaphoreWaits.size();
@@ -76,6 +78,11 @@ namespace dxvk {
7678
submitInfo.pSignalSemaphoreInfos = m_semaphoreSignals.data();
7779
}
7880

81+
if (device->features().nvLowLatency2 && frameId && !m_commandBuffers.empty()) {
82+
latencySubmitInfo.presentID = frameId;
83+
latencySubmitInfo.pNext = std::exchange(submitInfo.pNext, &latencySubmitInfo);
84+
}
85+
7986
VkResult vr = VK_SUCCESS;
8087

8188
if (!this->isEmpty())
@@ -206,7 +213,7 @@ namespace dxvk {
206213
}
207214

208215

209-
VkResult DxvkCommandList::submit() {
216+
VkResult DxvkCommandList::submit(uint64_t frameId) {
210217
VkResult status = VK_SUCCESS;
211218

212219
const auto& graphics = m_device->queues().graphics;
@@ -238,7 +245,7 @@ namespace dxvk {
238245
// for any prior submissions, then block any subsequent ones
239246
m_commandSubmission.signalSemaphore(m_bindSemaphore, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
240247

241-
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
248+
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle, frameId)))
242249
return status;
243250

244251
sparseBind->waitSemaphore(m_bindSemaphore, 0);
@@ -259,7 +266,7 @@ namespace dxvk {
259266
if (m_device->hasDedicatedTransferQueue() && !m_commandSubmission.isEmpty()) {
260267
m_commandSubmission.signalSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
261268

262-
if ((status = m_commandSubmission.submit(m_device, transfer.queueHandle)))
269+
if ((status = m_commandSubmission.submit(m_device, transfer.queueHandle, frameId)))
263270
return status;
264271

265272
m_commandSubmission.waitSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
@@ -297,7 +304,7 @@ namespace dxvk {
297304
}
298305

299306
// Finally, submit all graphics commands of the current submission
300-
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
307+
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle, frameId)))
301308
return status;
302309
}
303310

‎src/dxvk/dxvk_cmdlist.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ namespace dxvk {
9494
*/
9595
VkResult submit(
9696
DxvkDevice* device,
97-
VkQueue queue);
97+
VkQueue queue,
98+
uint64_t frameId);
9899

99100
/**
100101
* \brief Resets object
@@ -199,7 +200,7 @@ namespace dxvk {
199200
* \brief Submits command list
200201
* \returns Submission status
201202
*/
202-
VkResult submit();
203+
VkResult submit(uint64_t frameId);
203204

204205
/**
205206
* \brief Stat counters

‎src/dxvk/dxvk_device.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace dxvk {
1818
m_properties (adapter->devicePropertiesExt()),
1919
m_perfHints (getPerfHints()),
2020
m_objects (this),
21+
m_latencyMarkers ({}),
2122
m_queues (queues),
2223
m_submissionQueue (this, queueCallback) {
2324

@@ -274,6 +275,7 @@ namespace dxvk {
274275
DxvkSubmitStatus* status) {
275276
DxvkSubmitInfo submitInfo = { };
276277
submitInfo.cmdList = commandList;
278+
submitInfo.frameId = m_latencyMarkers.render;
277279
m_submissionQueue.submit(submitInfo, status);
278280

279281
std::lock_guard<sync::Spinlock> statLock(m_statLock);

‎src/dxvk/dxvk_device.h

+50-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,16 @@ namespace dxvk {
6666
DxvkDeviceQueue transfer;
6767
DxvkDeviceQueue sparse;
6868
};
69-
69+
70+
/**
71+
* \brief Latency marker frame ids
72+
*/
73+
struct DxvkDeviceLowLatencyMarkers {
74+
uint64_t simulation;
75+
uint64_t render;
76+
uint64_t present;
77+
};
78+
7079
/**
7180
* \brief DXVK device
7281
*
@@ -534,6 +543,44 @@ namespace dxvk {
534543
* used by the GPU can be safely destroyed.
535544
*/
536545
void waitForIdle();
546+
547+
/**
548+
* \brief Updates the frame id for the given frame marker
549+
*
550+
* \param [in] marker The marker to set the frame ID for
551+
* \param [in] id The frame ID to set
552+
*/
553+
void setLatencyMarker(VkLatencyMarkerNV marker, uint64_t id) {
554+
switch (marker) {
555+
case VK_LATENCY_MARKER_SIMULATION_START_NV:
556+
m_latencyMarkers.simulation = id;
557+
break;
558+
case VK_LATENCY_MARKER_RENDERSUBMIT_START_NV:
559+
m_latencyMarkers.render = id;
560+
break;
561+
case VK_LATENCY_MARKER_PRESENT_START_NV:
562+
m_latencyMarkers.present = id;
563+
break;
564+
default:
565+
break;
566+
}
567+
}
568+
569+
/**
570+
* \brief Resets the latency markers back to zero
571+
*/
572+
void resetLatencyMarkers() {
573+
m_latencyMarkers = {};
574+
}
575+
576+
/**
577+
* \brief Returns the current set of latency marker frame IDs
578+
*
579+
* \returns The current set of frame marker IDs
580+
*/
581+
DxvkDeviceLowLatencyMarkers getLatencyMarkers() {
582+
return m_latencyMarkers;
583+
}
537584

538585
private:
539586

@@ -549,6 +596,8 @@ namespace dxvk {
549596
DxvkDevicePerfHints m_perfHints;
550597
DxvkObjects m_objects;
551598

599+
DxvkDeviceLowLatencyMarkers m_latencyMarkers;
600+
552601
sync::Spinlock m_statLock;
553602
DxvkStatCounters m_statCounters;
554603

‎src/dxvk/dxvk_device_info.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@ namespace dxvk {
6868
VkPhysicalDeviceMaintenance5FeaturesKHR khrMaintenance5;
6969
VkPhysicalDevicePresentIdFeaturesKHR khrPresentId;
7070
VkPhysicalDevicePresentWaitFeaturesKHR khrPresentWait;
71+
VkBool32 nvLowLatency2;
7172
VkBool32 nvxBinaryImport;
7273
VkBool32 nvxImageViewHandle;
7374
VkBool32 khrWin32KeyedMutex;
7475
};
7576

76-
}
77+
}

‎src/dxvk/dxvk_extensions.h

+1
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ namespace dxvk {
325325
DxvkExt khrPresentWait = { VK_KHR_PRESENT_WAIT_EXTENSION_NAME, DxvkExtMode::Optional };
326326
DxvkExt khrSwapchain = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, DxvkExtMode::Required };
327327
DxvkExt khrWin32KeyedMutex = { VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME, DxvkExtMode::Optional };
328+
DxvkExt nvLowLatency2 = { VK_NV_LOW_LATENCY_2_EXTENSION_NAME, DxvkExtMode::Optional };
328329
DxvkExt nvxBinaryImport = { VK_NVX_BINARY_IMPORT_EXTENSION_NAME, DxvkExtMode::Disabled };
329330
DxvkExt nvxImageViewHandle = { VK_NVX_IMAGE_VIEW_HANDLE_EXTENSION_NAME, DxvkExtMode::Disabled };
330331
};

‎src/dxvk/dxvk_presenter.cpp

+96-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ namespace dxvk {
1818
// with present operations and periodically signals the event
1919
if (m_device->features().khrPresentWait.presentWait && m_signal != nullptr)
2020
m_frameThread = dxvk::thread([this] { runFrameThread(); });
21+
22+
// If nvLowLatency2 is supported create the fence
23+
if (m_device->features().nvLowLatency2) {
24+
DxvkFenceCreateInfo info = {};
25+
info.initialValue = 0;
26+
info.sharedType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
27+
28+
m_lowLatencyFence = DxvkFenceValuePair(m_device->createFence(info), 0u);
29+
}
2130
}
2231

2332

@@ -48,6 +57,7 @@ namespace dxvk {
4857

4958

5059
VkResult Presenter::acquireNextImage(PresenterSync& sync, uint32_t& index) {
60+
std::lock_guard<dxvk::mutex> lock(m_lowLatencyMutex);
5161
sync = m_semaphores.at(m_frameIndex);
5262

5363
// Don't acquire more than one image at a time
@@ -68,11 +78,13 @@ namespace dxvk {
6878
VkResult Presenter::presentImage(
6979
VkPresentModeKHR mode,
7080
uint64_t frameId) {
81+
std::lock_guard<dxvk::mutex> lock(m_lowLatencyMutex);
82+
7183
PresenterSync sync = m_semaphores.at(m_frameIndex);
7284

7385
VkPresentIdKHR presentId = { VK_STRUCTURE_TYPE_PRESENT_ID_KHR };
7486
presentId.swapchainCount = 1;
75-
presentId.pPresentIds = &frameId;
87+
presentId.pPresentIds = &frameId;
7688

7789
VkSwapchainPresentModeInfoEXT modeInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT };
7890
modeInfo.swapchainCount = 1;
@@ -151,6 +163,8 @@ namespace dxvk {
151163

152164

153165
VkResult Presenter::recreateSwapChain(const PresenterDesc& desc) {
166+
std::lock_guard<dxvk::mutex> lock(m_lowLatencyMutex);
167+
154168
if (m_swapchain)
155169
destroySwapchain();
156170

@@ -293,6 +307,9 @@ namespace dxvk {
293307
modeInfo.presentModeCount = compatibleModes.size();
294308
modeInfo.pPresentModes = compatibleModes.data();
295309

310+
VkSwapchainLatencyCreateInfoNV lowLatencyInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_LATENCY_CREATE_INFO_NV };
311+
lowLatencyInfo.latencyModeEnable = VK_TRUE;
312+
296313
VkSwapchainCreateInfoKHR swapInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
297314
swapInfo.surface = m_surface;
298315
swapInfo.minImageCount = m_info.imageCount;
@@ -314,6 +331,9 @@ namespace dxvk {
314331
if (m_device->features().extSwapchainMaintenance1.swapchainMaintenance1)
315332
modeInfo.pNext = std::exchange(swapInfo.pNext, &modeInfo);
316333

334+
if (m_device->features().nvLowLatency2)
335+
lowLatencyInfo.pNext = std::exchange(swapInfo.pNext, &lowLatencyInfo);
336+
317337
Logger::info(str::format(
318338
"Presenter: Actual swap chain properties:"
319339
"\n Format: ", m_info.format.format,
@@ -322,11 +342,21 @@ namespace dxvk {
322342
"\n Buffer size: ", m_info.imageExtent.width, "x", m_info.imageExtent.height,
323343
"\n Image count: ", m_info.imageCount,
324344
"\n Exclusive FS: ", desc.fullScreenExclusive));
325-
345+
326346
if ((status = m_vkd->vkCreateSwapchainKHR(m_vkd->device(),
327347
&swapInfo, nullptr, &m_swapchain)))
328348
return status;
329-
349+
350+
if (m_device->features().nvLowLatency2) {
351+
VkLatencySleepModeInfoNV sleepModeInfo = { VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV };
352+
sleepModeInfo.lowLatencyMode = m_lowLatencyEnabled;
353+
sleepModeInfo.lowLatencyBoost = m_lowLatencyBoost;
354+
sleepModeInfo.minimumIntervalUs = m_minimumIntervalUs;
355+
356+
if ((status = m_vkd->vkSetLatencySleepModeNV(m_vkd->device(), m_swapchain, &sleepModeInfo)))
357+
return status;
358+
}
359+
330360
// Acquire images and create views
331361
std::vector<VkImage> images;
332362

@@ -422,6 +452,69 @@ namespace dxvk {
422452
m_vkd->vkSetHdrMetadataEXT(m_vkd->device(), 1, &m_swapchain, &hdrMetadata);
423453
}
424454

455+
VkResult Presenter::setLatencySleepMode(bool lowLatencyMode, bool lowLatencyBoost, uint32_t minimumIntervalUs) {
456+
VkLatencySleepModeInfoNV sleepModeInfo = { VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV };
457+
sleepModeInfo.lowLatencyMode = lowLatencyMode;
458+
sleepModeInfo.lowLatencyBoost = lowLatencyBoost;
459+
sleepModeInfo.minimumIntervalUs = minimumIntervalUs;
460+
461+
std::lock_guard<dxvk::mutex> lock(m_lowLatencyMutex);
462+
VkResult status = m_vkd->vkSetLatencySleepModeNV(m_vkd->device(), m_swapchain, &sleepModeInfo);
463+
464+
m_lowLatencyEnabled = lowLatencyMode;
465+
m_lowLatencyBoost = lowLatencyBoost;
466+
m_minimumIntervalUs = minimumIntervalUs;
467+
468+
if (!lowLatencyMode)
469+
m_device->resetLatencyMarkers();
470+
471+
return status;
472+
}
473+
474+
VkResult Presenter::latencySleep() {
475+
VkSemaphore sem = m_lowLatencyFence.fence->handle();
476+
uint64_t waitValue = m_lowLatencyFence.value + 1;
477+
m_lowLatencyFence.value++;
478+
479+
VkLatencySleepInfoNV sleepInfo = { VK_STRUCTURE_TYPE_LATENCY_SLEEP_INFO_NV };
480+
sleepInfo.signalSemaphore = sem;
481+
sleepInfo.value = waitValue;
482+
483+
{
484+
std::lock_guard<dxvk::mutex> lock(m_lowLatencyMutex);
485+
m_vkd->vkLatencySleepNV(m_vkd->device(), m_swapchain, &sleepInfo);
486+
}
487+
488+
m_lowLatencyFence.fence->wait(waitValue);
489+
490+
return VK_SUCCESS;
491+
}
492+
493+
void Presenter::setLatencyMarker(VkLatencyMarkerNV marker, uint64_t presentId) {
494+
VkSetLatencyMarkerInfoNV markerInfo = { VK_STRUCTURE_TYPE_SET_LATENCY_MARKER_INFO_NV };
495+
markerInfo.presentID = presentId;
496+
markerInfo.marker = marker;
497+
498+
std::lock_guard<dxvk::mutex> lock(m_lowLatencyMutex);
499+
m_vkd->vkSetLatencyMarkerNV(m_vkd->device(), m_swapchain, &markerInfo);
500+
}
501+
502+
VkResult Presenter::getLatencyTimings(std::vector<VkLatencyTimingsFrameReportNV>& frameReports) {
503+
VkGetLatencyMarkerInfoNV markerInfo = { VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV };
504+
uint32_t timingCount = 0;
505+
506+
std::lock_guard<dxvk::mutex> lock(m_lowLatencyMutex);
507+
m_vkd->vkGetLatencyTimingsNV(m_vkd->device(), m_swapchain, &timingCount, &markerInfo);
508+
509+
if (timingCount != 0) {
510+
frameReports.resize(timingCount, { VK_STRUCTURE_TYPE_GET_LATENCY_MARKER_INFO_NV });
511+
markerInfo.pTimings = frameReports.data();
512+
513+
m_vkd->vkGetLatencyTimingsNV(m_vkd->device(), m_swapchain, &timingCount, &markerInfo);
514+
}
515+
516+
return VK_SUCCESS;
517+
}
425518

426519
VkResult Presenter::getSupportedFormats(std::vector<VkSurfaceFormatKHR>& formats, VkFullScreenExclusiveEXT fullScreenExclusive) const {
427520
uint32_t numFormats = 0;

‎src/dxvk/dxvk_presenter.h

+43
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "../vulkan/vulkan_loader.h"
1616

1717
#include "dxvk_format.h"
18+
#include "dxvk_fence.h"
1819

1920
namespace dxvk {
2021

@@ -224,6 +225,42 @@ namespace dxvk {
224225
*/
225226
void setHdrMetadata(const VkHdrMetadataEXT& hdrMetadata);
226227

228+
/**
229+
* \brief Set the latency mode of the swapchain
230+
*
231+
* \param [in] enableLowLatency Determines if the low latency
232+
* mode should be enabled of disabled
233+
*/
234+
VkResult setLatencySleepMode(bool lowLatencyMode, bool lowLatencyBoost, uint32_t minimumIntervalUs);
235+
236+
/**
237+
* \brief Delay rendering work for lower latency
238+
*/
239+
VkResult latencySleep();
240+
241+
/**
242+
* \brief Set a latency marker for the given stage
243+
*
244+
* \param [in] marker The stage this marker is for
245+
* \param [in] presentId The presentId this marker is for
246+
*/
247+
void setLatencyMarker(VkLatencyMarkerNV marker, uint64_t presentId);
248+
249+
/**
250+
* \brief Get the low latency timing info
251+
*
252+
* \param [out] latencyInfo The structure to place
253+
* the latency timings into
254+
*/
255+
VkResult getLatencyTimings(std::vector<VkLatencyTimingsFrameReportNV>& frameReports);
256+
257+
/**
258+
* \brief Returns the low latency enabled state
259+
*/
260+
bool lowLatencyEnabled() {
261+
return m_lowLatencyEnabled;
262+
}
263+
227264
private:
228265

229266
Rc<DxvkDevice> m_device;
@@ -237,6 +274,11 @@ namespace dxvk {
237274
VkSurfaceKHR m_surface = VK_NULL_HANDLE;
238275
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
239276

277+
DxvkFenceValuePair m_lowLatencyFence = {};
278+
bool m_lowLatencyEnabled = false;
279+
bool m_lowLatencyBoost = false;
280+
uint32_t m_minimumIntervalUs = 0;
281+
240282
std::vector<PresenterImage> m_images;
241283
std::vector<PresenterSync> m_semaphores;
242284

@@ -250,6 +292,7 @@ namespace dxvk {
250292
FpsLimiter m_fpsLimiter;
251293

252294
dxvk::mutex m_frameMutex;
295+
dxvk::mutex m_lowLatencyMutex;
253296
dxvk::condition_variable m_frameCond;
254297
dxvk::thread m_frameThread;
255298
std::queue<PresenterFrame> m_frameQueue;

‎src/dxvk/dxvk_queue.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ namespace dxvk {
126126
m_callback(true);
127127

128128
if (entry.submit.cmdList != nullptr)
129-
entry.result = entry.submit.cmdList->submit();
129+
entry.result = entry.submit.cmdList->submit(entry.submit.frameId);
130130
else if (entry.present.presenter != nullptr)
131131
entry.result = entry.present.presenter->presentImage(entry.present.presentMode, entry.present.frameId);
132132

@@ -226,4 +226,4 @@ namespace dxvk {
226226
}
227227
}
228228

229-
}
229+
}

‎src/dxvk/dxvk_queue.h

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace dxvk {
3232
*/
3333
struct DxvkSubmitInfo {
3434
Rc<DxvkCommandList> cmdList;
35+
uint64_t frameId;
3536
};
3637

3738

‎src/vulkan/vulkan_loader.h

+8
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,14 @@ namespace dxvk::vk {
452452
VULKAN_FN(wine_vkAcquireKeyedMutex);
453453
VULKAN_FN(wine_vkReleaseKeyedMutex);
454454
#endif
455+
456+
#ifdef VK_NV_LOW_LATENCY_2_EXTENSION_NAME
457+
VULKAN_FN(vkSetLatencySleepModeNV);
458+
VULKAN_FN(vkLatencySleepNV);
459+
VULKAN_FN(vkSetLatencyMarkerNV);
460+
VULKAN_FN(vkGetLatencyTimingsNV);
461+
VULKAN_FN(vkQueueNotifyOutOfBandNV);
462+
#endif
455463
};
456464

457465
}

0 commit comments

Comments
 (0)
Please sign in to comment.