Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate VMA (Vulkan Memory Allocator) #15162

Merged
merged 10 commits into from
Nov 23, 2021
Prev Previous commit
Next Next commit
Change the PushBuffer API a bit to not take explicit memory types.
  • Loading branch information
hrydgard committed Nov 22, 2021
commit 0cbb7ab027734c51daa6b9130c71fa0f1f3ed32f
18 changes: 14 additions & 4 deletions Common/GPU/Vulkan/VulkanMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

using namespace PPSSPP_VK;

VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryPropertyMask)
: vulkan_(vulkan), memoryPropertyMask_(memoryPropertyMask), size_(size), usage_(usage) {
VulkanPushBuffer::VulkanPushBuffer(VulkanContext *vulkan, size_t size, VkBufferUsageFlags usage, PushBufferType type)
: vulkan_(vulkan), size_(size), usage_(usage), type_(type) {
bool res = AddBuffer();
_assert_(res);
}
Expand All @@ -54,6 +54,13 @@ bool VulkanPushBuffer::AddBuffer() {
return false;
}

VkMemoryPropertyFlags memoryPropertyMask_;
if (type_ == PushBufferType::CPU_TO_GPU) {
memoryPropertyMask_ = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
} else {
memoryPropertyMask_ = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
}

// Get the buffer memory requirements. None of this can be cached!
VkMemoryRequirements reqs;
vkGetBufferMemoryRequirements(device, info.buffer, &reqs);
Expand Down Expand Up @@ -92,7 +99,7 @@ void VulkanPushBuffer::Destroy(VulkanContext *vulkan) {

void VulkanPushBuffer::NextBuffer(size_t minSize) {
// First, unmap the current memory.
if (memoryPropertyMask_ & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
if (type_ == PushBufferType::CPU_TO_GPU)
Unmap();

buf_++;
Expand All @@ -112,7 +119,7 @@ void VulkanPushBuffer::NextBuffer(size_t minSize) {

// Now, move to the next buffer and map it.
offset_ = 0;
if (memoryPropertyMask_ & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
if (type_ == PushBufferType::CPU_TO_GPU)
Map();
}

Expand Down Expand Up @@ -150,13 +157,16 @@ void VulkanPushBuffer::Unmap() {
if (!writePtr_)
return;

/*
// We could never hit this path before because we specified the mask explicitly.
hrydgard marked this conversation as resolved.
Show resolved Hide resolved
if ((memoryPropertyMask_ & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) {
VkMappedMemoryRange range{ VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE };
range.offset = 0;
range.size = offset_;
range.memory = buffers_[buf_].deviceMemory;
vkFlushMappedMemoryRanges(vulkan_->GetDevice(), 1, &range);
}
*/

vkUnmapMemory(vulkan_->GetDevice(), buffers_[buf_].deviceMemory);
writePtr_ = nullptr;
Expand Down
20 changes: 14 additions & 6 deletions Common/GPU/Vulkan/VulkanMemory.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@
#include "Common/Log.h"
#include "Common/GPU/Vulkan/VulkanContext.h"

// Forward declaration
VK_DEFINE_HANDLE(VmaAllocation);

// VulkanMemory
//
// Vulkan memory management utils.

enum class PushBufferType {
CPU_TO_GPU,
GPU_ONLY,
};

// VulkanPushBuffer
// Simple incrementing allocator.
// Use these to push vertex, index and uniform data. Generally you'll have two of these
Expand All @@ -24,10 +32,10 @@ class VulkanPushBuffer {
};

public:
// NOTE: If you create a push buffer with only VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
// NOTE: If you create a push buffer with PushBufferType::GPU_ONLY,
// then you can't use any of the push functions as pointers will not be reachable from the CPU.
// You must in this case use Allocate() only, and pass the returned offset and the VkBuffer to Vulkan APIs.
VulkanPushBuffer(VulkanContext *vulkan, size_t size, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryPropertyMask = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VulkanPushBuffer(VulkanContext *vulkan, size_t size, VkBufferUsageFlags usage, PushBufferType type);
~VulkanPushBuffer();

void Destroy(VulkanContext *vulkan);
Expand All @@ -40,17 +48,17 @@ class VulkanPushBuffer {
offset_ = 0;
// Note: we must defrag because some buffers may be smaller than size_.
Defragment(vulkan);
if (memoryPropertyMask_ & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
if (type_ == PushBufferType::CPU_TO_GPU)
Map();
}

void BeginNoReset() {
if (memoryPropertyMask_ & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
if (type_ == PushBufferType::CPU_TO_GPU)
Map();
}

void End() {
if (memoryPropertyMask_ & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
if (type_ == PushBufferType::CPU_TO_GPU)
Unmap();
}

Expand Down Expand Up @@ -117,7 +125,7 @@ class VulkanPushBuffer {
void Defragment(VulkanContext *vulkan);

VulkanContext *vulkan_;
VkMemoryPropertyFlags memoryPropertyMask_;
PushBufferType type_;

std::vector<BufInfo> buffers_;
size_t buf_ = 0;
Expand Down
2 changes: 1 addition & 1 deletion Common/GPU/Vulkan/thin3d_vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)

for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
frame_[i].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024, usage);
frame_[i].pushBuffer = new VulkanPushBuffer(vulkan_, 1024 * 1024, usage, PushBufferType::CPU_TO_GPU);
VkResult res = RecreateDescriptorPool(&frame_[i]);
_assert_(res == VK_SUCCESS);
}
Expand Down
20 changes: 5 additions & 15 deletions GPU/Vulkan/DrawEngineVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,9 @@ void DrawEngineVulkan::InitDeviceObjects() {
// We now create descriptor pools on demand, so removed from here.
// Note that pushUBO is also used for tessellation data (search for SetPushBuffer), and to upload
// the null texture. This should be cleaned up...
frame_[i].pushUBO = new VulkanPushBuffer(vulkan, 8 * 1024 * 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT);
frame_[i].pushVertex = new VulkanPushBuffer(vulkan, 2 * 1024 * 1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
frame_[i].pushIndex = new VulkanPushBuffer(vulkan, 1 * 1024 * 1024, VK_BUFFER_USAGE_INDEX_BUFFER_BIT);

frame_[i].pushLocal = new VulkanPushBuffer(vulkan, 1 * 1024 * 1024, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
frame_[i].pushUBO = new VulkanPushBuffer(vulkan, 8 * 1024 * 1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, PushBufferType::CPU_TO_GPU);
frame_[i].pushVertex = new VulkanPushBuffer(vulkan, 2 * 1024 * 1024, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, PushBufferType::CPU_TO_GPU);
frame_[i].pushIndex = new VulkanPushBuffer(vulkan, 1 * 1024 * 1024, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, PushBufferType::CPU_TO_GPU);
}

VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
Expand All @@ -177,7 +175,7 @@ void DrawEngineVulkan::InitDeviceObjects() {
res = vkCreateSampler(device, &samp, nullptr, &nullSampler_);
_dbg_assert_(VK_SUCCESS == res);

vertexCache_ = new VulkanPushBuffer(vulkan, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
vertexCache_ = new VulkanPushBuffer(vulkan, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, PushBufferType::CPU_TO_GPU);

tessDataTransferVulkan = new TessellationDataTransferVulkan(vulkan);
tessDataTransfer = tessDataTransferVulkan;
Expand Down Expand Up @@ -210,11 +208,6 @@ void DrawEngineVulkan::FrameData::Destroy(VulkanContext *vulkan) {
delete pushIndex;
pushIndex = nullptr;
}
if (pushLocal) {
pushLocal->Destroy(vulkan);
delete pushLocal;
pushLocal = nullptr;
}
}

void DrawEngineVulkan::DestroyDeviceObjects() {
Expand Down Expand Up @@ -272,13 +265,11 @@ void DrawEngineVulkan::BeginFrame() {
frame->pushUBO->Reset();
frame->pushVertex->Reset();
frame->pushIndex->Reset();
frame->pushLocal->Reset();

VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT);
frame->pushUBO->Begin(vulkan);
frame->pushVertex->Begin(vulkan);
frame->pushIndex->Begin(vulkan);
frame->pushLocal->Begin(vulkan);

// TODO: How can we make this nicer...
tessDataTransferVulkan->SetPushBuffer(frame->pushUBO);
Expand All @@ -289,7 +280,7 @@ void DrawEngineVulkan::BeginFrame() {
if (vertexCache_->GetTotalSize() > VERTEX_CACHE_SIZE) {
vertexCache_->Destroy(vulkan);
delete vertexCache_; // orphans the buffers, they'll get deleted once no longer used by an in-flight frame.
vertexCache_ = new VulkanPushBuffer(vulkan, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT);
vertexCache_ = new VulkanPushBuffer(vulkan, VERTEX_CACHE_SIZE, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, PushBufferType::CPU_TO_GPU);
vai_.Iterate([&](uint32_t hash, VertexArrayInfoVulkan *vai) {
delete vai;
});
Expand Down Expand Up @@ -338,7 +329,6 @@ void DrawEngineVulkan::EndFrame() {
frame->pushUBO->End();
frame->pushVertex->End();
frame->pushIndex->End();
frame->pushLocal->End();
vertexCache_->End();
}

Expand Down
8 changes: 0 additions & 8 deletions GPU/Vulkan/DrawEngineVulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,11 +177,6 @@ class DrawEngineVulkan : public DrawEngineCommon {
return GetCurFrame().pushUBO;
}

// Only use Allocate on this one.
VulkanPushBuffer *GetPushBufferLocal() {
return GetCurFrame().pushLocal;
}

const DrawEngineVulkanStats &GetStats() const {
return stats_;
}
Expand Down Expand Up @@ -250,9 +245,6 @@ class DrawEngineVulkan : public DrawEngineCommon {
VulkanPushBuffer *pushVertex = nullptr;
VulkanPushBuffer *pushIndex = nullptr;

// Special push buffer in GPU local memory, for texture data conversion and similar tasks.
VulkanPushBuffer *pushLocal;

// We do rolling allocation and reset instead of caching across frames. That we might do later.
DenseHashMap<DescriptorSetKey, VkDescriptorSet, (VkDescriptorSet)VK_NULL_HANDLE> descSets;

Expand Down
2 changes: 1 addition & 1 deletion GPU/Vulkan/GPU_Vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ void GPU_Vulkan::InitDeviceObjects() {
for (int i = 0; i < VulkanContext::MAX_INFLIGHT_FRAMES; i++) {
_assert_(!frameData_[i].push_);
VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
frameData_[i].push_ = new VulkanPushBuffer(vulkan, 256 * 1024, usage);
frameData_[i].push_ = new VulkanPushBuffer(vulkan, 256 * 1024, usage, PushBufferType::CPU_TO_GPU);
}

VulkanRenderManager *rm = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
Expand Down