diff --git a/include/mbgl/vulkan/buffer_resource.hpp b/include/mbgl/vulkan/buffer_resource.hpp index 2d59abff4fa..890d4b61d70 100644 --- a/include/mbgl/vulkan/buffer_resource.hpp +++ b/include/mbgl/vulkan/buffer_resource.hpp @@ -51,14 +51,18 @@ class BufferResource { void update(const void* data, std::size_t size, std::size_t offset) noexcept; std::size_t getSizeInBytes() const noexcept { return size; } - const void* contents() const noexcept { return (raw.empty() ? nullptr : raw.data()); } + const void* contents() const noexcept; + const void* contents(uint8_t resourceIndex) const noexcept; Context& getContext() const noexcept { return context; } const vk::Buffer& getVulkanBuffer() const noexcept { return bufferAllocation->buffer; } std::size_t getVulkanBufferOffset() const noexcept; - std::size_t getVulkanBufferSize() const noexcept; + std::size_t getVulkanBufferOffset(uint8_t resourceIndex) const noexcept; + // update the current sub-buffer with the latest data + void updateVulkanBuffer(); + void updateVulkanBuffer(const int8_t destination, const uint8_t source); - bool isValid() const noexcept { return !raw.empty(); } + bool isValid() const noexcept { return !!bufferAllocation; } operator bool() const noexcept { return isValid(); } bool operator!() const noexcept { return !isValid(); } @@ -69,14 +73,14 @@ class BufferResource { protected: Context& context; - std::vector raw; std::size_t size; std::uint32_t usage; - std::uint16_t version = 0; + VersionType version = 0; bool persistent; SharedBufferAllocation bufferAllocation; size_t bufferWindowSize = 0; + std::vector bufferWindowVersions; }; } // namespace vulkan diff --git a/src/mbgl/vulkan/buffer_resource.cpp b/src/mbgl/vulkan/buffer_resource.cpp index 2f9ccb4a45b..c3006289890 100644 --- a/src/mbgl/vulkan/buffer_resource.cpp +++ b/src/mbgl/vulkan/buffer_resource.cpp @@ -64,7 +64,10 @@ BufferResource::BufferResource( assert(bufferWindowSize != 0); - totalSize = bufferWindowSize * backend.getMaxFrames(); + const auto frameCount = backend.getMaxFrames(); + totalSize = bufferWindowSize * frameCount; + + bufferWindowVersions = std::vector(frameCount, 0); } const auto bufferInfo = vk::BufferCreateInfo() @@ -87,9 +90,7 @@ BufferResource::BufferResource( vmaMapMemory(allocator, bufferAllocation->allocation, &bufferAllocation->mappedBuffer); if (data) { - raw.resize(size); - std::memcpy(raw.data(), data, size); - std::memcpy(static_cast(bufferAllocation->mappedBuffer) + getVulkanBufferOffset(), data, size); + update(data, size, 0); } if (isValid()) { @@ -104,12 +105,13 @@ BufferResource::BufferResource( BufferResource::BufferResource(BufferResource&& other) noexcept : context(other.context), - raw(std::move(other.raw)), size(other.size), usage(other.usage), persistent(other.persistent), bufferAllocation(std::move(other.bufferAllocation)), - bufferWindowSize(other.bufferWindowSize) { + bufferWindowSize(other.bufferWindowSize), + version(other.version), + bufferWindowVersions(std::move(other.bufferWindowVersions)) { other.bufferAllocation = nullptr; } @@ -134,7 +136,7 @@ BufferResource& BufferResource::operator=(BufferResource&& other) noexcept { context.renderingStats().numBuffers--; context.renderingStats().memBuffers -= size; }; - raw = std::move(other.raw); + size = other.size; usage = other.usage; persistent = other.persistent; @@ -152,21 +154,63 @@ void BufferResource::update(const void* newData, std::size_t updateSize, std::si return; } - auto& stats = context.renderingStats(); + uint8_t* data = static_cast(bufferAllocation->mappedBuffer) + getVulkanBufferOffset() + offset; + std::memcpy(data, newData, updateSize); - std::memcpy(raw.data() + offset, newData, updateSize); - std::memcpy( - static_cast(bufferAllocation->mappedBuffer) + getVulkanBufferOffset() + offset, newData, updateSize); + auto& stats = context.renderingStats(); stats.bufferUpdateBytes += updateSize; - stats.bufferUpdates++; version++; + + if (bufferWindowSize) { + const auto frameIndex = context.getCurrentFrameResourceIndex(); + bufferWindowVersions[frameIndex] = version; + } +} + +const void* BufferResource::contents() const noexcept { + return contents(context.getCurrentFrameResourceIndex()); +} + +const void* BufferResource::contents(uint8_t resourceIndex) const noexcept { + if (!isValid()) { + return nullptr; + } + + return static_cast(bufferAllocation->mappedBuffer) + getVulkanBufferOffset(resourceIndex); } std::size_t BufferResource::getVulkanBufferOffset() const noexcept { - if (bufferWindowSize > 0) return 0; + return getVulkanBufferOffset(context.getCurrentFrameResourceIndex()); +} + +std::size_t BufferResource::getVulkanBufferOffset(std::uint8_t resourceIndex) const noexcept { + assert(context.getBackend().getMaxFrames() >= resourceIndex); + return bufferWindowSize ? resourceIndex * bufferWindowSize : 0; +} + +void BufferResource::updateVulkanBuffer() { + const auto frameCount = context.getBackend().getMaxFrames(); + + const int8_t currentIndex = context.getCurrentFrameResourceIndex(); + const int8_t prevIndex = currentIndex == 0 ? frameCount - 1 : currentIndex - 1; + + updateVulkanBuffer(currentIndex, prevIndex); +} + +void BufferResource::updateVulkanBuffer(const int8_t destination, const uint8_t source) { + if (!bufferWindowSize) { + return; + } + + if (bufferWindowVersions[destination] < bufferWindowVersions[source]) { + uint8_t* dstData = static_cast(bufferAllocation->mappedBuffer) + bufferWindowSize * destination; + uint8_t* srcData = static_cast(bufferAllocation->mappedBuffer) + bufferWindowSize * source; + + std::memcpy(dstData, srcData, size); - return context.getCurrentFrameResourceIndex() * bufferWindowSize; + bufferWindowVersions[destination] = bufferWindowVersions[source]; + } } } // namespace vulkan diff --git a/src/mbgl/vulkan/uniform_buffer.cpp b/src/mbgl/vulkan/uniform_buffer.cpp index b01e0facc90..0f102317d71 100644 --- a/src/mbgl/vulkan/uniform_buffer.cpp +++ b/src/mbgl/vulkan/uniform_buffer.cpp @@ -74,6 +74,22 @@ void UniformBufferArray::bindDescriptorSets(CommandEncoder& encoder) { } descriptorSet->update(*this, descriptorStartIndex, descriptorBindingCount); + + const auto frameCount = encoder.getContext().getBackend().getMaxFrames(); + const int32_t currentIndex = encoder.getContext().getCurrentFrameResourceIndex(); + const int32_t prevIndex = currentIndex == 0 ? frameCount - 1 : currentIndex - 1; + + for (uint32_t i = 0; i < descriptorBindingCount; ++i) { + const uint32_t index = descriptorStartIndex + i; + + if (!uniformBufferVector[index]) { + continue; + } + + auto& buff = static_cast(uniformBufferVector[index].get())->mutableBufferResource(); + buff.updateVulkanBuffer(currentIndex, prevIndex); + } + descriptorSet->bind(encoder); }