1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-02 19:24:12 +01:00

[dxvk] Move fence object into DxvkCommandList

Reduces command submission overhead by reusing fence objects
instead of creating new ones for each submission. Improves
error reporting in case the submission cannot be complete.
This commit is contained in:
Philip Rebohle 2018-03-22 18:57:33 +01:00
parent d9b1995cf0
commit 0bdae4f930
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
6 changed files with 84 additions and 48 deletions

View File

@ -1,4 +1,5 @@
#include "dxvk_cmdlist.h" #include "dxvk_cmdlist.h"
#include "dxvk_device.h"
namespace dxvk { namespace dxvk {
@ -6,7 +7,17 @@ namespace dxvk {
const Rc<vk::DeviceFn>& vkd, const Rc<vk::DeviceFn>& vkd,
DxvkDevice* device, DxvkDevice* device,
uint32_t queueFamily) uint32_t queueFamily)
: m_vkd(vkd), m_descAlloc(vkd), m_stagingAlloc(device) { : m_vkd (vkd),
m_descAlloc (vkd),
m_stagingAlloc(device) {
VkFenceCreateInfo fenceInfo;
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceInfo.pNext = nullptr;
fenceInfo.flags = 0;
if (m_vkd->vkCreateFence(m_vkd->device(), &fenceInfo, nullptr, &m_fence) != VK_SUCCESS)
throw DxvkError("DxvkFence::DxvkFence: Failed to create fence");
VkCommandPoolCreateInfo poolInfo; VkCommandPoolCreateInfo poolInfo;
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
poolInfo.pNext = nullptr; poolInfo.pNext = nullptr;
@ -29,18 +40,18 @@ namespace dxvk {
DxvkCommandList::~DxvkCommandList() { DxvkCommandList::~DxvkCommandList() {
this->synchronize();
this->reset(); this->reset();
m_vkd->vkDestroyCommandPool( m_vkd->vkDestroyCommandPool(m_vkd->device(), m_pool, nullptr);
m_vkd->device(), m_pool, nullptr); m_vkd->vkDestroyFence (m_vkd->device(), m_fence, nullptr);
} }
void DxvkCommandList::submit( VkResult DxvkCommandList::submit(
VkQueue queue, VkQueue queue,
VkSemaphore waitSemaphore, VkSemaphore waitSemaphore,
VkSemaphore wakeSemaphore, VkSemaphore wakeSemaphore) {
VkFence fence) {
const VkPipelineStageFlags waitStageMask const VkPipelineStageFlags waitStageMask
= VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
@ -55,8 +66,20 @@ namespace dxvk {
info.signalSemaphoreCount = wakeSemaphore == VK_NULL_HANDLE ? 0 : 1; info.signalSemaphoreCount = wakeSemaphore == VK_NULL_HANDLE ? 0 : 1;
info.pSignalSemaphores = &wakeSemaphore; info.pSignalSemaphores = &wakeSemaphore;
if (m_vkd->vkQueueSubmit(queue, 1, &info, fence) != VK_SUCCESS) return m_vkd->vkQueueSubmit(queue, 1, &info, m_fence);
throw DxvkError("DxvkDevice::submitCommandList: Command submission failed"); }
VkResult DxvkCommandList::synchronize() {
VkResult status = VK_TIMEOUT;
while (status == VK_TIMEOUT) {
status = m_vkd->vkWaitForFences(
m_vkd->device(), 1, &m_fence, VK_FALSE,
1'000'000'000ull);
}
return status;
} }
@ -68,16 +91,19 @@ namespace dxvk {
info.pInheritanceInfo = nullptr; info.pInheritanceInfo = nullptr;
if (m_vkd->vkResetCommandPool(m_vkd->device(), m_pool, 0) != VK_SUCCESS) if (m_vkd->vkResetCommandPool(m_vkd->device(), m_pool, 0) != VK_SUCCESS)
throw DxvkError("DxvkCommandList::beginRecording: Failed to reset command pool"); Logger::err("DxvkCommandList: Failed to reset command buffer");
if (m_vkd->vkBeginCommandBuffer(m_buffer, &info) != VK_SUCCESS) if (m_vkd->vkBeginCommandBuffer(m_buffer, &info) != VK_SUCCESS)
throw DxvkError("DxvkCommandList::beginRecording: Failed to begin command buffer recording"); Logger::err("DxvkCommandList: Failed to begin command buffer");
if (m_vkd->vkResetFences(m_vkd->device(), 1, &m_fence) != VK_SUCCESS)
Logger::err("DxvkCommandList: Failed to reset fence");
} }
void DxvkCommandList::endRecording() { void DxvkCommandList::endRecording() {
if (m_vkd->vkEndCommandBuffer(m_buffer) != VK_SUCCESS) if (m_vkd->vkEndCommandBuffer(m_buffer) != VK_SUCCESS)
throw DxvkError("DxvkCommandList::endRecording: Failed to record command buffer"); Logger::err("DxvkCommandList::endRecording: Failed to record command buffer");
} }

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <unordered_set> #include <limits>
#include "dxvk_binding.h" #include "dxvk_binding.h"
#include "dxvk_buffer.h" #include "dxvk_buffer.h"
@ -11,6 +11,7 @@
#include "dxvk_pipelayout.h" #include "dxvk_pipelayout.h"
#include "dxvk_query_tracker.h" #include "dxvk_query_tracker.h"
#include "dxvk_staging.h" #include "dxvk_staging.h"
#include "dxvk_sync.h"
namespace dxvk { namespace dxvk {
@ -39,13 +40,21 @@ namespace dxvk {
* \param [in] queue Device queue * \param [in] queue Device queue
* \param [in] waitSemaphore Semaphore to wait on * \param [in] waitSemaphore Semaphore to wait on
* \param [in] wakeSemaphore Semaphore to signal * \param [in] wakeSemaphore Semaphore to signal
* \param [in] fence Fence to signal * \returns Submission status
*/ */
void submit( VkResult submit(
VkQueue queue, VkQueue queue,
VkSemaphore waitSemaphore, VkSemaphore waitSemaphore,
VkSemaphore wakeSemaphore, VkSemaphore wakeSemaphore);
VkFence fence);
/**
* \brief Synchronizes command buffer execution
*
* Waits for the fence associated with
* this command buffer to get signaled.
* \returns Synchronization status
*/
VkResult synchronize();
/** /**
* \brief Begins recording * \brief Begins recording
@ -143,7 +152,6 @@ namespace dxvk {
*/ */
void reset(); void reset();
VkDescriptorSet allocateDescriptorSet( VkDescriptorSet allocateDescriptorSet(
VkDescriptorSetLayout descriptorLayout) { VkDescriptorSetLayout descriptorLayout) {
return m_descAlloc.alloc(descriptorLayout); return m_descAlloc.alloc(descriptorLayout);
@ -517,6 +525,8 @@ namespace dxvk {
Rc<vk::DeviceFn> m_vkd; Rc<vk::DeviceFn> m_vkd;
VkFence m_fence;
VkCommandPool m_pool; VkCommandPool m_pool;
VkCommandBuffer m_buffer; VkCommandBuffer m_buffer;

View File

@ -209,12 +209,10 @@ namespace dxvk {
} }
Rc<DxvkFence> DxvkDevice::submitCommandList( void DxvkDevice::submitCommandList(
const Rc<DxvkCommandList>& commandList, const Rc<DxvkCommandList>& commandList,
const Rc<DxvkSemaphore>& waitSync, const Rc<DxvkSemaphore>& waitSync,
const Rc<DxvkSemaphore>& wakeSync) { const Rc<DxvkSemaphore>& wakeSync) {
Rc<DxvkFence> fence = new DxvkFence(m_vkd);
VkSemaphore waitSemaphore = VK_NULL_HANDLE; VkSemaphore waitSemaphore = VK_NULL_HANDLE;
VkSemaphore wakeSemaphore = VK_NULL_HANDLE; VkSemaphore wakeSemaphore = VK_NULL_HANDLE;
@ -230,13 +228,19 @@ namespace dxvk {
{ // Queue submissions are not thread safe { // Queue submissions are not thread safe
std::lock_guard<std::mutex> lock(m_submissionLock); std::lock_guard<std::mutex> lock(m_submissionLock);
commandList->submit(m_graphicsQueue,
waitSemaphore, wakeSemaphore, fence->handle()); const VkResult status = commandList->submit(
m_graphicsQueue, waitSemaphore, wakeSemaphore);
if (status != VK_SUCCESS) {
Logger::err(str::format(
"DxvkDevice: Command buffer submission failed: ",
status));
}
} }
// Add this to the set of running submissions // Add this to the set of running submissions
m_submissionQueue.submit(fence, commandList); m_submissionQueue.submit(commandList);
return fence;
} }

View File

@ -313,7 +313,7 @@ namespace dxvk {
* \param [in] wakeSync (Optional) Semaphore to notify * \param [in] wakeSync (Optional) Semaphore to notify
* \returns Synchronization fence * \returns Synchronization fence
*/ */
Rc<DxvkFence> submitCommandList( void submitCommandList(
const Rc<DxvkCommandList>& commandList, const Rc<DxvkCommandList>& commandList,
const Rc<DxvkSemaphore>& waitSync, const Rc<DxvkSemaphore>& waitSync,
const Rc<DxvkSemaphore>& wakeSync); const Rc<DxvkSemaphore>& wakeSync);

View File

@ -20,16 +20,14 @@ namespace dxvk {
} }
void DxvkSubmissionQueue::submit( void DxvkSubmissionQueue::submit(const Rc<DxvkCommandList>& cmdList) {
const Rc<DxvkFence>& fence,
const Rc<DxvkCommandList>& cmdList) {
{ std::unique_lock<std::mutex> lock(m_mutex); { std::unique_lock<std::mutex> lock(m_mutex);
m_condOnTake.wait(lock, [this] { m_condOnTake.wait(lock, [this] {
return m_entries.size() < MaxNumQueuedCommandBuffers; return m_entries.size() < MaxNumQueuedCommandBuffers;
}); });
m_entries.push({ fence, cmdList }); m_entries.push(cmdList);
m_condOnAdd.notify_one(); m_condOnAdd.notify_one();
} }
} }
@ -37,7 +35,7 @@ namespace dxvk {
void DxvkSubmissionQueue::threadFunc() { void DxvkSubmissionQueue::threadFunc() {
while (!m_stopped.load()) { while (!m_stopped.load()) {
Entry entry; Rc<DxvkCommandList> cmdList;
{ std::unique_lock<std::mutex> lock(m_mutex); { std::unique_lock<std::mutex> lock(m_mutex);
@ -46,22 +44,27 @@ namespace dxvk {
}); });
if (m_entries.size() != 0) { if (m_entries.size() != 0) {
entry = std::move(m_entries.front()); cmdList = std::move(m_entries.front());
m_entries.pop(); m_entries.pop();
} }
m_condOnTake.notify_one(); m_condOnTake.notify_one();
} }
if (entry.fence != nullptr) { if (cmdList != nullptr) {
while (!entry.fence->wait(1'000'000'000ull)) VkResult status = cmdList->synchronize();
continue;
entry.cmdList->writeQueryData(); if (status == VK_SUCCESS) {
entry.cmdList->signalEvents(); cmdList->writeQueryData();
entry.cmdList->reset(); cmdList->signalEvents();
cmdList->reset();
m_device->recycleCommandList(entry.cmdList); m_device->recycleCommandList(cmdList);
} else {
Logger::err(str::format(
"DxvkSubmissionQueue: Failed to sync fence: ",
status));
}
} }
} }
} }

View File

@ -24,17 +24,10 @@ namespace dxvk {
DxvkSubmissionQueue(DxvkDevice* device); DxvkSubmissionQueue(DxvkDevice* device);
~DxvkSubmissionQueue(); ~DxvkSubmissionQueue();
void submit( void submit(const Rc<DxvkCommandList>& cmdList);
const Rc<DxvkFence>& fence,
const Rc<DxvkCommandList>& cmdList);
private: private:
struct Entry {
Rc<DxvkFence> fence;
Rc<DxvkCommandList> cmdList;
};
DxvkDevice* m_device; DxvkDevice* m_device;
std::atomic<bool> m_stopped = { false }; std::atomic<bool> m_stopped = { false };
@ -42,7 +35,7 @@ namespace dxvk {
std::mutex m_mutex; std::mutex m_mutex;
std::condition_variable m_condOnAdd; std::condition_variable m_condOnAdd;
std::condition_variable m_condOnTake; std::condition_variable m_condOnTake;
std::queue<Entry> m_entries; std::queue<Rc<DxvkCommandList>> m_entries;
std::thread m_thread; std::thread m_thread;
void threadFunc(); void threadFunc();