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

[dxvk] Get rid of global timeline semaphore

Timeline semaphores are broken on 32-bit Proton, so just use the existing
command list binary semaphore to synchronize sparse binding operation.

This will introduce some additional graphics queue submissions around
sparse binding, but since that is basically unused it's not a concern.
This commit is contained in:
Philip Rebohle 2023-01-21 12:54:10 +01:00
parent d020f4451a
commit 41ee092b97
4 changed files with 28 additions and 57 deletions

View File

@ -176,7 +176,9 @@ namespace dxvk {
VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
if (m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_sdmaSemaphore))
if (m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_bindSemaphore)
|| m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_postSemaphore)
|| m_vkd->vkCreateSemaphore(m_vkd->device(), &semaphoreInfo, nullptr, &m_sdmaSemaphore))
throw DxvkError("DxvkCommandList: Failed to create semaphore");
VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
@ -196,14 +198,15 @@ namespace dxvk {
DxvkCommandList::~DxvkCommandList() {
this->reset();
m_vkd->vkDestroySemaphore(m_vkd->device(), m_bindSemaphore, nullptr);
m_vkd->vkDestroySemaphore(m_vkd->device(), m_postSemaphore, nullptr);
m_vkd->vkDestroySemaphore(m_vkd->device(), m_sdmaSemaphore, nullptr);
m_vkd->vkDestroyFence(m_vkd->device(), m_fence, nullptr);
}
VkResult DxvkCommandList::submit(
VkSemaphore semaphore,
uint64_t& semaphoreValue) {
VkResult DxvkCommandList::submit() {
VkResult status = VK_SUCCESS;
const auto& graphics = m_device->queues().graphics;
@ -222,44 +225,37 @@ namespace dxvk {
? &m_cmdSparseBinds[cmd.sparseCmd]
: nullptr;
if (sparseBind) {
// Sparse bindig needs to serialize command execution, so wait
// for any prior submissions, then block any subsequent ones
sparseBind->waitSemaphore(semaphore, semaphoreValue);
sparseBind->signalSemaphore(semaphore, ++semaphoreValue);
m_commandSubmission.waitSemaphore(semaphore, semaphoreValue,
VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
}
if (isFirst) {
// Wait for per-command list semaphores on first submission
for (const auto& entry : m_waitSemaphores) {
if (sparseBind) {
sparseBind->waitSemaphore(
entry.fence->handle(),
entry.value);
} else {
m_commandSubmission.waitSemaphore(
entry.fence->handle(),
entry.value, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
}
m_commandSubmission.waitSemaphore(entry.fence->handle(),
entry.value, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
}
}
// Execute sparse bind
if (sparseBind) {
// Sparse binding needs to serialize command execution, so wait
// for any prior submissions, then block any subsequent ones
m_commandSubmission.signalSemaphore(m_bindSemaphore, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
return status;
sparseBind->waitSemaphore(m_bindSemaphore, 0);
sparseBind->signalSemaphore(m_postSemaphore, 0);
if ((status = sparseBind->submit(m_device, sparse.queueHandle)))
return status;
m_commandSubmission.waitSemaphore(m_postSemaphore, 0, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
}
// Submit transfer commands as necessary
if (cmd.usedFlags.test(DxvkCmdBuffer::SdmaBuffer))
m_commandSubmission.executeCommandBuffer(cmd.sdmaBuffer);
// If we had either a transfer command or a semaphore wait,
// submit to the transfer queue so that all subsequent commands
// get stalled appropriately.
// If we had either a transfer command or a semaphore wait, submit to the
// transfer queue so that all subsequent commands get stalled as necessary.
if (m_device->hasDedicatedTransferQueue() && !m_commandSubmission.isEmpty()) {
m_commandSubmission.signalSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
@ -283,15 +279,10 @@ namespace dxvk {
if (cmd.usedFlags.test(DxvkCmdBuffer::ExecBuffer))
m_commandSubmission.executeCommandBuffer(cmd.execBuffer);
// Signal global timeline semaphore at the end of every submission
m_commandSubmission.signalSemaphore(semaphore,
++semaphoreValue, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
if (isLast) {
// Signal per-command list semaphores on the final submission
for (const auto& entry : m_signalSemaphores) {
m_commandSubmission.signalSemaphore(
entry.fence->handle(),
m_commandSubmission.signalSemaphore(entry.fence->handle(),
entry.value, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
}

View File

@ -198,18 +198,9 @@ namespace dxvk {
/**
* \brief Submits command list
*
* \param [in] semaphore Global timeline semaphore
* \param [in,out] semaphoreValue Semaphore value. On input,
* this is the last signaled value of the semaphore so that
* synchronization can take place as needed. On ouput, this
* will contain the new value the semaphore gets signaled
* to by this submission.
* \returns Submission status
*/
VkResult submit(
VkSemaphore semaphore,
uint64_t& semaphoreValue);
VkResult submit();
/**
* \brief Stat counters
@ -1029,6 +1020,8 @@ namespace dxvk {
Rc<DxvkCommandPool> m_graphicsPool;
Rc<DxvkCommandPool> m_transferPool;
VkSemaphore m_bindSemaphore = VK_NULL_HANDLE;
VkSemaphore m_postSemaphore = VK_NULL_HANDLE;
VkSemaphore m_sdmaSemaphore = VK_NULL_HANDLE;
VkFence m_fence = VK_NULL_HANDLE;

View File

@ -7,15 +7,7 @@ namespace dxvk {
: m_device(device),
m_submitThread([this] () { submitCmdLists(); }),
m_finishThread([this] () { finishCmdLists(); }) {
auto vk = m_device->vkd();
VkSemaphoreTypeCreateInfo typeInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO };
typeInfo.semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE;
VkSemaphoreCreateInfo info = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, &typeInfo };
if (vk->vkCreateSemaphore(vk->device(), &info, nullptr, &m_semaphore))
throw DxvkError("Failed to create global timeline semaphore");
}
@ -31,8 +23,6 @@ namespace dxvk {
m_submitThread.join();
m_finishThread.join();
vk->vkDestroySemaphore(vk->device(), m_semaphore, nullptr);
}
@ -116,7 +106,7 @@ namespace dxvk {
std::lock_guard<dxvk::mutex> lock(m_mutexQueue);
if (entry.submit.cmdList != nullptr)
status = entry.submit.cmdList->submit(m_semaphore, m_semaphoreValue);
status = entry.submit.cmdList->submit();
else if (entry.present.presenter != nullptr)
status = entry.present.presenter->presentImage();
} else {

View File

@ -183,9 +183,6 @@ namespace dxvk {
std::atomic<uint32_t> m_pending = { 0u };
std::atomic<uint64_t> m_gpuIdle = { 0ull };
VkSemaphore m_semaphore = VK_NULL_HANDLE;
uint64_t m_semaphoreValue = 0ull;
dxvk::mutex m_mutex;
dxvk::mutex m_mutexQueue;