Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
doitsujin committed Jan 19, 2025
1 parent a71de01 commit a6670dc
Show file tree
Hide file tree
Showing 9 changed files with 545 additions and 15 deletions.
20 changes: 14 additions & 6 deletions src/dxvk/dxvk_cmdlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ namespace dxvk {

VkResult DxvkCommandSubmission::submit(
DxvkDevice* device,
VkQueue queue) {
VkQueue queue,
uint64_t trackedId) {
auto vk = device->vkd();

VkLatencySubmissionPresentIdNV latencyInfo = { VK_STRUCTURE_TYPE_LATENCY_SUBMISSION_PRESENT_ID_NV };
latencyInfo.presentID = trackedId;

VkSubmitInfo2 submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO_2 };

if (!m_semaphoreWaits.empty()) {
Expand All @@ -70,6 +74,9 @@ namespace dxvk {
submitInfo.pSignalSemaphoreInfos = m_semaphoreSignals.data();
}

if (trackedId && device->features().nvLowLatency2)
latencyInfo.pNext = std::exchange(submitInfo.pNext, &latencyInfo);

VkResult vr = VK_SUCCESS;

if (!this->isEmpty())
Expand Down Expand Up @@ -200,7 +207,8 @@ namespace dxvk {

VkResult DxvkCommandList::submit(
const DxvkTimelineSemaphores& semaphores,
DxvkTimelineSemaphoreValues& timelines) {
DxvkTimelineSemaphoreValues& timelines,
uint64_t trackedId) {
VkResult status = VK_SUCCESS;

static const std::array<DxvkCmdBuffer, 2> SdmaCmdBuffers =
Expand Down Expand Up @@ -259,7 +267,7 @@ namespace dxvk {
m_commandSubmission.signalSemaphore(semaphores.transfer,
++timelines.transfer, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);

if ((status = m_commandSubmission.submit(m_device, transfer.queueHandle)))
if ((status = m_commandSubmission.submit(m_device, transfer.queueHandle, trackedId)))
return status;

m_commandSubmission.waitSemaphore(semaphores.transfer,
Expand Down Expand Up @@ -301,7 +309,7 @@ namespace dxvk {
++timelines.graphics, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);

// Finally, submit all graphics commands of the current submission
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle, trackedId)))
return status;

// If there are WSI semaphores involved, do another submit only
Expand All @@ -311,7 +319,7 @@ namespace dxvk {
m_commandSubmission.signalSemaphore(semaphores.graphics,
++timelines.graphics, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);

if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle, trackedId)))
return status;
}

Expand All @@ -321,7 +329,7 @@ namespace dxvk {
m_commandSubmission.waitSemaphore(semaphores.graphics,
timelines.graphics, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);

if (isLast && (status = m_commandSubmission.submit(m_device, transfer.queueHandle)))
if (isLast && (status = m_commandSubmission.submit(m_device, transfer.queueHandle, trackedId)))
return status;
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/dxvk/dxvk_cmdlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,13 @@ namespace dxvk {
*
* \param [in] device DXVK device
* \param [in] queue Queue to submit to
* \param [in] trackedId Latency frame ID
* \returns Submission return value
*/
VkResult submit(
DxvkDevice* device,
VkQueue queue);
VkQueue queue,
uint64_t trackedId);

/**
* \brief Resets object
Expand Down Expand Up @@ -215,11 +217,13 @@ namespace dxvk {
*
* \param [in] semaphores Timeline semaphore pair
* \param [in] timelines Timeline semaphore values
* \param [in] trackedId Latency frame ID
* \returns Submission status
*/
VkResult submit(
const DxvkTimelineSemaphores& semaphores,
DxvkTimelineSemaphoreValues& timelines);
DxvkTimelineSemaphoreValues& timelines,
uint64_t trackedId);

