mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-05 01:24:14 +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:
parent
d020f4451a
commit
41ee092b97
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user