diff --git a/src/d3d11/d3d11_initializer.cpp b/src/d3d11/d3d11_initializer.cpp index 7a264e38..ac0a7b03 100644 --- a/src/d3d11/d3d11_initializer.cpp +++ b/src/d3d11/d3d11_initializer.cpp @@ -9,7 +9,8 @@ namespace dxvk { D3D11Device* pParent) : m_parent(pParent), m_device(pParent->GetDXVKDevice()), - m_context(m_device->createContext(DxvkContextType::Supplementary)) { + m_context(m_device->createContext(DxvkContextType::Supplementary)), + m_stagingBuffer(m_device, StagingBufferSize) { m_context->beginRecording( m_device->createCommandList()); } @@ -81,20 +82,22 @@ namespace dxvk { const D3D11_SUBRESOURCE_DATA* pInitialData) { std::lock_guard lock(m_mutex); - DxvkBufferSlice bufferSlice = pBuffer->GetBufferSlice(); + Rc buffer = pBuffer->GetBuffer(); if (pInitialData != nullptr && pInitialData->pSysMem != nullptr) { - m_transferMemory += bufferSlice.length(); + auto stagingSlice = m_stagingBuffer.alloc(buffer->info().size); + std::memcpy(stagingSlice.mapPtr(0), pInitialData->pSysMem, stagingSlice.length()); + + m_transferMemory += buffer->info().size; m_transferCommands += 1; - m_context->uploadBuffer( - bufferSlice.buffer(), - pInitialData->pSysMem); + m_context->uploadBuffer(buffer, + stagingSlice.buffer(), + stagingSlice.offset()); } else { m_transferCommands += 1; - m_context->initBuffer( - bufferSlice.buffer()); + m_context->initBuffer(buffer); } FlushImplicit(); @@ -284,6 +287,8 @@ namespace dxvk { m_transferCommands = 0; m_transferMemory = 0; + + m_stagingBuffer.reset(); } diff --git a/src/d3d11/d3d11_initializer.h b/src/d3d11/d3d11_initializer.h index fd3d4dfa..732b2058 100644 --- a/src/d3d11/d3d11_initializer.h +++ b/src/d3d11/d3d11_initializer.h @@ -1,5 +1,7 @@ #pragma once +#include "../dxvk/dxvk_staging.h" + #include "d3d11_buffer.h" #include "d3d11_texture.h" @@ -18,6 +20,9 @@ namespace dxvk { class D3D11Initializer { constexpr static size_t MaxTransferMemory = 32 * 1024 * 1024; constexpr static size_t MaxTransferCommands = 512; + + // Use a staging buffer with a linear allocator to service small uploads + constexpr static VkDeviceSize StagingBufferSize = 1ull << 20; public: D3D11Initializer( @@ -45,6 +50,8 @@ namespace dxvk { D3D11Device* m_parent; Rc m_device; Rc m_context; + + DxvkStagingBuffer m_stagingBuffer; size_t m_transferCommands = 0; size_t m_transferMemory = 0; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 3bd1d98a..706979fc 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -2537,20 +2537,18 @@ namespace dxvk { void DxvkContext::uploadBuffer( const Rc& buffer, - const void* data) { + const Rc& source, + VkDeviceSize sourceOffset) { auto bufferSlice = buffer->getSliceHandle(); - - auto stagingSlice = m_staging.alloc(bufferSlice.length); - auto stagingHandle = stagingSlice.getSliceHandle(); - std::memcpy(stagingHandle.mapPtr, data, bufferSlice.length); + auto sourceSlice = source->getSliceHandle(sourceOffset, buffer->info().size); VkBufferCopy2 copyRegion = { VK_STRUCTURE_TYPE_BUFFER_COPY_2 }; - copyRegion.srcOffset = stagingHandle.offset; + copyRegion.srcOffset = sourceSlice.offset; copyRegion.dstOffset = bufferSlice.offset; copyRegion.size = bufferSlice.length; VkCopyBufferInfo2 copyInfo = { VK_STRUCTURE_TYPE_COPY_BUFFER_INFO_2 }; - copyInfo.srcBuffer = stagingHandle.handle; + copyInfo.srcBuffer = sourceSlice.handle; copyInfo.dstBuffer = bufferSlice.handle; copyInfo.regionCount = 1; copyInfo.pRegions = ©Region; @@ -2574,7 +2572,7 @@ namespace dxvk { buffer->info().stages, buffer->info().access); } - m_cmd->trackResource(stagingSlice.buffer()); + m_cmd->trackResource(source); m_cmd->trackResource(buffer); } diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index ce936ce1..a4c5fa89 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1151,14 +1151,17 @@ namespace dxvk { /** * \brief Uses transfer queue to initialize buffer - * - * Only safe to use if the buffer is not in use by the GPU. + * + * Always replaces the entire buffer. Only safe to use + * if the buffer is currently not in use by the GPU. * \param [in] buffer The buffer to initialize - * \param [in] data The data to copy to the buffer + * \param [in] source Staging buffer containing data + * \param [in] sourceOffset Offset into staging buffer */ void uploadBuffer( const Rc& buffer, - const void* data); + const Rc& source, + VkDeviceSize sourceOffset); /** * \brief Uses transfer queue to initialize image