mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-03 13:24:20 +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:
parent
e59f53abfa
commit
67b9b6e1e1
@ -139,16 +139,19 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
void DxvkCommandList::stagedBufferCopy(
|
void DxvkCommandList::stagedBufferCopy(
|
||||||
|
DxvkCmdBuffer cmdBuffer,
|
||||||
VkBuffer dstBuffer,
|
VkBuffer dstBuffer,
|
||||||
VkDeviceSize dstOffset,
|
VkDeviceSize dstOffset,
|
||||||
VkDeviceSize dataSize,
|
VkDeviceSize dataSize,
|
||||||
const DxvkStagingBufferSlice& dataSlice) {
|
const DxvkStagingBufferSlice& dataSlice) {
|
||||||
|
m_cmdBuffersUsed.set(cmdBuffer);
|
||||||
|
|
||||||
VkBufferCopy region;
|
VkBufferCopy region;
|
||||||
region.srcOffset = dataSlice.offset;
|
region.srcOffset = dataSlice.offset;
|
||||||
region.dstOffset = dstOffset;
|
region.dstOffset = dstOffset;
|
||||||
region.size = dataSize;
|
region.size = dataSize;
|
||||||
|
|
||||||
m_vkd->vkCmdCopyBuffer(m_execBuffer,
|
m_vkd->vkCmdCopyBuffer(getCmdBuffer(cmdBuffer),
|
||||||
dataSlice.buffer, dstBuffer, 1, ®ion);
|
dataSlice.buffer, dstBuffer, 1, ®ion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -620,11 +620,14 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
void cmdUpdateBuffer(
|
void cmdUpdateBuffer(
|
||||||
|
DxvkCmdBuffer cmdBuffer,
|
||||||
VkBuffer dstBuffer,
|
VkBuffer dstBuffer,
|
||||||
VkDeviceSize dstOffset,
|
VkDeviceSize dstOffset,
|
||||||
VkDeviceSize dataSize,
|
VkDeviceSize dataSize,
|
||||||
const void* pData) {
|
const void* pData) {
|
||||||
m_vkd->vkCmdUpdateBuffer(m_execBuffer,
|
m_cmdBuffersUsed.set(cmdBuffer);
|
||||||
|
|
||||||
|
m_vkd->vkCmdUpdateBuffer(getCmdBuffer(cmdBuffer),
|
||||||
dstBuffer, dstOffset, dataSize, pData);
|
dstBuffer, dstOffset, dataSize, pData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -692,6 +695,7 @@ namespace dxvk {
|
|||||||
|
|
||||||
|
|
||||||
void stagedBufferCopy(
|
void stagedBufferCopy(
|
||||||
|
DxvkCmdBuffer cmdBuffer,
|
||||||
VkBuffer dstBuffer,
|
VkBuffer dstBuffer,
|
||||||
VkDeviceSize dstOffset,
|
VkDeviceSize dstOffset,
|
||||||
VkDeviceSize dataSize,
|
VkDeviceSize dataSize,
|
||||||
|
@ -68,6 +68,7 @@ namespace dxvk {
|
|||||||
Rc<DxvkCommandList> DxvkContext::endRecording() {
|
Rc<DxvkCommandList> DxvkContext::endRecording() {
|
||||||
this->spillRenderPass();
|
this->spillRenderPass();
|
||||||
|
|
||||||
|
m_transfers.recordCommands(m_cmd);
|
||||||
m_barriers.recordCommands(m_cmd);
|
m_barriers.recordCommands(m_cmd);
|
||||||
|
|
||||||
m_cmd->endRecording();
|
m_cmd->endRecording();
|
||||||
@ -342,6 +343,7 @@ namespace dxvk {
|
|||||||
data[i] = value;
|
data[i] = value;
|
||||||
|
|
||||||
m_cmd->cmdUpdateBuffer(
|
m_cmd->cmdUpdateBuffer(
|
||||||
|
DxvkCmdBuffer::ExecBuffer,
|
||||||
slice.handle,
|
slice.handle,
|
||||||
slice.offset,
|
slice.offset,
|
||||||
slice.length,
|
slice.length,
|
||||||
@ -1719,20 +1721,39 @@ namespace dxvk {
|
|||||||
VkDeviceSize offset,
|
VkDeviceSize offset,
|
||||||
VkDeviceSize size,
|
VkDeviceSize size,
|
||||||
const void* data) {
|
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();
|
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
|
// Vulkan specifies that small amounts of data (up to 64kB) can
|
||||||
// be copied to a buffer directly if the size is a multiple of
|
// be copied to a buffer directly if the size is a multiple of
|
||||||
// four. Anything else must be copied through a staging buffer.
|
// four. Anything else must be copied through a staging buffer.
|
||||||
// We'll limit the size to 4kB in order to keep command buffers
|
// 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.
|
// 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)) {
|
if ((size <= 4096) && ((size & 0x3) == 0) && ((offset & 0x3) == 0)) {
|
||||||
m_cmd->cmdUpdateBuffer(
|
m_cmd->cmdUpdateBuffer(
|
||||||
|
cmdBuffer,
|
||||||
bufferSlice.handle,
|
bufferSlice.handle,
|
||||||
bufferSlice.offset,
|
bufferSlice.offset,
|
||||||
bufferSlice.length,
|
bufferSlice.length,
|
||||||
@ -1742,13 +1763,18 @@ namespace dxvk {
|
|||||||
std::memcpy(slice.mapPtr, data, size);
|
std::memcpy(slice.mapPtr, data, size);
|
||||||
|
|
||||||
m_cmd->stagedBufferCopy(
|
m_cmd->stagedBufferCopy(
|
||||||
|
cmdBuffer,
|
||||||
bufferSlice.handle,
|
bufferSlice.handle,
|
||||||
bufferSlice.offset,
|
bufferSlice.offset,
|
||||||
bufferSlice.length,
|
bufferSlice.length,
|
||||||
slice);
|
slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_barriers.accessBuffer(
|
auto& barriers = replaceBuffer
|
||||||
|
? m_transfers
|
||||||
|
: m_barriers;
|
||||||
|
|
||||||
|
barriers.accessBuffer(
|
||||||
bufferSlice,
|
bufferSlice,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
|
Loading…
Reference in New Issue
Block a user