mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-30 20:52:11 +01:00
[dxvk] Support splitting command lists into multipe submissions
This commit is contained in:
parent
e378be826e
commit
6f2ff2562d
@ -72,7 +72,7 @@ namespace dxvk {
|
||||
|
||||
VkResult vr = VK_SUCCESS;
|
||||
|
||||
if (submitInfo.waitSemaphoreInfoCount || submitInfo.commandBufferInfoCount || submitInfo.signalSemaphoreInfoCount)
|
||||
if (!this->isEmpty())
|
||||
vr = vk->vkQueueSubmit2(queue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
|
||||
this->reset();
|
||||
@ -87,6 +87,13 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
|
||||
bool DxvkCommandSubmission::isEmpty() const {
|
||||
return m_semaphoreWaits.empty()
|
||||
&& m_semaphoreSignals.empty()
|
||||
&& m_commandBuffers.empty();
|
||||
}
|
||||
|
||||
|
||||
DxvkCommandPool::DxvkCommandPool(
|
||||
DxvkDevice* device,
|
||||
uint32_t queueFamily)
|
||||
@ -190,10 +197,29 @@ namespace dxvk {
|
||||
|
||||
m_commandSubmission.reset();
|
||||
|
||||
if (m_cmd.usedFlags.test(DxvkCmdBuffer::SdmaBuffer)) {
|
||||
m_commandSubmission.executeCommandBuffer(m_cmd.sdmaBuffer);
|
||||
for (size_t i = 0; i < m_cmdSubmissions.size(); i++) {
|
||||
bool isFirst = i == 0;
|
||||
bool isLast = i == m_cmdSubmissions.size() - 1;
|
||||
|
||||
if (m_device->hasDedicatedTransferQueue()) {
|
||||
const auto& cmd = m_cmdSubmissions[i];
|
||||
|
||||
if (isFirst) {
|
||||
// Wait for per-command list semaphores on first submission
|
||||
for (const auto& entry : m_waitSemaphores) {
|
||||
m_commandSubmission.waitSemaphore(
|
||||
entry.fence->handle(),
|
||||
entry.value, 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 (m_device->hasDedicatedTransferQueue() && !m_commandSubmission.isEmpty()) {
|
||||
m_commandSubmission.signalSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
|
||||
if ((status = m_commandSubmission.submit(m_device, transfer.queueHandle)))
|
||||
@ -201,58 +227,101 @@ namespace dxvk {
|
||||
|
||||
m_commandSubmission.waitSemaphore(m_sdmaSemaphore, 0, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
// We promise to never do weird stuff to WSI images on
|
||||
// the transfer queue, so blocking graphics is sufficient
|
||||
if (isFirst && m_wsiSemaphores.acquire) {
|
||||
m_commandSubmission.waitSemaphore(m_wsiSemaphores.acquire,
|
||||
0, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
// Submit graphics commands
|
||||
if (cmd.usedFlags.test(DxvkCmdBuffer::InitBuffer))
|
||||
m_commandSubmission.executeCommandBuffer(cmd.initBuffer);
|
||||
|
||||
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(),
|
||||
entry.value, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
// Signal WSI semaphore on the final submission
|
||||
if (m_wsiSemaphores.present) {
|
||||
m_commandSubmission.signalSemaphore(m_wsiSemaphores.present,
|
||||
0, 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)))
|
||||
return status;
|
||||
}
|
||||
|
||||
if (m_cmd.usedFlags.test(DxvkCmdBuffer::InitBuffer))
|
||||
m_commandSubmission.executeCommandBuffer(m_cmd.initBuffer);
|
||||
|
||||
if (m_cmd.usedFlags.test(DxvkCmdBuffer::ExecBuffer))
|
||||
m_commandSubmission.executeCommandBuffer(m_cmd.execBuffer);
|
||||
|
||||
if (m_wsiSemaphores.acquire) {
|
||||
m_commandSubmission.waitSemaphore(m_wsiSemaphores.acquire,
|
||||
0, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
if (m_wsiSemaphores.present) {
|
||||
m_commandSubmission.signalSemaphore(m_wsiSemaphores.present,
|
||||
0, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
for (const auto& entry : m_waitSemaphores) {
|
||||
m_commandSubmission.waitSemaphore(
|
||||
entry.fence->handle(),
|
||||
entry.value, VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
for (const auto& entry : m_signalSemaphores)
|
||||
m_commandSubmission.signalSemaphore(entry.fence->handle(), entry.value, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
|
||||
m_commandSubmission.signalSemaphore(semaphore,
|
||||
++semaphoreValue, VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT);
|
||||
|
||||
if ((status = m_commandSubmission.submit(m_device, graphics.queueHandle)))
|
||||
return status;
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::beginRecording() {
|
||||
void DxvkCommandList::init() {
|
||||
m_cmd = DxvkCommandSubmissionInfo();
|
||||
|
||||
// Grab a fresh set of command buffers from the pools
|
||||
m_cmd.execBuffer = m_graphicsPool->getCommandBuffer();
|
||||
m_cmd.initBuffer = m_graphicsPool->getCommandBuffer();
|
||||
m_cmd.sdmaBuffer = m_transferPool->getCommandBuffer();
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::endRecording() {
|
||||
if (m_vkd->vkEndCommandBuffer(m_cmd.execBuffer) != VK_SUCCESS
|
||||
|| m_vkd->vkEndCommandBuffer(m_cmd.initBuffer) != VK_SUCCESS
|
||||
|| m_vkd->vkEndCommandBuffer(m_cmd.sdmaBuffer) != VK_SUCCESS)
|
||||
Logger::err("DxvkCommandList::endRecording: Failed to record command buffer");
|
||||
void DxvkCommandList::finalize() {
|
||||
if (m_cmdSubmissions.empty() || m_cmd.usedFlags != 0)
|
||||
m_cmdSubmissions.push_back(m_cmd);
|
||||
|
||||
// For consistency, end all command buffers here,
|
||||
// regardless of whether they have been used.
|
||||
this->endCommandBuffer(m_cmd.execBuffer);
|
||||
this->endCommandBuffer(m_cmd.initBuffer);
|
||||
this->endCommandBuffer(m_cmd.sdmaBuffer);
|
||||
|
||||
// Reset all command buffer handles
|
||||
m_cmd = DxvkCommandSubmissionInfo();
|
||||
|
||||
// Increment queue submission count
|
||||
uint64_t submissionCount = m_cmdSubmissions.size();
|
||||
m_statCounters.addCtr(DxvkStatCounter::QueueSubmitCount, submissionCount);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DxvkCommandList::next() {
|
||||
if (m_cmd.usedFlags != 0)
|
||||
m_cmdSubmissions.push_back(m_cmd);
|
||||
|
||||
// Only replace used command buffer to save resources
|
||||
if (m_cmd.usedFlags.test(DxvkCmdBuffer::ExecBuffer)) {
|
||||
this->endCommandBuffer(m_cmd.execBuffer);
|
||||
m_cmd.execBuffer = m_graphicsPool->getCommandBuffer();
|
||||
}
|
||||
|
||||
if (m_cmd.usedFlags.test(DxvkCmdBuffer::InitBuffer)) {
|
||||
this->endCommandBuffer(m_cmd.initBuffer);
|
||||
m_cmd.initBuffer = m_graphicsPool->getCommandBuffer();
|
||||
}
|
||||
|
||||
if (m_cmd.usedFlags.test(DxvkCmdBuffer::SdmaBuffer)) {
|
||||
this->endCommandBuffer(m_cmd.sdmaBuffer);
|
||||
m_cmd.sdmaBuffer = m_transferPool->getCommandBuffer();
|
||||
}
|
||||
|
||||
m_cmd.usedFlags = 0;
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::reset() {
|
||||
// Free resources and other objects
|
||||
@ -284,6 +353,7 @@ namespace dxvk {
|
||||
|
||||
m_waitSemaphores.clear();
|
||||
m_signalSemaphores.clear();
|
||||
m_cmdSubmissions.clear();
|
||||
|
||||
m_wsiSemaphores = vk::PresenterSync();
|
||||
|
||||
@ -292,4 +362,12 @@ namespace dxvk {
|
||||
m_transferPool->reset();
|
||||
}
|
||||
|
||||
|
||||
void DxvkCommandList::endCommandBuffer(VkCommandBuffer cmdBuffer) {
|
||||
auto vk = m_device->vkd();
|
||||
|
||||
if (vk->vkEndCommandBuffer(cmdBuffer))
|
||||
throw DxvkError("DxvkCommandList: Failed to end command buffer");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -94,6 +94,14 @@ namespace dxvk {
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* \brief Checks whether the submission is empty
|
||||
*
|
||||
* \returns \c true if there are no command
|
||||
* buffers or semaphores.
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
private:
|
||||
|
||||
std::vector<VkSemaphoreSubmitInfo> m_semaphoreWaits;
|
||||
@ -215,21 +223,29 @@ namespace dxvk {
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Begins recording
|
||||
*
|
||||
* Resets the command buffer and
|
||||
* begins command buffer recording.
|
||||
* \brief Initializes command buffers
|
||||
*
|
||||
* Prepares command list for command recording.
|
||||
*/
|
||||
void beginRecording();
|
||||
void init();
|
||||
|
||||
/**
|
||||
* \brief Ends recording
|
||||
*
|
||||
*
|
||||
* Ends command buffer recording, making
|
||||
* the command list ready for submission.
|
||||
* \param [in] stats Stat counters
|
||||
*/
|
||||
void endRecording();
|
||||
void finalize();
|
||||
|
||||
/**
|
||||
* \brief Interrupts recording
|
||||
*
|
||||
* Begins a new set of command buffers while adding the
|
||||
* current set to the submission list. This can be useful
|
||||
* to split the command list into multiple submissions.
|
||||
*/
|
||||
void next();
|
||||
|
||||
/**
|
||||
* \brief Frees buffer slice
|
||||
@ -972,6 +988,8 @@ namespace dxvk {
|
||||
|
||||
std::vector<DxvkFenceValuePair> m_waitSemaphores;
|
||||
std::vector<DxvkFenceValuePair> m_signalSemaphores;
|
||||
|
||||
std::vector<DxvkCommandSubmissionInfo> m_cmdSubmissions;
|
||||
|
||||
std::vector<std::pair<
|
||||
Rc<DxvkDescriptorPool>,
|
||||
@ -985,7 +1003,9 @@ namespace dxvk {
|
||||
if (cmdBuffer == DxvkCmdBuffer::SdmaBuffer) return m_cmd.sdmaBuffer;
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
|
||||
void endCommandBuffer(VkCommandBuffer cmdBuffer);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ namespace dxvk {
|
||||
|
||||
void DxvkContext::beginRecording(const Rc<DxvkCommandList>& cmdList) {
|
||||
m_cmd = cmdList;
|
||||
m_cmd->beginRecording();
|
||||
m_cmd->init();
|
||||
|
||||
// Mark all resources as untracked
|
||||
m_vbTracked.clear();
|
||||
@ -120,7 +120,7 @@ namespace dxvk {
|
||||
m_descriptorPool = m_descriptorManager->getDescriptorPool();
|
||||
}
|
||||
|
||||
m_cmd->endRecording();
|
||||
m_cmd->finalize();
|
||||
return std::exchange(m_cmd, nullptr);
|
||||
}
|
||||
|
||||
|
@ -274,7 +274,6 @@ namespace dxvk {
|
||||
|
||||
std::lock_guard<sync::Spinlock> statLock(m_statLock);
|
||||
m_statCounters.merge(commandList->statCounters());
|
||||
m_statCounters.addCtr(DxvkStatCounter::QueueSubmitCount, 1);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user