Skip to content

Commit 4a1e10c

Browse files
committed
Add Vulkan Memory Allocator integration and refactor memory management
1 parent fa20b7c commit 4a1e10c

File tree

14 files changed

+568
-154
lines changed

14 files changed

+568
-154
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ asset/rectified
44
asset/rectified.zip
55
asset/SanMiguel
66
imgui.ini
7+
.claude

CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ find_package(imgui CONFIG REQUIRED)
4646
find_package(glfw3 CONFIG REQUIRED)
4747
find_package(spdlog CONFIG REQUIRED)
4848
find_package(tinyobjloader CONFIG REQUIRED)
49+
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
4950

5051
target_link_libraries(${PROJECT_NAME} PUBLIC
5152
spirv_reflect
@@ -56,6 +57,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC
5657
spdlog::spdlog_header_only
5758
tinyobjloader::tinyobjloader
5859
KTX::ktx
60+
VulkanMemoryAllocator::VulkanMemoryAllocator
5961

6062
optimized ${VULKAN_LIB}/slang.lib
6163

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
#pragma once
22
#include "Context.hpp"
3+
#include "MemoryManager.hpp"
34

45
namespace rv {
56
struct BufferCreateInfo {
67
vk::BufferUsageFlags usage;
7-
8-
vk::MemoryPropertyFlags memory;
9-
108
size_t size = 0;
11-
9+
MemoryUsage memoryUsage = MemoryUsage::GpuOnly;
1210
std::string debugName;
1311
};
1412

@@ -17,30 +15,42 @@ class Buffer {
1715

1816
public:
1917
Buffer(const Context& context, const BufferCreateInfo& createInfo);
18+
~Buffer();
2019

21-
auto getBuffer() const -> vk::Buffer { return *m_buffer; }
20+
// コピー・ムーブ禁止(VMA割り当てのため)
21+
Buffer(const Buffer&) = delete;
22+
Buffer& operator=(const Buffer&) = delete;
23+
Buffer(Buffer&&) = delete;
24+
Buffer& operator=(Buffer&&) = delete;
25+
26+
auto getBuffer() const -> vk::Buffer {
27+
return m_vmaAllocation.buffer;
28+
}
2229
auto getSize() const -> vk::DeviceSize { return m_size; }
23-
auto getInfo() const -> vk::DescriptorBufferInfo { return {*m_buffer, 0, m_size}; }
30+
auto getInfo() const -> vk::DescriptorBufferInfo {
31+
return {getBuffer(), 0, m_size};
32+
}
2433
auto getAddress() const -> vk::DeviceAddress;
2534

2635
auto map() -> void*;
2736
void unmap();
2837
void copy(const void* data);
2938

3039
void prepareStagingBuffer();
40+
41+
// VMA関連のメソッド
42+
const BufferAllocation& getAllocation() const { return m_vmaAllocation; }
3143

3244
private:
3345
const Context* m_context = nullptr;
34-
35-
vk::UniqueBuffer m_buffer;
36-
vk::UniqueDeviceMemory m_memory;
3746
vk::DeviceSize m_size = 0u;
38-
39-
// For host buffer
47+
BufferAllocation m_vmaAllocation;
48+
49+
// ホストバッファー用
4050
void* m_mapped = nullptr;
41-
bool m_isHostVisible;
51+
bool m_isHostVisible = false;
4252

43-
// For device buffer
53+
// デバイスバッファー用
4454
BufferHandle m_stagingBuffer;
4555
};
4656
} // namespace rv

include/reactive/Graphics/Context.hpp

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include <vulkan/vulkan.hpp>
1313

14+
#include "MemoryManager.hpp"
15+
1416
namespace std {
1517
template <>
1618
struct hash<vk::QueueFlags> {
@@ -126,17 +128,6 @@ static constexpr vk::BufferUsageFlags Scratch =
126128
vk::BufferUsageFlagBits::eShaderDeviceAddress;
127129
} // namespace BufferUsage
128130

129-
namespace MemoryUsage {
130-
static constexpr vk::MemoryPropertyFlags Device =
131-
vk::MemoryPropertyFlagBits::eDeviceLocal;
132-
static constexpr vk::MemoryPropertyFlags Host =
133-
vk::MemoryPropertyFlagBits::eHostVisible |
134-
vk::MemoryPropertyFlagBits::eHostCoherent;
135-
static constexpr vk::MemoryPropertyFlags DeviceHost =
136-
vk::MemoryPropertyFlagBits::eDeviceLocal |
137-
vk::MemoryPropertyFlagBits::eHostVisible |
138-
vk::MemoryPropertyFlagBits::eHostCoherent;
139-
} // namespace MemoryUsage
140131

141132
namespace ImageUsage {
142133
static constexpr vk::ImageUsageFlags ColorAttachment =
@@ -220,10 +211,6 @@ class Context {
220211
void oneTimeSubmit(const std::function<void(CommandBufferHandle)>& command,
221212
vk::QueueFlags flag = QueueFlags::General) const;
222213

223-
// Memory
224-
auto findMemoryTypeIndex(vk::MemoryRequirements requirements,
225-
vk::MemoryPropertyFlags memoryProp) const -> uint32_t;
226-
227214
// Physical device
228215
template <typename T>
229216
auto getPhysicalDeviceProperties2() const -> T {
@@ -280,6 +267,12 @@ class Context {
280267

281268
auto createFence(const FenceCreateInfo& createInfo) const -> FenceHandle;
282269

270+
// Memory management
271+
auto getMemoryManager() const -> const MemoryManager& { return *m_memoryManager; }
272+
273+
// Debug utils
274+
auto isDebugUtilsEnabled() const -> bool { return m_debugMessenger.get(); }
275+
283276
private:
284277
static auto VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
285278
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
@@ -311,5 +304,7 @@ class Context {
311304
mutable std::map<vk::QueueFlags, std::vector<ThreadQueue>> m_queues;
312305
std::unordered_map<vk::QueueFlags, uint32_t> m_queueFamilies;
313306
vk::UniqueDescriptorPool m_descriptorPool;
307+
308+
std::unique_ptr<MemoryManager> m_memoryManager;
314309
};
315310
} // namespace rv

include/reactive/Graphics/Image.hpp

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22
#include <vulkan/vulkan.hpp>
33
#include "Context.hpp"
4+
#include "MemoryManager.hpp"
45

56
namespace rv {
67
class Buffer;
@@ -21,21 +22,16 @@ struct SamplerCreateInfo {
2122
// mipLevels: UINT32_MAX の場合は画像解像度から最大ミップレベルを自動計算する
2223
struct ImageCreateInfo {
2324
vk::ImageUsageFlags usage;
24-
2525
vk::Extent3D extent = {1, 1, 1};
26-
2726
vk::ImageType imageType = vk::ImageType::e2D;
28-
2927
vk::Format format;
30-
3128
uint32_t mipLevels = 1;
32-
29+
MemoryUsage memoryUsage = MemoryUsage::GpuOnly;
30+
3331
std::optional<ImageViewCreateInfo> viewInfo;
34-
3532
std::optional<SamplerCreateInfo> samplerInfo;
36-
37-
// Debug
38-
std::string debugName{};
33+
34+
std::string debugName;
3935
};
4036

4137
class Image {
@@ -44,6 +40,7 @@ class Image {
4440
public:
4541
Image(const Context& context, const ImageCreateInfo& createInfo);
4642

43+
// 外部イメージ用コンストラクタ(スワップチェーンなど)
4744
Image(vk::Image image,
4845
vk::ImageView view,
4946
vk::Extent3D extent,
@@ -54,23 +51,20 @@ class Image {
5451
m_viewType{vk::ImageViewType::e2D},
5552
m_extent{extent},
5653
m_format{format},
57-
m_aspect{aspect} {}
58-
59-
Image(const Context* context,
60-
vk::Image _image,
61-
vk::Format _imageFormat,
62-
vk::ImageLayout _imageLayout,
63-
vk::DeviceMemory _deviceMemory,
64-
vk::ImageViewType _viewType,
65-
uint32_t _width,
66-
uint32_t _height,
67-
uint32_t _depth,
68-
uint32_t _levelCount,
69-
uint32_t _layerCount);
54+
m_aspect{aspect},
55+
m_hasOwnership{false} {}
7056

7157
~Image();
7258

73-
auto getImage() const -> vk::Image { return m_image; }
59+
// コピー・ムーブ禁止(VMA割り当てのため)
60+
Image(const Image&) = delete;
61+
Image& operator=(const Image&) = delete;
62+
Image(Image&&) = delete;
63+
Image& operator=(Image&&) = delete;
64+
65+
auto getImage() const -> vk::Image {
66+
return m_vmaAllocation.image ? m_vmaAllocation.image : m_image;
67+
}
7468
auto getView() const -> vk::ImageView { return m_view; }
7569
auto getSampler() const -> vk::Sampler { return m_sampler; }
7670
auto getInfo() const -> vk::DescriptorImageInfo { return {m_sampler, m_view, m_layout}; }
@@ -81,6 +75,9 @@ class Image {
8175
auto getFormat() const -> vk::Format { return m_format; }
8276
auto getLayerCount() const -> uint32_t { return m_layerCount; }
8377
auto getViewType() const -> vk::ImageViewType { return m_viewType; }
78+
79+
// VMA関連のメソッド
80+
const ImageAllocation& getAllocation() const { return m_vmaAllocation; }
8481

8582
// Ensure that data is pre-filled
8683
// ImageLayout is implicitly shifted to ShaderReadOnlyOptimal
@@ -145,15 +142,16 @@ class Image {
145142

146143
const Context* m_context = nullptr;
147144
std::string m_debugName;
145+
bool m_hasOwnership = false;
148146

149-
vk::Image m_image;
150-
vk::DeviceMemory m_memory;
147+
// VMA管理のイメージまたは外部リソース
148+
ImageAllocation m_vmaAllocation;
149+
vk::Image m_image; // 外部リソース用
150+
151151
vk::ImageView m_view;
152152
vk::Sampler m_sampler;
153153
vk::ImageViewType m_viewType;
154154

155-
bool m_hasOwnership = false;
156-
157155
vk::ImageLayout m_layout = vk::ImageLayout::eUndefined;
158156
vk::Extent3D m_extent;
159157
vk::Format m_format = {};
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
#pragma once
2+
#include "reactive/common.hpp"
3+
4+
namespace rv {
5+
6+
// Forward declarations
7+
class Context;
8+
9+
// メモリ割り当て情報
10+
struct BufferAllocation {
11+
vk::Buffer buffer;
12+
VmaAllocation allocation;
13+
VmaAllocationInfo info;
14+
15+
BufferAllocation() = default;
16+
BufferAllocation(vk::Buffer buf, VmaAllocation alloc, const VmaAllocationInfo& allocInfo)
17+
: buffer(buf), allocation(alloc), info(allocInfo) {}
18+
19+
// データマッピング用ヘルパー
20+
void* getMappedData() const { return info.pMappedData; }
21+
bool isMapped() const { return info.pMappedData != nullptr; }
22+
};
23+
24+
struct ImageAllocation {
25+
vk::Image image;
26+
VmaAllocation allocation;
27+
VmaAllocationInfo info;
28+
29+
ImageAllocation() = default;
30+
ImageAllocation(vk::Image img, VmaAllocation alloc, const VmaAllocationInfo& allocInfo)
31+
: image(img), allocation(alloc), info(allocInfo) {}
32+
};
33+
34+
// メモリ使用方法を指定
35+
enum class MemoryUsage {
36+
GpuOnly, // GPU専用(Device Local)
37+
CpuOnly, // CPU専用(Host Visible)
38+
CpuToGpu, // CPU→GPU転送用(Host Visible + Host Coherent)
39+
GpuToCpu, // GPU→CPU読み取り用(Host Visible + Host Cached)
40+
CpuCopy, // CPU側コピー用(Host Visible + Host Coherent + Host Cached)
41+
GpuLazilyAllocated // 遅延割り当て(Lazily Allocated)
42+
};
43+
44+
// バッファー作成情報
45+
struct BufferCreateInfo {
46+
vk::DeviceSize size;
47+
vk::BufferUsageFlags usage;
48+
MemoryUsage memoryUsage = MemoryUsage::GpuOnly;
49+
bool preferredFlags = false; // 推奨フラグを優先するか
50+
std::string debugName;
51+
};
52+
53+
// イメージ作成情報
54+
struct ImageCreateInfo {
55+
vk::ImageType imageType = vk::ImageType::e2D;
56+
vk::Format format;
57+
vk::Extent3D extent;
58+
uint32_t mipLevels = 1;
59+
uint32_t arrayLayers = 1;
60+
vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1;
61+
vk::ImageTiling tiling = vk::ImageTiling::eOptimal;
62+
vk::ImageUsageFlags usage;
63+
vk::ImageLayout initialLayout = vk::ImageLayout::eUndefined;
64+
MemoryUsage memoryUsage = MemoryUsage::GpuOnly;
65+
std::string debugName;
66+
};
67+
68+
/**
69+
* VMA (Vulkan Memory Allocator) を使用したメモリ管理クラス
70+
*
71+
* このクラスは以下の問題を解決します:
72+
* 1. 個別VkDeviceMemory割り当てによる制限到達
73+
* 2. メモリフラグメンテーション
74+
* 3. メモリ使用量の最適化
75+
* 4. 自動的なメモリタイプ選択
76+
*/
77+
class MemoryManager {
78+
public:
79+
explicit MemoryManager(const Context* context);
80+
~MemoryManager();
81+
82+
// コピー・ムーブ禁止
83+
MemoryManager(const MemoryManager&) = delete;
84+
MemoryManager& operator=(const MemoryManager&) = delete;
85+
MemoryManager(MemoryManager&&) = delete;
86+
MemoryManager& operator=(MemoryManager&&) = delete;
87+
88+
// バッファー作成・破棄
89+
BufferAllocation createBuffer(const BufferCreateInfo& createInfo);
90+
void destroyBuffer(const BufferAllocation& allocation);
91+
92+
// イメージ作成・破棄
93+
ImageAllocation createImage(const ImageCreateInfo& createInfo);
94+
void destroyImage(const ImageAllocation& allocation);
95+
96+
// メモリマッピング
97+
void* mapMemory(const BufferAllocation& allocation);
98+
void unmapMemory(const BufferAllocation& allocation);
99+
100+
// メモリ統計情報
101+
void getMemoryStatistics(VmaTotalStatistics* stats) const;
102+
void getMemoryBudget(VmaBudget* budget) const;
103+
104+
// デフラグメンテーション
105+
void defragment();
106+
107+
// デバッグ情報
108+
void dumpMemoryToJson(const std::string& filePath) const;
109+
110+
private:
111+
const Context* m_context;
112+
VmaAllocator m_allocator;
113+
114+
// VMA usage フラグ変換
115+
VmaMemoryUsage convertMemoryUsage(MemoryUsage usage) const;
116+
VmaAllocationCreateFlags getMemoryFlags(MemoryUsage usage) const;
117+
118+
// デバッグ名設定
119+
void setDebugName(vk::Buffer buffer, const std::string& name) const;
120+
void setDebugName(vk::Image image, const std::string& name) const;
121+
};
122+
123+
} // namespace rv

include/reactive/pch.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
1818
#include <vulkan/vulkan.hpp>
1919

20+
#define VMA_IMPLEMENTATION
21+
#include <vk_mem_alloc.h>
22+
2023
#include <spdlog/spdlog.h>
2124

2225
#include <GLFW/glfw3.h>

include/reactive/reactive.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include "Compiler/Compiler.hpp"
1111
#include "Graphics/Fence.hpp"
12+
#include "Graphics/MemoryManager.hpp"
1213
#include "Graphics/Shader.hpp"
1314
#include "Scene/AABB.hpp"
1415
#include "Scene/Camera.hpp"

0 commit comments

Comments
 (0)