#pragma once
#include <cstdint>
#include <cstring>
#include <functional>
#include <vector>
#include "Common/Data/Collections/FastVec.h"
#include "Common/GPU/Vulkan/VulkanContext.h"
#include "Common/GPU/GPUBackendCommon.h"
VK_DEFINE_HANDLE(VmaAllocation);
class VulkanPushPool : public GPUMemoryManager {
public:
VulkanPushPool(VulkanContext *vulkan, const char *name, size_t originalBlockSize, VkBufferUsageFlags usage);
~VulkanPushPool();
void Destroy();
void BeginFrame();
const char *Name() const override {
return name_;
}
void GetDebugString(char *buffer, size_t bufSize) const override;
uint8_t *Allocate(VkDeviceSize numBytes, VkDeviceSize alignment, VkBuffer *vkbuf, uint32_t *bindOffset) {
_dbg_assert_(curBlockIndex_ >= 0);
Block &block = blocks_[curBlockIndex_];
VkDeviceSize offset = (block.used + (alignment - 1)) & ~(alignment - 1);
if (offset + numBytes <= block.size) {
block.used = offset + numBytes;
*vkbuf = block.buffer;
*bindOffset = (uint32_t)offset;
return block.writePtr + offset;
}
NextBlock(numBytes);
*vkbuf = blocks_[curBlockIndex_].buffer;
*bindOffset = 0;
return blocks_[curBlockIndex_].writePtr;
}
VkDeviceSize Push(const void *data, VkDeviceSize numBytes, int alignment, VkBuffer *vkbuf) {
uint32_t bindOffset;
uint8_t *ptr = Allocate(numBytes, alignment, vkbuf, &bindOffset);
memcpy(ptr, data, numBytes);
return bindOffset;
}
size_t GetUsedThisFrame() const;
private:
void NextBlock(VkDeviceSize allocationSize);
struct Block {
~Block();
VkBuffer buffer;
VmaAllocation allocation;
VkDeviceSize size;
VkDeviceSize used;
int frameIndex;
bool original;
double lastUsed;
uint8_t *writePtr;
void Destroy(VulkanContext *vulkan);
};
Block CreateBlock(size_t sz);
VulkanContext *vulkan_;
VkDeviceSize originalBlockSize_;
std::vector<Block> blocks_;
VkBufferUsageFlags usage_;
int curBlockIndex_ = -1;
const char *name_;
};