/**
* \brief Stat counters
Expand Down
4 changes: 4 additions & 0 deletions src/dxvk/dxvk_device.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "dxvk_device.h"
#include "dxvk_instance.h"
#include "dxvk_latency_builtin.h"
#include "dxvk_latency_builtin_nv.h"

namespace dxvk {

Expand Down Expand Up @@ -311,6 +312,9 @@ namespace dxvk {
if (m_options.latencySleep != Tristate::True)
return nullptr;

if (m_features.nvLowLatency2)
return new DxvkBuiltInLatencyTrackerNv(presenter);

return new DxvkBuiltInLatencyTracker(
m_options.latencyTolerance);
}
Expand Down
212 changes: 212 additions & 0 deletions src/dxvk/dxvk_latency_builtin_nv.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#include "dxvk_latency_builtin_nv.h"

namespace dxvk {

DxvkBuiltInLatencyTrackerNv::DxvkBuiltInLatencyTrackerNv(
const Rc<Presenter>& presenter)
: m_presenter(presenter) {
auto limit = FpsLimiter::getEnvironmentOverride();

if (limit)
m_envFpsLimit = *limit;
}


DxvkBuiltInLatencyTrackerNv::~DxvkBuiltInLatencyTrackerNv() {
VkLatencySleepModeInfoNV latencyMode = { VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV };
latencyMode.lowLatencyMode = VK_FALSE;
latencyMode.lowLatencyBoost = VK_FALSE;
latencyMode.minimumIntervalUs = 0;

m_presenter->setLatencySleepModeNv(latencyMode);
}


void DxvkBuiltInLatencyTrackerNv::notifyCpuPresentBegin(
uint64_t frameId) {
// Not interesting here
}


void DxvkBuiltInLatencyTrackerNv::notifyCpuPresentEnd(
uint64_t frameId) {
std::unique_lock lock(m_mutex);
auto frame = getFrame(frameId);

if (frame)
frame->presentPending = VK_TRUE;
}


void DxvkBuiltInLatencyTrackerNv::notifyCsRenderBegin(
uint64_t frameId) {
m_presenter->setLatencyMarkerNv(frameId,
VK_LATENCY_MARKER_SIMULATION_END_NV);
m_presenter->setLatencyMarkerNv(frameId,
VK_LATENCY_MARKER_RENDERSUBMIT_START_NV);
}


void DxvkBuiltInLatencyTrackerNv::notifyCsRenderEnd(
uint64_t frameId) {
m_presenter->setLatencyMarkerNv(frameId,
VK_LATENCY_MARKER_RENDERSUBMIT_END_NV);
}


void DxvkBuiltInLatencyTrackerNv::notifyQueueSubmit(
uint64_t frameId) {
// Handled by driver
}


void DxvkBuiltInLatencyTrackerNv::notifyQueuePresentBegin(
uint64_t frameId) {
m_presenter->setLatencyMarkerNv(frameId,
VK_LATENCY_MARKER_PRESENT_START_NV);
}


void DxvkBuiltInLatencyTrackerNv::notifyQueuePresentEnd(
uint64_t frameId,
VkResult status) {
m_presenter->setLatencyMarkerNv(frameId,
VK_LATENCY_MARKER_PRESENT_END_NV);

std::unique_lock lock(m_mutex);
auto frame = getFrame(frameId);

if (frame)
frame->presentResult = status;

m_cond.notify_one();
}


void DxvkBuiltInLatencyTrackerNv::notifyGpuExecutionBegin(
uint64_t frameId) {
// Handled by driver
}


void DxvkBuiltInLatencyTrackerNv::notifyGpuExecutionEnd(
uint64_t frameId) {
// Handled by driver
}


void DxvkBuiltInLatencyTrackerNv::notifyGpuPresentEnd(
uint64_t frameId) {
std::unique_lock lock(m_mutex);
auto frame = getFrame(frameId);

if (frame)
frame->frameEnd = dxvk::high_resolution_clock::now();
}


void DxvkBuiltInLatencyTrackerNv::sleepAndBeginFrame(
uint64_t frameId,
double maxFrameRate) {
bool presentSuccessful = false;

duration sleepDuration(0u);

{ std::unique_lock lock(m_mutex);

// Don't try to sleep if we haven't set up
// low latency mode for the swapchain yet
if (m_lowLatencyEnabled) {
auto curr = getFrame(frameId - 1u);

if (curr && curr->presentPending) {
m_cond.wait(lock, [curr] {
return curr->presentResult != VK_NOT_READY;
});

presentSuccessful = curr->presentResult >= 0;
}
}
}

if (presentSuccessful) {
auto t0 = dxvk::high_resolution_clock::now();
m_presenter->latencySleepNv(frameId - 1u);

sleepDuration += dxvk::high_resolution_clock::now() - t0;
}

{ std::unique_lock lock(m_mutex);
// Set up low latency mode for subsequent frames
VkLatencySleepModeInfoNV latencyMode = { VK_STRUCTURE_TYPE_LATENCY_SLEEP_MODE_INFO_NV };
latencyMode.lowLatencyMode = VK_TRUE;
latencyMode.lowLatencyBoost = VK_TRUE;
latencyMode.minimumIntervalUs = 0;

if (m_envFpsLimit > 0.0)
maxFrameRate = m_envFpsLimit;

if (maxFrameRate > 0.0)
latencyMode.minimumIntervalUs = uint64_t(1'000'000.0 / maxFrameRate);

m_presenter->setLatencySleepModeNv(latencyMode);
m_presenter->setLatencyMarkerNv(frameId,
VK_LATENCY_MARKER_INPUT_SAMPLE_NV);
m_presenter->setLatencyMarkerNv(frameId,
VK_LATENCY_MARKER_SIMULATION_START_NV);

auto next = initFrame(frameId);
next->frameStart = dxvk::high_resolution_clock::now();
next->sleepDuration = sleepDuration;

m_lowLatencyEnabled = true;
}
}


void DxvkBuiltInLatencyTrackerNv::discardTimings() {
std::unique_lock lock(m_mutex);
m_lastDiscard = m_lastFrameId;
}


DxvkLatencyStats DxvkBuiltInLatencyTrackerNv::getStatistics(
uint64_t frameId) {
std::unique_lock lock(m_mutex);

auto frame = getFrame(frameId);

while (frame && frame->frameEnd == time_point())
frame = getFrame(--frameId);

if (!frame)
return DxvkLatencyStats();

DxvkLatencyStats stats = { };
stats.frameLatency = std::chrono::duration_cast<std::chrono::microseconds>(frame->frameEnd - frame->frameStart);
stats.sleepDuration = std::chrono::duration_cast<std::chrono::microseconds>(frame->sleepDuration);
return stats;
}


DxvkLatencyFrameDataNv* DxvkBuiltInLatencyTrackerNv::initFrame(uint64_t frameId) {
auto& frame = m_frames[frameId % FrameCount];

frame = DxvkLatencyFrameDataNv();
frame.frameId = frameId;

m_lastFrameId = frameId;
return &m_frames[frameId % FrameCount];
}


DxvkLatencyFrameDataNv* DxvkBuiltInLatencyTrackerNv::getFrame(uint64_t frameId) {
auto& frame = m_frames[frameId % FrameCount];

if (frameId <= m_lastDiscard || frame.frameId != frameId)
return nullptr;

return &frame;
}

}
Loading

0 comments on commit a6670dc

Please sign in to comment.