blob: 661399e634a7f99889b0df47fbe8bf68c3a1335b [file] [log] [blame]
Adam Sawicki51fa9662018-10-03 13:44:29 +02001#include "Common.h"
2#include "SparseBindingTest.h"
3
4#ifdef _WIN32
5
6////////////////////////////////////////////////////////////////////////////////
7// External imports
8
9extern VkDevice g_hDevice;
10extern VmaAllocator g_hAllocator;
11extern uint32_t g_FrameIndex;
12extern bool g_SparseBindingEnabled;
13extern VkQueue g_hSparseBindingQueue;
14extern VkFence g_ImmediateFence;
15
16void SaveAllocatorStatsToFile(const wchar_t* filePath);
17
18////////////////////////////////////////////////////////////////////////////////
19// Class definitions
20
21class BaseImage
22{
23public:
Adam Sawickid062b782018-10-03 15:26:22 +020024 virtual void Init(RandomNumberGenerator& rand) = 0;
Adam Sawicki51fa9662018-10-03 13:44:29 +020025 virtual ~BaseImage();
26
27protected:
28 VkImage m_Image = VK_NULL_HANDLE;
29
30 void FillImageCreateInfo(VkImageCreateInfo& outInfo, RandomNumberGenerator& rand);
31};
32
33class TraditionalImage : public BaseImage
34{
35public:
Adam Sawickid062b782018-10-03 15:26:22 +020036 virtual void Init(RandomNumberGenerator& rand);
Adam Sawicki51fa9662018-10-03 13:44:29 +020037 virtual ~TraditionalImage();
38
39private:
40 VmaAllocation m_Allocation = VK_NULL_HANDLE;
41};
42
43class SparseBindingImage : public BaseImage
44{
45public:
Adam Sawickid062b782018-10-03 15:26:22 +020046 virtual void Init(RandomNumberGenerator& rand);
Adam Sawicki51fa9662018-10-03 13:44:29 +020047 virtual ~SparseBindingImage();
48
49private:
50 std::vector<VmaAllocation> m_Allocations;
51};
52
53////////////////////////////////////////////////////////////////////////////////
54// class BaseImage
55
56BaseImage::~BaseImage()
57{
58 if(m_Image)
59 {
60 vkDestroyImage(g_hDevice, m_Image, nullptr);
61 }
62}
63
64void BaseImage::FillImageCreateInfo(VkImageCreateInfo& outInfo, RandomNumberGenerator& rand)
65{
66 constexpr uint32_t imageSizeMin = 8;
67 constexpr uint32_t imageSizeMax = 2048;
68
69 ZeroMemory(&outInfo, sizeof(outInfo));
70 outInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
71 outInfo.imageType = VK_IMAGE_TYPE_2D;
72 outInfo.extent.width = rand.Generate() % (imageSizeMax - imageSizeMin) + imageSizeMin;
73 outInfo.extent.height = rand.Generate() % (imageSizeMax - imageSizeMin) + imageSizeMin;
74 outInfo.extent.depth = 1;
75 outInfo.mipLevels = 1; // TODO ?
Adam Sawickid062b782018-10-03 15:26:22 +020076 outInfo.arrayLayers = 1;
Adam Sawicki51fa9662018-10-03 13:44:29 +020077 outInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
78 outInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
79 outInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
80 outInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
81 outInfo.samples = VK_SAMPLE_COUNT_1_BIT;
82 outInfo.flags = 0;
83}
84
85////////////////////////////////////////////////////////////////////////////////
86// class TraditionalImage
87
Adam Sawickid062b782018-10-03 15:26:22 +020088void TraditionalImage::Init(RandomNumberGenerator& rand)
Adam Sawicki51fa9662018-10-03 13:44:29 +020089{
90 VkImageCreateInfo imageCreateInfo;
91 FillImageCreateInfo(imageCreateInfo, rand);
92
93 VmaAllocationCreateInfo allocCreateInfo = {};
94 allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
95 // Default BEST_FIT is clearly better.
96 //allocCreateInfo.flags |= VMA_ALLOCATION_CREATE_STRATEGY_WORST_FIT_BIT;
97
Adam Sawickid062b782018-10-03 15:26:22 +020098 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageCreateInfo, &allocCreateInfo,
99 &m_Image, &m_Allocation, nullptr) );
Adam Sawicki51fa9662018-10-03 13:44:29 +0200100}
101
102TraditionalImage::~TraditionalImage()
103{
104 if(m_Allocation)
105 {
106 vmaFreeMemory(g_hAllocator, m_Allocation);
107 }
108}
109
110////////////////////////////////////////////////////////////////////////////////
111// class SparseBindingImage
112
Adam Sawickid062b782018-10-03 15:26:22 +0200113void SparseBindingImage::Init(RandomNumberGenerator& rand)
Adam Sawicki51fa9662018-10-03 13:44:29 +0200114{
115 assert(g_SparseBindingEnabled && g_hSparseBindingQueue);
116
117 // Create image.
118 VkImageCreateInfo imageCreateInfo;
119 FillImageCreateInfo(imageCreateInfo, rand);
120 imageCreateInfo.flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT;
Adam Sawickid062b782018-10-03 15:26:22 +0200121 ERR_GUARD_VULKAN( vkCreateImage(g_hDevice, &imageCreateInfo, nullptr, &m_Image) );
Adam Sawicki51fa9662018-10-03 13:44:29 +0200122
123 // Get memory requirements.
124 VkMemoryRequirements imageMemReq;
125 vkGetImageMemoryRequirements(g_hDevice, m_Image, &imageMemReq);
126
127 // This is just to silence validation layer warning.
128 // But it doesn't help. Looks like a bug in Vulkan validation layers.
129 uint32_t sparseMemReqCount = 0;
130 vkGetImageSparseMemoryRequirements(g_hDevice, m_Image, &sparseMemReqCount, nullptr);
Adam Sawickia7d77692018-10-03 16:15:27 +0200131 TEST(sparseMemReqCount <= 8);
Adam Sawicki51fa9662018-10-03 13:44:29 +0200132 VkSparseImageMemoryRequirements sparseMemReq[8];
133 vkGetImageSparseMemoryRequirements(g_hDevice, m_Image, &sparseMemReqCount, sparseMemReq);
134
135 // According to Vulkan specification, for sparse resources memReq.alignment is also page size.
136 const VkDeviceSize pageSize = imageMemReq.alignment;
137 const uint32_t pageCount = (uint32_t)ceil_div<VkDeviceSize>(imageMemReq.size, pageSize);
138
139 VmaAllocationCreateInfo allocCreateInfo = {};
140 allocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
141
142 VkMemoryRequirements pageMemReq = imageMemReq;
143 pageMemReq.size = pageSize;
144
145 // Allocate and bind memory pages.
146 m_Allocations.resize(pageCount);
147 std::fill(m_Allocations.begin(), m_Allocations.end(), nullptr);
148 std::vector<VkSparseMemoryBind> binds{pageCount};
Adam Sawickid062b782018-10-03 15:26:22 +0200149 std::vector<VmaAllocationInfo> allocInfo{pageCount};
150 ERR_GUARD_VULKAN( vmaAllocateMemoryPages(g_hAllocator, &pageMemReq, &allocCreateInfo, pageCount, m_Allocations.data(), allocInfo.data()) );
151
Adam Sawicki51fa9662018-10-03 13:44:29 +0200152 for(uint32_t i = 0; i < pageCount; ++i)
153 {
Adam Sawicki51fa9662018-10-03 13:44:29 +0200154 binds[i] = {};
155 binds[i].resourceOffset = pageSize * i;
156 binds[i].size = pageSize;
Adam Sawickid062b782018-10-03 15:26:22 +0200157 binds[i].memory = allocInfo[i].deviceMemory;
158 binds[i].memoryOffset = allocInfo[i].offset;
Adam Sawicki51fa9662018-10-03 13:44:29 +0200159 }
160
161 VkSparseImageOpaqueMemoryBindInfo imageBindInfo;
162 imageBindInfo.image = m_Image;
163 imageBindInfo.bindCount = pageCount;
164 imageBindInfo.pBinds = binds.data();
165
166 VkBindSparseInfo bindSparseInfo = { VK_STRUCTURE_TYPE_BIND_SPARSE_INFO };
167 bindSparseInfo.pImageOpaqueBinds = &imageBindInfo;
168 bindSparseInfo.imageOpaqueBindCount = 1;
169
170 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &g_ImmediateFence) );
171 ERR_GUARD_VULKAN( vkQueueBindSparse(g_hSparseBindingQueue, 1, &bindSparseInfo, g_ImmediateFence) );
172 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &g_ImmediateFence, VK_TRUE, UINT64_MAX) );
Adam Sawicki51fa9662018-10-03 13:44:29 +0200173}
174
175SparseBindingImage::~SparseBindingImage()
176{
Adam Sawickid062b782018-10-03 15:26:22 +0200177 vmaFreeMemoryPages(g_hAllocator, m_Allocations.size(), m_Allocations.data());
Adam Sawicki51fa9662018-10-03 13:44:29 +0200178}
179
180////////////////////////////////////////////////////////////////////////////////
181// Private functions
182
183////////////////////////////////////////////////////////////////////////////////
184// Public functions
185
186void TestSparseBinding()
187{
188 struct ImageInfo
189 {
190 std::unique_ptr<BaseImage> image;
191 uint32_t endFrame;
192 };
193 std::vector<ImageInfo> images;
194
195 constexpr uint32_t frameCount = 2000;
196 constexpr uint32_t imageLifeFramesMin = 1;
197 constexpr uint32_t imageLifeFramesMax = 400;
198
199 RandomNumberGenerator rand(4652467);
200
201 for(uint32_t i = 0; i < frameCount; ++i)
202 {
203 // Bump frame index.
204 ++g_FrameIndex;
205 vmaSetCurrentFrameIndex(g_hAllocator, g_FrameIndex);
206
207 // Create one new, random image.
208 ImageInfo imageInfo;
209 //imageInfo.image = std::make_unique<TraditionalImage>();
210 imageInfo.image = std::make_unique<SparseBindingImage>();
Adam Sawickid062b782018-10-03 15:26:22 +0200211 imageInfo.image->Init(rand);
212 imageInfo.endFrame = g_FrameIndex + rand.Generate() % (imageLifeFramesMax - imageLifeFramesMin) + imageLifeFramesMin;
213 images.push_back(std::move(imageInfo));
Adam Sawicki51fa9662018-10-03 13:44:29 +0200214
215 // Delete all images that expired.
216 for(size_t i = images.size(); i--; )
217 {
218 if(g_FrameIndex >= images[i].endFrame)
219 {
220 images.erase(images.begin() + i);
221 }
222 }
223 }
224
225 SaveAllocatorStatsToFile(L"SparseBindingTest.json");
226
227 // Free remaining images.
228 images.clear();
229}
230
231#endif // #ifdef _WIN32