dxvk/src/dxvk/dxvk_memory.h

328 lines
8.6 KiB
C
Raw Normal View History

2017-10-10 22:32:13 +01:00
#pragma once
#include "dxvk_adapter.h"
namespace dxvk {
class DxvkMemoryAllocator;
class DxvkMemoryChunk;
2017-10-10 22:32:13 +01:00
/**
* \brief Memory stats
*
* Reports the amount of device memory
* allocated and used by the application.
*/
struct DxvkMemoryStats {
VkDeviceSize memoryAllocated = 0;
VkDeviceSize memoryUsed = 0;
};
2017-10-10 22:32:13 +01:00
/**
* \brief Device memory object
*
* Stores a Vulkan memory object. If the object
* was allocated on host-visible memory, it will
* be persistently mapped.
*/
struct DxvkDeviceMemory {
VkDeviceMemory memHandle = VK_NULL_HANDLE;
void* memPointer = nullptr;
VkDeviceSize memSize = 0;
VkMemoryPropertyFlags memFlags = 0;
float priority = 0.0f;
};
/**
* \brief Memory heap
*
* Corresponds to a Vulkan memory heap and stores
* its properties as well as allocation statistics.
*/
struct DxvkMemoryHeap {
VkMemoryHeap properties;
DxvkMemoryStats stats;
VkDeviceSize budget;
};
/**
* \brief Memory type
*
* Corresponds to a Vulkan memory type and stores
* memory chunks used to sub-allocate memory on
* this memory type.
*/
struct DxvkMemoryType {
DxvkMemoryHeap* heap;
uint32_t heapId;
VkMemoryType memType;
uint32_t memTypeId;
VkDeviceSize chunkSize;
std::vector<Rc<DxvkMemoryChunk>> chunks;
};
2017-10-10 22:32:13 +01:00
/**
* \brief Memory slice
*
* Represents a slice of memory that has
* been sub-allocated from a bigger chunk.
2017-10-10 22:32:13 +01:00
*/
class DxvkMemory {
friend class DxvkMemoryAllocator;
2017-10-10 22:32:13 +01:00
public:
DxvkMemory();
DxvkMemory(
DxvkMemoryAllocator* alloc,
DxvkMemoryChunk* chunk,
DxvkMemoryType* type,
VkDeviceMemory memory,
VkDeviceSize offset,
VkDeviceSize length,
void* mapPtr);
2017-10-10 22:32:13 +01:00
DxvkMemory (DxvkMemory&& other);
DxvkMemory& operator = (DxvkMemory&& other);
~DxvkMemory();
/**
* \brief Memory object
*
* This information is required when
* binding memory to Vulkan objects.
* \returns Memory object
*/
VkDeviceMemory memory() const {
return m_memory;
}
/**
* \brief Offset into device memory
2017-10-10 22:32:13 +01:00
*
* This information is required when
* binding memory to Vulkan objects.
* \returns Offset into device memory
2017-10-10 22:32:13 +01:00
*/
VkDeviceSize offset() const {
return m_offset;
2017-10-10 22:32:13 +01:00
}
/**
* \brief Pointer to mapped data
*
* \param [in] offset Byte offset
2017-10-10 22:32:13 +01:00
* \returns Pointer to mapped data
*/
void* mapPtr(VkDeviceSize offset) const {
return reinterpret_cast<char*>(m_mapPtr) + offset;
2017-10-10 22:32:13 +01:00
}
/**
* \brief Returns length of memory allocated
*
* \returns Memory size
*/
VkDeviceSize length() const {
return m_length;
}
/**
* \brief Checks whether the memory slice is defined
*
* \returns \c true if this slice points to actual device
* memory, and \c false if it is undefined.
*/
operator bool () const {
return m_memory != VK_NULL_HANDLE;
}
2017-10-10 22:32:13 +01:00
private:
DxvkMemoryAllocator* m_alloc = nullptr;
DxvkMemoryChunk* m_chunk = nullptr;
DxvkMemoryType* m_type = nullptr;
VkDeviceMemory m_memory = VK_NULL_HANDLE;
VkDeviceSize m_offset = 0;
VkDeviceSize m_length = 0;
void* m_mapPtr = nullptr;
void free();
};
/**
* \brief Memory chunk
*
* A single chunk of memory that provides a
* sub-allocator. This is not thread-safe.
*/
class DxvkMemoryChunk : public RcObject {
public:
DxvkMemoryChunk(
DxvkMemoryAllocator* alloc,
DxvkMemoryType* type,
DxvkDeviceMemory memory);
~DxvkMemoryChunk();
/**
* \brief Allocates memory from the chunk
*
* On failure, this returns a slice with
* \c VK_NULL_HANDLE as the memory handle.
* \param [in] flags Requested memory flags
* \param [in] size Number of bytes to allocate
* \param [in] align Required alignment
* \param [in] priority Requested priority
* \returns The allocated memory slice
*/
DxvkMemory alloc(
VkMemoryPropertyFlags flags,
VkDeviceSize size,
VkDeviceSize align,
float priority);
/**
* \brief Frees memory
*
* Returns a slice back to the chunk.
* Called automatically when a memory
* slice runs out of scope.
* \param [in] offset Slice offset
* \param [in] length Slice length
*/
void free(
VkDeviceSize offset,
VkDeviceSize length);
private:
struct FreeSlice {
VkDeviceSize offset;
VkDeviceSize length;
};
DxvkMemoryAllocator* m_alloc;
DxvkMemoryType* m_type;
DxvkDeviceMemory m_memory;
2018-03-20 21:36:02 +00:00
std::vector<FreeSlice> m_freeList;
};
2017-10-10 22:32:13 +01:00
/**
* \brief Memory allocator
*
* Allocates device memory for Vulkan resources.
* Memory objects will be destroyed automatically.
*/
class DxvkMemoryAllocator {
2017-10-10 22:32:13 +01:00
friend class DxvkMemory;
friend class DxvkMemoryChunk;
2017-10-10 22:32:13 +01:00
public:
DxvkMemoryAllocator(const DxvkDevice* device);
2017-10-10 22:32:13 +01:00
~DxvkMemoryAllocator();
/**
* \brief Buffer-image granularity
*
* The granularity between linear and non-linear
* resources in adjacent memory locations. See
* section 11.6 of the Vulkan spec for details.
* \returns Buffer-image granularity
*/
VkDeviceSize bufferImageGranularity() const {
return m_devProps.limits.bufferImageGranularity;
}
2017-10-10 22:32:13 +01:00
/**
* \brief Allocates device memory
*
* \param [in] req Memory requirements
* \param [in] dedAllocReq Dedicated allocation requirements
* \param [in] dedAllocInfo Dedicated allocation info
* \param [in] flags Memory type flags
* \param [in] priority Device-local memory priority
2017-10-10 22:32:13 +01:00
* \returns Allocated memory slice
*/
DxvkMemory alloc(
const VkMemoryRequirements* req,
const VkMemoryDedicatedRequirements& dedAllocReq,
const VkMemoryDedicatedAllocateInfo& dedAllocInfo,
VkMemoryPropertyFlags flags,
float priority);
2017-10-10 22:32:13 +01:00
/**
* \brief Queries memory stats
*
* Returns the total amount of memory
* allocated and used for a given heap.
* \param [in] heap Heap index
* \returns Memory stats for this heap
*/
DxvkMemoryStats getMemoryStats(uint32_t heap) const {
return m_memHeaps[heap].stats;
}
2017-10-10 22:32:13 +01:00
private:
2017-10-10 22:32:13 +01:00
const Rc<vk::DeviceFn> m_vkd;
const DxvkDevice* m_device;
const VkPhysicalDeviceProperties m_devProps;
2017-10-10 22:32:13 +01:00
const VkPhysicalDeviceMemoryProperties m_memProps;
std::mutex m_mutex;
std::array<DxvkMemoryHeap, VK_MAX_MEMORY_HEAPS> m_memHeaps;
std::array<DxvkMemoryType, VK_MAX_MEMORY_TYPES> m_memTypes;
DxvkMemory tryAlloc(
const VkMemoryRequirements* req,
const VkMemoryDedicatedAllocateInfo* dedAllocInfo,
VkMemoryPropertyFlags flags,
float priority);
DxvkMemory tryAllocFromType(
DxvkMemoryType* type,
VkMemoryPropertyFlags flags,
VkDeviceSize size,
VkDeviceSize align,
float priority,
const VkMemoryDedicatedAllocateInfo* dedAllocInfo);
DxvkDeviceMemory tryAllocDeviceMemory(
DxvkMemoryType* type,
VkMemoryPropertyFlags flags,
VkDeviceSize size,
float priority,
const VkMemoryDedicatedAllocateInfo* dedAllocInfo);
void free(
const DxvkMemory& memory);
void freeChunkMemory(
DxvkMemoryType* type,
DxvkMemoryChunk* chunk,
VkDeviceSize offset,
VkDeviceSize length);
void freeDeviceMemory(
DxvkMemoryType* type,
DxvkDeviceMemory memory);
VkDeviceSize pickChunkSize(
uint32_t memTypeId) const;
2017-10-10 22:32:13 +01:00
};
}