Files
OpenVulkano/openVulkanoCpp/Vulkan/Resources/ManagedBuffer.hpp
2024-09-30 16:44:17 +02:00

126 lines
3.1 KiB
C++

/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#define CRASH_ON_MULTIPLE_MAPPINGS_TO_SAME_ALLOCATION
#include "MemoryAllocation.hpp"
#include "MemoryPool.hpp"
#include <memory>
#include <functional>
namespace OpenVulkano::Vulkan
{
class ManagedBuffer
{
public:
using Ptr = std::unique_ptr<ManagedBuffer, ManagedBufferDeleter>;
MemoryAllocation* allocation;
vk::DeviceSize offset, size;
vk::Buffer buffer;
vk::BufferUsageFlags usage;
vk::MemoryPropertyFlags properties;
void* mapped = nullptr;
ManagedBuffer(MemoryAllocation* alloc, vk::DeviceSize offset, vk::DeviceSize size, vk::Buffer buffer, vk::BufferUsageFlags usageFlags, vk::MemoryPropertyFlags memProperties)
: allocation(alloc), offset(offset), size(size), buffer(buffer), usage(usageFlags), properties(memProperties), mapped(nullptr)
{}
~ManagedBuffer()
{
if (allocation) [[likely]] allocation->device.destroy(buffer);
}
[[nodiscard]] bool IsLast() const
{
return (offset + size == allocation->used);
}
[[nodiscard]] bool IsMapped() const
{
return mapped || allocation->mapped;
}
[[nodiscard]] void* GetMappedMemory() const { return mapped; }
template <typename T = char>
[[nodiscard]] T* GetMappedMemory() const { return static_cast<T*>(mapped); }
/**
* \brief Maps the buffer into the memory of the host.
* \tparam T The type of the buffers data.
* \param offset The offset from where to map the buffer.
* \param size The size to be mapped. VK_WHOLE_SIZE to map the whole buffer.
* \pparam longTermMapping If the mapping is intended to be held long term. Short term mappings must be freed before mapping a different region in the same memory allocation for them to work reliable with all drivers.
* \return The pointer to the mapped buffer.
*/
template <typename T = void>
T* Map(vk::DeviceSize offset = 0, vk::DeviceSize size = VK_WHOLE_SIZE, bool longTermMapping = true)
{
if (!mapped)
{
if (allocation->mapped || longTermMapping)
{
mapped = static_cast<uint8_t*>(allocation->Map()) + offset + this->offset;
}
else
{
if (size == VK_WHOLE_SIZE) size = this->size;
mapped = allocation->MapChild(this->offset + offset, size);
}
}
return static_cast<T*>(mapped);
}
/**
* \brief Un-maps the buffer from the host.
*/
void UnMap()
{
if (mapped)
{
if (allocation->mapped)
{
allocation->UnMap();
}
else
{
allocation->UnMapChild();
}
mapped = nullptr;
}
}
void Copy(void* data)
{
if (mapped)
{
memcpy(mapped, data, size);
}
else
{
void* dataMapped = Map(0, VK_WHOLE_SIZE, false);
memcpy(dataMapped, data, size);
UnMap();
}
}
void Copy(const void* data, vk::DeviceSize size, vk::DeviceSize offset)
{
if(mapped) memcpy(static_cast<char*>(mapped) + offset, data, size);
else
{
void* dataMapped = Map(offset, size, false);
memcpy(dataMapped, data, size);
UnMap();
}
}
};
}