2017-10-10 22:32:13 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include "dxvk_adapter.h"
|
|
|
|
|
|
|
|
namespace dxvk {
|
|
|
|
|
|
|
|
class DxvkMemoryAllocator;
|
2018-05-29 13:48:27 +01:00
|
|
|
class DxvkMemoryChunk;
|
2017-10-10 22:32:13 +01:00
|
|
|
|
2018-04-03 14:32:00 +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;
|
|
|
|
};
|
2022-02-23 20:56:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
enum class DxvkSharedHandleMode {
|
|
|
|
None,
|
|
|
|
Import,
|
|
|
|
Export,
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Shared handle info
|
|
|
|
*
|
|
|
|
* The shared resource information for a given resource.
|
|
|
|
*/
|
|
|
|
struct DxvkSharedHandleInfo {
|
|
|
|
DxvkSharedHandleMode mode = DxvkSharedHandleMode::None;
|
|
|
|
VkExternalMemoryHandleTypeFlagBits type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_FLAG_BITS_MAX_ENUM;
|
|
|
|
union {
|
2022-08-21 20:09:35 +01:00
|
|
|
// When we want to implement this on non-Windows platforms,
|
|
|
|
// we could add a `int fd` here, etc.
|
|
|
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
2022-02-23 20:56:31 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-05-29 13:48:27 +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 {
|
2018-09-17 08:08:00 +01:00
|
|
|
VkDeviceMemory memHandle = VK_NULL_HANDLE;
|
|
|
|
void* memPointer = nullptr;
|
|
|
|
VkDeviceSize memSize = 0;
|
|
|
|
VkMemoryPropertyFlags memFlags = 0;
|
2019-01-30 10:38:55 +00:00
|
|
|
float priority = 0.0f;
|
2018-05-29 13:48:27 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Memory heap
|
|
|
|
*
|
|
|
|
* Corresponds to a Vulkan memory heap and stores
|
|
|
|
* its properties as well as allocation statistics.
|
|
|
|
*/
|
|
|
|
struct DxvkMemoryHeap {
|
|
|
|
VkMemoryHeap properties;
|
|
|
|
DxvkMemoryStats stats;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \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;
|
2018-11-13 11:21:53 +00:00
|
|
|
uint32_t heapId;
|
2018-05-29 13:48:27 +01:00
|
|
|
|
|
|
|
VkMemoryType memType;
|
|
|
|
uint32_t memTypeId;
|
|
|
|
|
|
|
|
std::vector<Rc<DxvkMemoryChunk>> chunks;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-10-10 22:32:13 +01:00
|
|
|
/**
|
|
|
|
* \brief Memory slice
|
2017-12-16 15:48:42 +00:00
|
|
|
*
|
|
|
|
* Represents a slice of memory that has
|
|
|
|
* been sub-allocated from a bigger chunk.
|
2017-10-10 22:32:13 +01:00
|
|
|
*/
|
|
|
|
class DxvkMemory {
|
2018-05-29 13:48:27 +01:00
|
|
|
friend class DxvkMemoryAllocator;
|
2017-10-10 22:32:13 +01:00
|
|
|
public:
|
|
|
|
|
|
|
|
DxvkMemory();
|
|
|
|
DxvkMemory(
|
2018-05-29 13:48:27 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2017-12-16 15:48:42 +00:00
|
|
|
* \brief Offset into device memory
|
2017-10-10 22:32:13 +01:00
|
|
|
*
|
|
|
|
* This information is required when
|
|
|
|
* binding memory to Vulkan objects.
|
2017-12-16 15:48:42 +00:00
|
|
|
* \returns Offset into device memory
|
2017-10-10 22:32:13 +01:00
|
|
|
*/
|
|
|
|
VkDeviceSize offset() const {
|
2017-12-16 15:48:42 +00:00
|
|
|
return m_offset;
|
2017-10-10 22:32:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Pointer to mapped data
|
2017-12-10 14:57:51 +00:00
|
|
|
*
|
|
|
|
* \param [in] offset Byte offset
|
2017-10-10 22:32:13 +01:00
|
|
|
* \returns Pointer to mapped data
|
|
|
|
*/
|
2017-12-10 14:57:51 +00:00
|
|
|
void* mapPtr(VkDeviceSize offset) const {
|
|
|
|
return reinterpret_cast<char*>(m_mapPtr) + offset;
|
2017-10-10 22:32:13 +01:00
|
|
|
}
|
2018-05-29 13:48:27 +01:00
|
|
|
|
2019-07-18 18:05:01 +01:00
|
|
|
/**
|
|
|
|
* \brief Returns length of memory allocated
|
|
|
|
*
|
|
|
|
* \returns Memory size
|
|
|
|
*/
|
|
|
|
VkDeviceSize length() const {
|
|
|
|
return m_length;
|
|
|
|
}
|
|
|
|
|
2018-05-29 13:48:27 +01:00
|
|
|
/**
|
|
|
|
* \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.
|
|
|
|
*/
|
2024-01-27 03:42:40 +00:00
|
|
|
explicit operator bool () const {
|
2018-05-29 13:48:27 +01:00
|
|
|
return m_memory != VK_NULL_HANDLE;
|
|
|
|
}
|
2017-10-10 22:32:13 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
2018-05-29 13:48:27 +01:00
|
|
|
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;
|
2017-12-16 15:48:42 +00:00
|
|
|
|
2018-04-03 14:32:00 +01:00
|
|
|
void free();
|
|
|
|
|
2017-12-16 15:48:42 +00:00
|
|
|
};
|
2022-01-12 15:22:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Memory allocation flags
|
|
|
|
*
|
|
|
|
* Used to batch similar allocations into the same
|
|
|
|
* set of chunks, which may help with fragmentation.
|
|
|
|
*/
|
|
|
|
enum class DxvkMemoryFlag : uint32_t {
|
|
|
|
Small = 0, ///< Small allocation
|
|
|
|
GpuReadable = 1, ///< Medium-priority resource
|
|
|
|
GpuWritable = 2, ///< High-priority resource
|
2022-02-12 16:44:20 +00:00
|
|
|
Transient = 3, ///< Resource is short-lived
|
|
|
|
IgnoreConstraints = 4, ///< Ignore most allocation flags
|
2022-01-12 15:22:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
using DxvkMemoryFlags = Flags<DxvkMemoryFlag>;
|
2017-12-16 15:48:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Memory chunk
|
|
|
|
*
|
|
|
|
* A single chunk of memory that provides a
|
|
|
|
* sub-allocator. This is not thread-safe.
|
|
|
|
*/
|
|
|
|
class DxvkMemoryChunk : public RcObject {
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
DxvkMemoryChunk(
|
2018-05-29 13:48:27 +01:00
|
|
|
DxvkMemoryAllocator* alloc,
|
|
|
|
DxvkMemoryType* type,
|
2022-01-12 15:22:05 +00:00
|
|
|
DxvkDeviceMemory memory,
|
|
|
|
DxvkMemoryFlags m_hints);
|
2017-12-16 15:48:42 +00:00
|
|
|
|
|
|
|
~DxvkMemoryChunk();
|
2018-09-17 08:08:00 +01:00
|
|
|
|
2017-12-16 15:48:42 +00:00
|
|
|
/**
|
|
|
|
* \brief Allocates memory from the chunk
|
|
|
|
*
|
|
|
|
* On failure, this returns a slice with
|
|
|
|
* \c VK_NULL_HANDLE as the memory handle.
|
2022-01-12 15:22:05 +00:00
|
|
|
* \param [in] flags Requested memory type flags
|
2017-12-16 15:48:42 +00:00
|
|
|
* \param [in] size Number of bytes to allocate
|
|
|
|
* \param [in] align Required alignment
|
2022-01-12 15:22:05 +00:00
|
|
|
* \param [in] hints Memory category
|
2017-12-16 15:48:42 +00:00
|
|
|
* \returns The allocated memory slice
|
|
|
|
*/
|
|
|
|
DxvkMemory alloc(
|
2018-09-17 08:08:00 +01:00
|
|
|
VkMemoryPropertyFlags flags,
|
|
|
|
VkDeviceSize size,
|
2019-01-30 10:38:55 +00:00
|
|
|
VkDeviceSize align,
|
2022-01-12 15:22:05 +00:00
|
|
|
DxvkMemoryFlags hints);
|
2017-12-16 15:48:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \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);
|
2022-01-12 13:11:42 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Checks whether the chunk is being used
|
|
|
|
* \returns \c true if there are no allocations left
|
|
|
|
*/
|
|
|
|
bool isEmpty() const;
|
|
|
|
|
2022-01-13 16:35:17 +00:00
|
|
|
/**
|
|
|
|
* \brief Checks whether hints and flags of another chunk match
|
|
|
|
* \param [in] other The chunk to compare to
|
|
|
|
*/
|
|
|
|
bool isCompatible(const Rc<DxvkMemoryChunk>& other) const;
|
|
|
|
|
2017-12-16 15:48:42 +00:00
|
|
|
private:
|
|
|
|
|
|
|
|
struct FreeSlice {
|
|
|
|
VkDeviceSize offset;
|
|
|
|
VkDeviceSize length;
|
|
|
|
};
|
|
|
|
|
2018-05-29 13:48:27 +01:00
|
|
|
DxvkMemoryAllocator* m_alloc;
|
|
|
|
DxvkMemoryType* m_type;
|
|
|
|
DxvkDeviceMemory m_memory;
|
2022-01-12 15:22:05 +00:00
|
|
|
DxvkMemoryFlags m_hints;
|
2018-03-20 21:36:02 +00:00
|
|
|
|
2017-12-16 15:48:42 +00:00
|
|
|
std::vector<FreeSlice> m_freeList;
|
2022-01-12 15:22:05 +00:00
|
|
|
|
|
|
|
bool checkHints(DxvkMemoryFlags hints) const;
|
2017-12-16 15:48:42 +00:00
|
|
|
|
|
|
|
};
|
2022-08-25 17:20:11 +01:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Memory requirement info
|
|
|
|
*/
|
|
|
|
struct DxvkMemoryRequirements {
|
2023-01-14 00:02:03 +00:00
|
|
|
VkImageTiling tiling;
|
2022-08-25 17:20:11 +01:00
|
|
|
VkMemoryDedicatedRequirements dedicated;
|
|
|
|
VkMemoryRequirements2 core;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \brief Memory allocation info
|
|
|
|
*/
|
|
|
|
struct DxvkMemoryProperties {
|
|
|
|
VkExportMemoryAllocateInfo sharedExport;
|
|
|
|
VkImportMemoryWin32HandleInfoKHR sharedImportWin32;
|
|
|
|
VkMemoryDedicatedAllocateInfo dedicated;
|
|
|
|
VkMemoryPropertyFlags flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2017-10-10 22:32:13 +01:00
|
|
|
/**
|
|
|
|
* \brief Memory allocator
|
|
|
|
*
|
|
|
|
* Allocates device memory for Vulkan resources.
|
|
|
|
* Memory objects will be destroyed automatically.
|
|
|
|
*/
|
2019-07-30 19:06:59 +01:00
|
|
|
class DxvkMemoryAllocator {
|
2017-10-10 22:32:13 +01:00
|
|
|
friend class DxvkMemory;
|
2018-05-29 13:48:27 +01:00
|
|
|
friend class DxvkMemoryChunk;
|
2022-01-12 15:22:05 +00:00
|
|
|
|
|
|
|
constexpr static VkDeviceSize SmallAllocationThreshold = 256 << 10;
|
2017-10-10 22:32:13 +01:00
|
|
|
public:
|
|
|
|
|
2022-08-20 20:57:46 +01:00
|
|
|
DxvkMemoryAllocator(DxvkDevice* device);
|
2017-10-10 22:32:13 +01:00
|
|
|
~DxvkMemoryAllocator();
|
|
|
|
|
2022-08-20 20:57:46 +01:00
|
|
|
/**
|
|
|
|
* \brief Memory type mask for sparse resources
|
|
|
|
* \returns Sparse resource memory types
|
|
|
|
*/
|
|
|
|
uint32_t getSparseMemoryTypes() const {
|
|
|
|
return m_sparseMemoryTypes;
|
|
|
|
}
|
|
|
|
|
2017-10-10 22:32:13 +01:00
|
|
|
/**
|
|
|
|
* \brief Allocates device memory
|
|
|
|
*
|
|
|
|
* \param [in] req Memory requirements
|
2022-08-25 17:20:11 +01:00
|
|
|
* \param [in] info Memory properties
|
2022-01-12 15:22:05 +00:00
|
|
|
* \param [in] hints Memory hints
|
2017-10-10 22:32:13 +01:00
|
|
|
* \returns Allocated memory slice
|
|
|
|
*/
|
|
|
|
DxvkMemory alloc(
|
2023-01-14 00:02:03 +00:00
|
|
|
DxvkMemoryRequirements req,
|
2022-08-25 17:20:11 +01:00
|
|
|
DxvkMemoryProperties info,
|
2022-01-12 15:22:05 +00:00
|
|
|
DxvkMemoryFlags hints);
|
2017-10-10 22:32:13 +01:00
|
|
|
|
2019-12-13 10:15:52 +00: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:
|
2018-05-29 13:48:27 +01:00
|
|
|
|
2022-08-20 20:57:46 +01:00
|
|
|
DxvkDevice* m_device;
|
|
|
|
VkPhysicalDeviceMemoryProperties m_memProps;
|
2017-10-10 22:32:13 +01:00
|
|
|
|
2021-06-28 18:19:29 +01:00
|
|
|
dxvk::mutex m_mutex;
|
2018-05-29 13:48:27 +01:00
|
|
|
std::array<DxvkMemoryHeap, VK_MAX_MEMORY_HEAPS> m_memHeaps;
|
|
|
|
std::array<DxvkMemoryType, VK_MAX_MEMORY_TYPES> m_memTypes;
|
2020-01-28 11:33:37 +00:00
|
|
|
|
2023-03-01 10:52:55 +00:00
|
|
|
VkDeviceSize m_maxChunkSize;
|
|
|
|
|
2022-08-20 20:57:46 +01:00
|
|
|
uint32_t m_sparseMemoryTypes = 0u;
|
|
|
|
|
2018-02-27 11:36:44 +00:00
|
|
|
DxvkMemory tryAlloc(
|
2022-08-25 17:20:11 +01:00
|
|
|
const DxvkMemoryRequirements& req,
|
|
|
|
const DxvkMemoryProperties& info,
|
2022-01-12 15:22:05 +00:00
|
|
|
DxvkMemoryFlags hints);
|
2018-02-27 11:36:44 +00:00
|
|
|
|
2018-05-29 13:48:27 +01:00
|
|
|
DxvkMemory tryAllocFromType(
|
2018-06-24 09:55:42 +01:00
|
|
|
DxvkMemoryType* type,
|
|
|
|
VkDeviceSize size,
|
|
|
|
VkDeviceSize align,
|
2022-08-25 17:20:11 +01:00
|
|
|
const DxvkMemoryProperties& info,
|
|
|
|
DxvkMemoryFlags hints);
|
2018-05-29 13:48:27 +01:00
|
|
|
|
|
|
|
DxvkDeviceMemory tryAllocDeviceMemory(
|
2018-06-24 09:55:42 +01:00
|
|
|
DxvkMemoryType* type,
|
|
|
|
VkDeviceSize size,
|
2022-08-25 17:20:11 +01:00
|
|
|
DxvkMemoryProperties info,
|
|
|
|
DxvkMemoryFlags hints);
|
2018-05-29 13:48:27 +01:00
|
|
|
|
|
|
|
void free(
|
|
|
|
const DxvkMemory& memory);
|
|
|
|
|
|
|
|
void freeChunkMemory(
|
|
|
|
DxvkMemoryType* type,
|
|
|
|
DxvkMemoryChunk* chunk,
|
|
|
|
VkDeviceSize offset,
|
|
|
|
VkDeviceSize length);
|
|
|
|
|
|
|
|
void freeDeviceMemory(
|
|
|
|
DxvkMemoryType* type,
|
|
|
|
DxvkDeviceMemory memory);
|
2018-07-09 18:18:39 +01:00
|
|
|
|
|
|
|
VkDeviceSize pickChunkSize(
|
2022-01-12 15:22:05 +00:00
|
|
|
uint32_t memTypeId,
|
|
|
|
DxvkMemoryFlags hints) const;
|
2018-05-29 13:48:27 +01:00
|
|
|
|
2022-01-13 16:35:17 +00:00
|
|
|
bool shouldFreeChunk(
|
|
|
|
const DxvkMemoryType* type,
|
|
|
|
const Rc<DxvkMemoryChunk>& chunk) const;
|
|
|
|
|
|
|
|
bool shouldFreeEmptyChunks(
|
|
|
|
const DxvkMemoryHeap* heap,
|
|
|
|
VkDeviceSize allocationSize) const;
|
|
|
|
|
|
|
|
void freeEmptyChunks(
|
|
|
|
const DxvkMemoryHeap* heap);
|
|
|
|
|
2022-08-20 20:57:46 +01:00
|
|
|
uint32_t determineSparseMemoryTypes(
|
|
|
|
DxvkDevice* device) const;
|
|
|
|
|
2023-03-01 10:52:55 +00:00
|
|
|
VkDeviceSize determineMaxChunkSize(
|
|
|
|
DxvkDevice* device) const;
|
|
|
|
|
2023-01-14 01:26:42 +00:00
|
|
|
void logMemoryError(
|
|
|
|
const VkMemoryRequirements& req) const;
|
|
|
|
|
|
|
|
void logMemoryStats() const;
|
|
|
|
|
2017-10-10 22:32:13 +01:00
|
|
|
};
|
|
|
|
|
2022-02-23 20:56:31 +00:00
|
|
|
}
|