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

[dxvk] Pull buffer updates out of render passes whenever possible

Instead of ending the render pass and inserting two barriers, we
perform the update and barrier in a dedicated command buffer.

Improves performance in Sekiro by 5-10% depending on resolution and scene.
This commit is contained in:
Philip Rebohle 2019-04-02 12:52:44 +02:00
parent e59f53abfa
commit 67b9b6e1e1
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
3 changed files with 43 additions and 10 deletions

View File

@ -139,16 +139,19 @@ namespace dxvk {
void DxvkCommandList::stagedBufferCopy(
DxvkCmdBuffer cmdBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const DxvkStagingBufferSlice& dataSlice) {
m_cmdBuffersUsed.set(cmdBuffer);
VkBufferCopy region;
region.srcOffset = dataSlice.offset;
region.dstOffset = dstOffset;
region.size = dataSize;
m_vkd->vkCmdCopyBuffer(m_execBuffer,
m_vkd->vkCmdCopyBuffer(getCmdBuffer(cmdBuffer),
dataSlice.buffer, dstBuffer, 1, &region);
}

View File

@ -620,11 +620,14 @@ namespace dxvk {
void cmdUpdateBuffer(
DxvkCmdBuffer cmdBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const void* pData) {
m_vkd->vkCmdUpdateBuffer(m_execBuffer,
m_cmdBuffersUsed.set(cmdBuffer);
m_vkd->vkCmdUpdateBuffer(getCmdBuffer(cmdBuffer),
dstBuffer, dstOffset, dataSize, pData);
}
@ -692,6 +695,7 @@ namespace dxvk {
void stagedBufferCopy(
DxvkCmdBuffer cmdBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,

View File

@ -68,6 +68,7 @@ namespace dxvk {
Rc<DxvkCommandList> DxvkContext::endRecording() {
this->spillRenderPass();
m_transfers.recordCommands(m_cmd);
m_barriers.recordCommands(m_cmd);
m_cmd->endRecording();
@ -342,6 +343,7 @@ namespace dxvk {
data[i] = value;
m_cmd->cmdUpdateBuffer(
DxvkCmdBuffer::ExecBuffer,
slice.handle,
slice.offset,
slice.length,
@ -1719,20 +1721,39 @@ namespace dxvk {
VkDeviceSize offset,
VkDeviceSize size,
const void* data) {
bool replaceBuffer = (size == buffer->info().size)
&& (size <= (1 << 20)) /* 1 MB */
&& (m_flags.test(DxvkContextFlag::GpRenderPassBound));
DxvkBufferSliceHandle bufferSlice;
DxvkCmdBuffer cmdBuffer;
if (replaceBuffer) {
// As an optimization, allocate a free slice and perform
// the copy in the initialization command buffer instead
// interrupting the render pass and stalling the pipeline.
bufferSlice = buffer->allocSlice();
cmdBuffer = DxvkCmdBuffer::InitBuffer;
this->invalidateBuffer(buffer, bufferSlice);
} else {
this->spillRenderPass();
bufferSlice = buffer->getSliceHandle(offset, size);
cmdBuffer = DxvkCmdBuffer::ExecBuffer;
if (m_barriers.isBufferDirty(bufferSlice, DxvkAccess::Write))
m_barriers.recordCommands(m_cmd);
}
// Vulkan specifies that small amounts of data (up to 64kB) can
// be copied to a buffer directly if the size is a multiple of
// four. Anything else must be copied through a staging buffer.
// We'll limit the size to 4kB in order to keep command buffers
// reasonably small, we do not know how much data apps may upload.
auto bufferSlice = buffer->getSliceHandle(offset, size);
if (m_barriers.isBufferDirty(bufferSlice, DxvkAccess::Write))
m_barriers.recordCommands(m_cmd);
if ((size <= 4096) && ((size & 0x3) == 0) && ((offset & 0x3) == 0)) {
m_cmd->cmdUpdateBuffer(
cmdBuffer,
bufferSlice.handle,
bufferSlice.offset,
bufferSlice.length,
@ -1742,13 +1763,18 @@ namespace dxvk {
std::memcpy(slice.mapPtr, data, size);
m_cmd->stagedBufferCopy(
cmdBuffer,
bufferSlice.handle,
bufferSlice.offset,
bufferSlice.length,
slice);
}
m_barriers.accessBuffer(
auto& barriers = replaceBuffer
? m_transfers
: m_barriers;
barriers.accessBuffer(
bufferSlice,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_TRANSFER_WRITE_BIT,