blob: 819bd12124c6ea98ac3e37f87fc410f222b44b91 [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawicki50882502020-02-07 16:51:31 +01002// Copyright (c) 2017-2020 Advanced Micro Devices, Inc. All rights reserved.
Adam Sawickie6e498f2017-06-16 17:21:31 +02003//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21//
22
Adam Sawickif1a793c2018-03-13 15:42:22 +010023#ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +020024
Adam Sawicki51fa9662018-10-03 13:44:29 +020025#include "SparseBindingTest.h"
Adam Sawickif1a793c2018-03-13 15:42:22 +010026#include "Tests.h"
27#include "VmaUsage.h"
28#include "Common.h"
Adam Sawicki8317ba92019-11-18 13:14:11 +010029#include <atomic>
Adam Sawickie6e498f2017-06-16 17:21:31 +020030
31static const char* const SHADER_PATH1 = "./";
32static const char* const SHADER_PATH2 = "../bin/";
33static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
34static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_LUNARG_standard_validation";
Adam Sawicki8ef0d202020-03-02 15:43:47 +010035static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.4.0";
36static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.4.0";
Adam Sawickie6e498f2017-06-16 17:21:31 +020037
38static const bool VSYNC = true;
39static const uint32_t COMMAND_BUFFER_COUNT = 2;
Adam Sawickia68c01c2018-03-13 16:40:45 +010040static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
Adam Sawicki8317ba92019-11-18 13:14:11 +010041static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = true;
Adam Sawickie6e498f2017-06-16 17:21:31 +020042
Adam Sawickib8333fb2018-03-13 16:15:53 +010043VkPhysicalDevice g_hPhysicalDevice;
44VkDevice g_hDevice;
45VmaAllocator g_hAllocator;
Adam Sawicki4ac8ff82019-11-18 14:47:33 +010046VkInstance g_hVulkanInstance;
Adam Sawickib8333fb2018-03-13 16:15:53 +010047bool g_MemoryAliasingWarningEnabled = true;
48
Adam Sawicki50882502020-02-07 16:51:31 +010049bool g_EnableValidationLayer = true;
50bool VK_KHR_get_memory_requirements2_enabled = false;
51bool VK_KHR_get_physical_device_properties2_enabled = false;
52bool VK_KHR_dedicated_allocation_enabled = false;
53bool VK_KHR_bind_memory2_enabled = false;
54bool VK_EXT_memory_budget_enabled = false;
55bool VK_AMD_device_coherent_memory_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020056bool g_SparseBindingEnabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010057
Adam Sawickie6e498f2017-06-16 17:21:31 +020058static HINSTANCE g_hAppInstance;
59static HWND g_hWnd;
60static LONG g_SizeX = 1280, g_SizeY = 720;
Adam Sawickie6e498f2017-06-16 17:21:31 +020061static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020062static VkQueue g_hPresentQueue;
63static VkSurfaceFormatKHR g_SurfaceFormat;
64static VkExtent2D g_Extent;
65static VkSwapchainKHR g_hSwapchain;
66static std::vector<VkImage> g_SwapchainImages;
67static std::vector<VkImageView> g_SwapchainImageViews;
68static std::vector<VkFramebuffer> g_Framebuffers;
69static VkCommandPool g_hCommandPool;
70static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
71static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020072VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020073static uint32_t g_NextCommandBufferIndex;
74static VkSemaphore g_hImageAvailableSemaphore;
75static VkSemaphore g_hRenderFinishedSemaphore;
76static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
77static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020078static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020079static VkDescriptorSetLayout g_hDescriptorSetLayout;
80static VkDescriptorPool g_hDescriptorPool;
81static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
82static VkSampler g_hSampler;
83static VkFormat g_DepthFormat;
84static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +020085static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +020086static VkImageView g_hDepthImageView;
87
88static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
89static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
90static std::vector<VkPresentModeKHR> g_PresentModes;
91
92static PFN_vkCreateDebugReportCallbackEXT g_pvkCreateDebugReportCallbackEXT;
93static PFN_vkDebugReportMessageEXT g_pvkDebugReportMessageEXT;
94static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
95static VkDebugReportCallbackEXT g_hCallback;
96
Adam Sawickie6e498f2017-06-16 17:21:31 +020097static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +020098VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +010099VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200100
101static VkPipelineLayout g_hPipelineLayout;
102static VkRenderPass g_hRenderPass;
103static VkPipeline g_hPipeline;
104
105static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200106static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200107static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200108static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200109static uint32_t g_VertexCount;
110static uint32_t g_IndexCount;
111
112static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200113static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200114static VkImageView g_hTextureImageView;
115
Adam Sawicki8317ba92019-11-18 13:14:11 +0100116static std::atomic_uint32_t g_CpuAllocCount;
117
Adam Sawickia68c01c2018-03-13 16:40:45 +0100118static void* CustomCpuAllocation(
119 void* pUserData, size_t size, size_t alignment,
120 VkSystemAllocationScope allocationScope)
121{
122 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100123 void* const result = _aligned_malloc(size, alignment);
124 if(result)
125 {
126 ++g_CpuAllocCount;
127 }
128 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100129}
130
131static void* CustomCpuReallocation(
132 void* pUserData, void* pOriginal, size_t size, size_t alignment,
133 VkSystemAllocationScope allocationScope)
134{
135 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100136 void* const result = _aligned_realloc(pOriginal, size, alignment);
137 if(pOriginal && !result)
138 {
139 --g_CpuAllocCount;
140 }
141 else if(!pOriginal && result)
142 {
143 ++g_CpuAllocCount;
144 }
145 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100146}
147
148static void CustomCpuFree(void* pUserData, void* pMemory)
149{
150 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100151 if(pMemory)
152 {
153 const uint32_t oldAllocCount = g_CpuAllocCount.fetch_sub(1);
154 TEST(oldAllocCount > 0);
155 _aligned_free(pMemory);
156 }
Adam Sawickia68c01c2018-03-13 16:40:45 +0100157}
158
Adam Sawicki1f84f622019-07-02 13:40:01 +0200159static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
160 CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA, // pUserData
161 &CustomCpuAllocation, // pfnAllocation
162 &CustomCpuReallocation, // pfnReallocation
163 &CustomCpuFree // pfnFree
164};
165
166const VkAllocationCallbacks* g_Allocs;
167
Adam Sawicki978fcf52018-12-05 14:38:48 +0100168void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200169{
170 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
171 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
172 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
173}
174
Adam Sawicki978fcf52018-12-05 14:38:48 +0100175void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200176{
177 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
178
179 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
180 submitInfo.commandBufferCount = 1;
181 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
182
183 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
184 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
185}
186
Adam Sawickida6c1942018-12-05 17:34:34 +0100187void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200188{
189 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
190 if(file.is_open() == false)
191 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
192 assert(file.is_open());
193 size_t fileSize = (size_t)file.tellg();
194 if(fileSize > 0)
195 {
196 out.resize(fileSize);
197 file.seekg(0);
198 file.read(out.data(), fileSize);
199 file.close();
200 }
201 else
202 out.clear();
203}
204
205VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback(
206 VkDebugReportFlagsEXT flags,
207 VkDebugReportObjectTypeEXT objectType,
208 uint64_t object,
209 size_t location,
210 int32_t messageCode,
211 const char* pLayerPrefix,
212 const char* pMessage,
213 void* pUserData)
214{
Adam Sawickib8333fb2018-03-13 16:15:53 +0100215 // "Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug."
216 if(!g_MemoryAliasingWarningEnabled && flags == VK_DEBUG_REPORT_WARNING_BIT_EXT &&
217 (strstr(pMessage, " is aliased with non-linear ") || strstr(pMessage, " is aliased with linear ")))
218 {
219 return VK_FALSE;
220 }
221
222 // Ignoring because when VK_KHR_dedicated_allocation extension is enabled,
223 // vkGetBufferMemoryRequirements2KHR function is used instead, while Validation
224 // Layer seems to be unaware of it.
225 if (strstr(pMessage, "but vkGetBufferMemoryRequirements() has not been called on that buffer") != nullptr)
226 {
227 return VK_FALSE;
228 }
229 if (strstr(pMessage, "but vkGetImageMemoryRequirements() has not been called on that image") != nullptr)
230 {
231 return VK_FALSE;
232 }
Adam Sawicki94e82062018-08-20 11:12:51 +0200233
234 /*
235 "Mapping an image with layout VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL can result in undefined behavior if this memory is used by the device. Only GENERAL or PREINITIALIZED should be used."
236 Ignoring because we map entire VkDeviceMemory blocks, where different types of
237 images and buffers may end up together, especially on GPUs with unified memory
238 like Intel.
239 */
240 if(strstr(pMessage, "Mapping an image with layout") != nullptr &&
241 strstr(pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr)
242 {
243 return VK_FALSE;
244 }
Adam Sawickib8333fb2018-03-13 16:15:53 +0100245
246 switch(flags)
247 {
248 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
249 SetConsoleColor(CONSOLE_COLOR::WARNING);
250 break;
251 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
252 SetConsoleColor(CONSOLE_COLOR::ERROR_);
253 break;
254 default:
255 SetConsoleColor(CONSOLE_COLOR::INFO);
256 }
257
Adam Sawickie6e498f2017-06-16 17:21:31 +0200258 printf("%s \xBA %s\n", pLayerPrefix, pMessage);
259
Adam Sawickib8333fb2018-03-13 16:15:53 +0100260 SetConsoleColor(CONSOLE_COLOR::NORMAL);
261
262 if(flags == VK_DEBUG_REPORT_WARNING_BIT_EXT ||
263 flags == VK_DEBUG_REPORT_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200264 {
265 OutputDebugStringA(pMessage);
266 OutputDebugStringA("\n");
267 }
268
269 return VK_FALSE;
270}
271
272static VkSurfaceFormatKHR ChooseSurfaceFormat()
273{
274 assert(!g_SurfaceFormats.empty());
275
276 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
277 {
278 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
279 return result;
280 }
281
282 for(const auto& format : g_SurfaceFormats)
283 {
284 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
285 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
286 {
287 return format;
288 }
289 }
290
291 return g_SurfaceFormats[0];
292}
293
294VkPresentModeKHR ChooseSwapPresentMode()
295{
296 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
297
298 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
299 g_PresentModes.end())
300 {
301 return preferredMode;
302 }
303
304 return VK_PRESENT_MODE_FIFO_KHR;
305}
306
307static VkExtent2D ChooseSwapExtent()
308{
309 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
310 return g_SurfaceCapabilities.currentExtent;
311
312 VkExtent2D result = {
313 std::max(g_SurfaceCapabilities.minImageExtent.width,
314 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
315 std::max(g_SurfaceCapabilities.minImageExtent.height,
316 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
317 return result;
318}
319
320struct Vertex
321{
322 float pos[3];
323 float color[3];
324 float texCoord[2];
325};
326
327static void CreateMesh()
328{
329 assert(g_hAllocator);
330
331 static Vertex vertices[] = {
332 // -X
333 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
334 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
335 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
336 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
337 // +X
338 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
339 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
340 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
341 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
342 // -Z
343 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
344 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
345 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
346 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
347 // +Z
348 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
349 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
350 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
351 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
352 // -Y
353 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
354 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
355 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
356 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
357 // +Y
358 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
359 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
360 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
361 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
362 };
363 static uint16_t indices[] = {
364 0, 1, 2, 3, USHRT_MAX,
365 4, 5, 6, 7, USHRT_MAX,
366 8, 9, 10, 11, USHRT_MAX,
367 12, 13, 14, 15, USHRT_MAX,
368 16, 17, 18, 19, USHRT_MAX,
369 20, 21, 22, 23, USHRT_MAX,
370 };
371
372 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
373 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
374 g_IndexCount = (uint32_t)_countof(indices);
375
376 // Create vertex buffer
377
378 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
379 vbInfo.size = vertexBufferSize;
380 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
381 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200382
Adam Sawicki976f9202017-09-12 20:45:14 +0200383 VmaAllocationCreateInfo vbAllocCreateInfo = {};
384 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100385 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200386
Adam Sawicki819860e2017-07-04 14:30:38 +0200387 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
388 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
389 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200390 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200391
392 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200393
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200394 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
395
Adam Sawickie6e498f2017-06-16 17:21:31 +0200396 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200397 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
398 vbAllocCreateInfo.flags = 0;
399 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200400
401 // Create index buffer
402
403 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
404 ibInfo.size = indexBufferSize;
405 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
406 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200407
Adam Sawicki976f9202017-09-12 20:45:14 +0200408 VmaAllocationCreateInfo ibAllocCreateInfo = {};
409 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100410 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200411
Adam Sawickie6e498f2017-06-16 17:21:31 +0200412 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200413 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
414 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200415 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200416
Adam Sawicki819860e2017-07-04 14:30:38 +0200417 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200418
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200419 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
420
Adam Sawickie6e498f2017-06-16 17:21:31 +0200421 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200422 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
423 ibAllocCreateInfo.flags = 0;
424 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200425
426 // Copy buffers
427
428 BeginSingleTimeCommands();
429
430 VkBufferCopy vbCopyRegion = {};
431 vbCopyRegion.srcOffset = 0;
432 vbCopyRegion.dstOffset = 0;
433 vbCopyRegion.size = vbInfo.size;
434 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
435
436 VkBufferCopy ibCopyRegion = {};
437 ibCopyRegion.srcOffset = 0;
438 ibCopyRegion.dstOffset = 0;
439 ibCopyRegion.size = ibInfo.size;
440 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
441
442 EndSingleTimeCommands();
443
Adam Sawicki819860e2017-07-04 14:30:38 +0200444 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
445 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200446}
447
Adam Sawickie6e498f2017-06-16 17:21:31 +0200448static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
449{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100450 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200451
452 const VkDeviceSize imageSize = sizeX * sizeY * 4;
453
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100454 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
455 stagingBufInfo.size = imageSize;
456 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
457
458 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
459 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
460 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200461
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100462 VkBuffer stagingBuf = VK_NULL_HANDLE;
463 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
464 VmaAllocationInfo stagingBufAllocInfo = {};
465 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200466
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100467 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
468 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200469 for(uint32_t y = 0; y < sizeY; ++y)
470 {
471 uint32_t* pPixelData = (uint32_t*)pRowData;
472 for(uint32_t x = 0; x < sizeY; ++x)
473 {
474 *pPixelData =
475 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
476 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
477 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
478 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
479 ++pPixelData;
480 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100481 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200482 }
483
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200484 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
485
Adam Sawicki10844a82017-08-16 17:32:09 +0200486 // Create g_hTextureImage in GPU memory.
487
Adam Sawickie6e498f2017-06-16 17:21:31 +0200488 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
489 imageInfo.imageType = VK_IMAGE_TYPE_2D;
490 imageInfo.extent.width = sizeX;
491 imageInfo.extent.height = sizeY;
492 imageInfo.extent.depth = 1;
493 imageInfo.mipLevels = 1;
494 imageInfo.arrayLayers = 1;
495 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
496 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
497 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
498 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
499 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
500 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
501 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200502
Adam Sawicki976f9202017-09-12 20:45:14 +0200503 VmaAllocationCreateInfo imageAllocCreateInfo = {};
504 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200505
Adam Sawicki976f9202017-09-12 20:45:14 +0200506 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200507
Adam Sawicki10844a82017-08-16 17:32:09 +0200508 // Transition image layouts, copy image.
509
510 BeginSingleTimeCommands();
511
512 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200513 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
514 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200515 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
516 imgMemBarrier.subresourceRange.baseMipLevel = 0;
517 imgMemBarrier.subresourceRange.levelCount = 1;
518 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
519 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200520 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
521 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
522 imgMemBarrier.image = g_hTextureImage;
523 imgMemBarrier.srcAccessMask = 0;
524 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
525
526 vkCmdPipelineBarrier(
527 g_hTemporaryCommandBuffer,
528 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
529 VK_PIPELINE_STAGE_TRANSFER_BIT,
530 0,
531 0, nullptr,
532 0, nullptr,
533 1, &imgMemBarrier);
534
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100535 VkBufferImageCopy region = {};
536 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
537 region.imageSubresource.layerCount = 1;
538 region.imageExtent.width = sizeX;
539 region.imageExtent.height = sizeY;
540 region.imageExtent.depth = 1;
541
542 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200543
544 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
545 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
546 imgMemBarrier.image = g_hTextureImage;
547 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
548 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
549
550 vkCmdPipelineBarrier(
551 g_hTemporaryCommandBuffer,
552 VK_PIPELINE_STAGE_TRANSFER_BIT,
553 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
554 0,
555 0, nullptr,
556 0, nullptr,
557 1, &imgMemBarrier);
558
559 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200560
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100561 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200562
563 // Create ImageView
564
565 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
566 textureImageViewInfo.image = g_hTextureImage;
567 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
568 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
569 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
570 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
571 textureImageViewInfo.subresourceRange.levelCount = 1;
572 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
573 textureImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200574 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200575}
576
577struct UniformBufferObject
578{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200579 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200580};
581
582static void RegisterDebugCallbacks()
583{
584 g_pvkCreateDebugReportCallbackEXT =
585 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
586 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
587 g_pvkDebugReportMessageEXT =
588 reinterpret_cast<PFN_vkDebugReportMessageEXT>
589 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
590 g_pvkDestroyDebugReportCallbackEXT =
591 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
592 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
593 assert(g_pvkCreateDebugReportCallbackEXT);
594 assert(g_pvkDebugReportMessageEXT);
595 assert(g_pvkDestroyDebugReportCallbackEXT);
596
597 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
598 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
599 callbackCreateInfo.pNext = nullptr;
600 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
601 VK_DEBUG_REPORT_ERROR_BIT_EXT |
602 VK_DEBUG_REPORT_WARNING_BIT_EXT |
603 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
604 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
605 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
606 callbackCreateInfo.pUserData = nullptr;
607
Adam Sawicki1f84f622019-07-02 13:40:01 +0200608 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, g_Allocs, &g_hCallback) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200609}
610
611static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
612{
613 const VkLayerProperties* propsEnd = pProps + propCount;
614 return std::find_if(
615 pProps,
616 propsEnd,
617 [pLayerName](const VkLayerProperties& prop) -> bool {
618 return strcmp(pLayerName, prop.layerName) == 0;
619 }) != propsEnd;
620}
621
622static VkFormat FindSupportedFormat(
623 const std::vector<VkFormat>& candidates,
624 VkImageTiling tiling,
625 VkFormatFeatureFlags features)
626{
627 for (VkFormat format : candidates)
628 {
629 VkFormatProperties props;
630 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
631
632 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
633 ((props.linearTilingFeatures & features) == features))
634 {
635 return format;
636 }
637 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
638 ((props.optimalTilingFeatures & features) == features))
639 {
640 return format;
641 }
642 }
643 return VK_FORMAT_UNDEFINED;
644}
645
646static VkFormat FindDepthFormat()
647{
648 std::vector<VkFormat> formats;
649 formats.push_back(VK_FORMAT_D32_SFLOAT);
650 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
651 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
652
653 return FindSupportedFormat(
654 formats,
655 VK_IMAGE_TILING_OPTIMAL,
656 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
657}
658
659static void CreateSwapchain()
660{
661 // Query surface formats.
662
663 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
664
665 uint32_t formatCount = 0;
666 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
667 g_SurfaceFormats.resize(formatCount);
668 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
669
670 uint32_t presentModeCount = 0;
671 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
672 g_PresentModes.resize(presentModeCount);
673 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
674
675 // Create swap chain
676
677 g_SurfaceFormat = ChooseSurfaceFormat();
678 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
679 g_Extent = ChooseSwapExtent();
680
681 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
682 if((g_SurfaceCapabilities.maxImageCount > 0) &&
683 (imageCount > g_SurfaceCapabilities.maxImageCount))
684 {
685 imageCount = g_SurfaceCapabilities.maxImageCount;
686 }
687
688 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
689 swapChainInfo.surface = g_hSurface;
690 swapChainInfo.minImageCount = imageCount;
691 swapChainInfo.imageFormat = g_SurfaceFormat.format;
692 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
693 swapChainInfo.imageExtent = g_Extent;
694 swapChainInfo.imageArrayLayers = 1;
695 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
696 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
697 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
698 swapChainInfo.presentMode = presentMode;
699 swapChainInfo.clipped = VK_TRUE;
700 swapChainInfo.oldSwapchain = g_hSwapchain;
701
702 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
703 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
704 {
705 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
706 swapChainInfo.queueFamilyIndexCount = 2;
707 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
708 }
709 else
710 {
711 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
712 }
713
714 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200715 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, g_Allocs, &hNewSwapchain) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200716 if(g_hSwapchain != VK_NULL_HANDLE)
Adam Sawicki1f84f622019-07-02 13:40:01 +0200717 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200718 g_hSwapchain = hNewSwapchain;
719
720 // Retrieve swapchain images.
721
722 uint32_t swapchainImageCount = 0;
723 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
724 g_SwapchainImages.resize(swapchainImageCount);
725 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
726
727 // Create swapchain image views.
728
729 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +0200730 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200731 g_SwapchainImageViews.clear();
732
733 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
734 g_SwapchainImageViews.resize(swapchainImageCount);
735 for(uint32_t i = 0; i < swapchainImageCount; ++i)
736 {
737 swapchainImageViewInfo.image = g_SwapchainImages[i];
738 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
739 swapchainImageViewInfo.format = g_SurfaceFormat.format;
740 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
741 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
742 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
743 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
744 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
745 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
746 swapchainImageViewInfo.subresourceRange.levelCount = 1;
747 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
748 swapchainImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200749 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200750 }
751
752 // Create depth buffer
753
754 g_DepthFormat = FindDepthFormat();
755 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
756
757 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
758 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
759 depthImageInfo.extent.width = g_Extent.width;
760 depthImageInfo.extent.height = g_Extent.height;
761 depthImageInfo.extent.depth = 1;
762 depthImageInfo.mipLevels = 1;
763 depthImageInfo.arrayLayers = 1;
764 depthImageInfo.format = g_DepthFormat;
765 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
766 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
767 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
768 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
769 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
770 depthImageInfo.flags = 0;
771
Adam Sawicki976f9202017-09-12 20:45:14 +0200772 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
773 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200774
Adam Sawicki976f9202017-09-12 20:45:14 +0200775 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200776
777 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
778 depthImageViewInfo.image = g_hDepthImage;
779 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
780 depthImageViewInfo.format = g_DepthFormat;
781 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
782 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
783 depthImageViewInfo.subresourceRange.levelCount = 1;
784 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
785 depthImageViewInfo.subresourceRange.layerCount = 1;
786
Adam Sawicki1f84f622019-07-02 13:40:01 +0200787 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200788
Adam Sawickie6e498f2017-06-16 17:21:31 +0200789 // Create pipeline layout
790 {
791 if(g_hPipelineLayout != VK_NULL_HANDLE)
792 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200793 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200794 g_hPipelineLayout = VK_NULL_HANDLE;
795 }
796
797 VkPushConstantRange pushConstantRanges[1];
798 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
799 pushConstantRanges[0].offset = 0;
800 pushConstantRanges[0].size = sizeof(UniformBufferObject);
801 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
802
803 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
804 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
805 pipelineLayoutInfo.setLayoutCount = 1;
806 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
807 pipelineLayoutInfo.pushConstantRangeCount = 1;
808 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200809 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200810 }
811
812 // Create render pass
813 {
814 if(g_hRenderPass != VK_NULL_HANDLE)
815 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200816 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200817 g_hRenderPass = VK_NULL_HANDLE;
818 }
819
820 VkAttachmentDescription attachments[2];
821 ZeroMemory(attachments, sizeof(attachments));
822
823 attachments[0].format = g_SurfaceFormat.format;
824 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
825 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
826 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
827 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
828 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100829 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200830 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
831
832 attachments[1].format = g_DepthFormat;
833 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
834 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
835 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
836 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
837 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100838 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200839 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
840
841 VkAttachmentReference colorAttachmentRef = {};
842 colorAttachmentRef.attachment = 0;
843 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
844
845 VkAttachmentReference depthStencilAttachmentRef = {};
846 depthStencilAttachmentRef.attachment = 1;
847 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
848
849 VkSubpassDescription subpassDesc = {};
850 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
851 subpassDesc.colorAttachmentCount = 1;
852 subpassDesc.pColorAttachments = &colorAttachmentRef;
853 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
854
Adam Sawickie6e498f2017-06-16 17:21:31 +0200855 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
856 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
857 renderPassInfo.pAttachments = attachments;
858 renderPassInfo.subpassCount = 1;
859 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200860 renderPassInfo.dependencyCount = 0;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200861 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200862 }
863
864 // Create pipeline
865 {
866 std::vector<char> vertShaderCode;
867 LoadShader(vertShaderCode, "Shader.vert.spv");
868 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
869 shaderModuleInfo.codeSize = vertShaderCode.size();
870 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
871 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200872 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200873
874 std::vector<char> hFragShaderCode;
875 LoadShader(hFragShaderCode, "Shader.frag.spv");
876 shaderModuleInfo.codeSize = hFragShaderCode.size();
877 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
878 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200879 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200880
881 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
882 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
883 vertPipelineShaderStageInfo.module = hVertShaderModule;
884 vertPipelineShaderStageInfo.pName = "main";
885
886 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
887 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
888 fragPipelineShaderStageInfo.module = fragShaderModule;
889 fragPipelineShaderStageInfo.pName = "main";
890
891 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
892 vertPipelineShaderStageInfo,
893 fragPipelineShaderStageInfo
894 };
895
896 VkVertexInputBindingDescription bindingDescription = {};
897 bindingDescription.binding = 0;
898 bindingDescription.stride = sizeof(Vertex);
899 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
900
901 VkVertexInputAttributeDescription attributeDescriptions[3];
902 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
903
904 attributeDescriptions[0].binding = 0;
905 attributeDescriptions[0].location = 0;
906 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
907 attributeDescriptions[0].offset = offsetof(Vertex, pos);
908
909 attributeDescriptions[1].binding = 0;
910 attributeDescriptions[1].location = 1;
911 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
912 attributeDescriptions[1].offset = offsetof(Vertex, color);
913
914 attributeDescriptions[2].binding = 0;
915 attributeDescriptions[2].location = 2;
916 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
917 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
918
919 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
920 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
921 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
922 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
923 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
924
925 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
926 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
927 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
928
929 VkViewport viewport = {};
930 viewport.x = 0.f;
931 viewport.y = 0.f;
932 viewport.width = (float)g_Extent.width;
933 viewport.height = (float)g_Extent.height;
934 viewport.minDepth = 0.f;
935 viewport.maxDepth = 1.f;
936
937 VkRect2D scissor = {};
938 scissor.offset.x = 0;
939 scissor.offset.y = 0;
940 scissor.extent = g_Extent;
941
942 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
943 pipelineViewportStateInfo.viewportCount = 1;
944 pipelineViewportStateInfo.pViewports = &viewport;
945 pipelineViewportStateInfo.scissorCount = 1;
946 pipelineViewportStateInfo.pScissors = &scissor;
947
948 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
949 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
950 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
951 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
952 pipelineRasterizationStateInfo.lineWidth = 1.f;
953 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
954 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
955 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
956 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
957 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
958 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
959
960 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
961 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
962 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
963 pipelineMultisampleStateInfo.minSampleShading = 1.f;
964 pipelineMultisampleStateInfo.pSampleMask = nullptr;
965 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
966 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
967
968 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
969 pipelineColorBlendAttachmentState.colorWriteMask =
970 VK_COLOR_COMPONENT_R_BIT |
971 VK_COLOR_COMPONENT_G_BIT |
972 VK_COLOR_COMPONENT_B_BIT |
973 VK_COLOR_COMPONENT_A_BIT;
974 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
975 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
976 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
977 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
978 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
979 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
980 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
981
982 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
983 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
984 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
985 pipelineColorBlendStateInfo.attachmentCount = 1;
986 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
987
988 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
989 depthStencilStateInfo.depthTestEnable = VK_TRUE;
990 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
991 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
992 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
993 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
994
995 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
996 pipelineInfo.stageCount = 2;
997 pipelineInfo.pStages = pipelineShaderStageInfos;
998 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
999 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
1000 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
1001 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
1002 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
1003 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
1004 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
1005 pipelineInfo.pDynamicState = nullptr;
1006 pipelineInfo.layout = g_hPipelineLayout;
1007 pipelineInfo.renderPass = g_hRenderPass;
1008 pipelineInfo.subpass = 0;
1009 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
1010 pipelineInfo.basePipelineIndex = -1;
1011 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
1012 g_hDevice,
1013 VK_NULL_HANDLE,
1014 1,
Adam Sawicki1f84f622019-07-02 13:40:01 +02001015 &pipelineInfo,
1016 g_Allocs,
Adam Sawickie6e498f2017-06-16 17:21:31 +02001017 &g_hPipeline) );
1018
Adam Sawicki1f84f622019-07-02 13:40:01 +02001019 vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
1020 vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001021 }
1022
1023 // Create frambuffers
1024
1025 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001026 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001027 g_Framebuffers.clear();
1028
1029 g_Framebuffers.resize(g_SwapchainImageViews.size());
1030 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1031 {
1032 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1033
1034 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1035 framebufferInfo.renderPass = g_hRenderPass;
1036 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1037 framebufferInfo.pAttachments = attachments;
1038 framebufferInfo.width = g_Extent.width;
1039 framebufferInfo.height = g_Extent.height;
1040 framebufferInfo.layers = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001041 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001042 }
1043
1044 // Create semaphores
1045
1046 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1047 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001048 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001049 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1050 }
1051 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1052 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001053 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001054 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1055 }
1056
1057 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
Adam Sawicki1f84f622019-07-02 13:40:01 +02001058 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
1059 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001060}
1061
1062static void DestroySwapchain(bool destroyActualSwapchain)
1063{
1064 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1065 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001066 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001067 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1068 }
1069 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1070 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001071 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001072 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1073 }
1074
1075 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001076 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001077 g_Framebuffers.clear();
1078
1079 if(g_hDepthImageView != VK_NULL_HANDLE)
1080 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001081 vkDestroyImageView(g_hDevice, g_hDepthImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001082 g_hDepthImageView = VK_NULL_HANDLE;
1083 }
1084 if(g_hDepthImage != VK_NULL_HANDLE)
1085 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001086 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001087 g_hDepthImage = VK_NULL_HANDLE;
1088 }
1089
1090 if(g_hPipeline != VK_NULL_HANDLE)
1091 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001092 vkDestroyPipeline(g_hDevice, g_hPipeline, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001093 g_hPipeline = VK_NULL_HANDLE;
1094 }
1095
1096 if(g_hRenderPass != VK_NULL_HANDLE)
1097 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001098 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001099 g_hRenderPass = VK_NULL_HANDLE;
1100 }
1101
1102 if(g_hPipelineLayout != VK_NULL_HANDLE)
1103 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001104 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001105 g_hPipelineLayout = VK_NULL_HANDLE;
1106 }
1107
1108 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001109 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001110 g_SwapchainImageViews.clear();
1111
1112 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1113 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001114 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001115 g_hSwapchain = VK_NULL_HANDLE;
1116 }
1117}
1118
Adam Sawicki50882502020-02-07 16:51:31 +01001119static constexpr uint32_t GetVulkanApiVersion()
1120{
Adam Sawicki8ef0d202020-03-02 15:43:47 +01001121#if VMA_VULKAN_VERSION == 1002000
1122 return VK_API_VERSION_1_2;
1123#elif VMA_VULKAN_VERSION == 1001000
1124 return VK_API_VERSION_1_1;
1125#elif VMA_VULKAN_VERSION == 1000000
1126 return VK_API_VERSION_1_0;
1127#else
1128 #error Invalid VMA_VULKAN_VERSION.
1129 return UINT32_MAX;
1130#endif
Adam Sawicki50882502020-02-07 16:51:31 +01001131}
1132
1133void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
1134{
1135 outInfo = {};
1136
1137 outInfo.physicalDevice = g_hPhysicalDevice;
1138 outInfo.device = g_hDevice;
1139 outInfo.instance = g_hVulkanInstance;
1140 outInfo.vulkanApiVersion = GetVulkanApiVersion();
1141
1142 if(VK_KHR_dedicated_allocation_enabled)
1143 {
1144 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1145 }
1146 if(VK_KHR_bind_memory2_enabled)
1147 {
1148 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
1149 }
1150#if !defined(VMA_MEMORY_BUDGET) || VMA_MEMORY_BUDGET == 1
1151 if(VK_EXT_memory_budget_enabled && VK_KHR_get_physical_device_properties2_enabled)
1152 {
1153 outInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
1154 }
1155#endif
1156 if(VK_AMD_device_coherent_memory_enabled)
1157 {
1158 outInfo.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT;
1159 }
1160
1161 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1162 {
1163 outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
1164 }
1165
1166 // Uncomment to enable recording to CSV file.
1167 /*
1168 static VmaRecordSettings recordSettings = {};
1169 recordSettings.pFilePath = "VulkanSample.csv";
1170 outInfo.pRecordSettings = &recordSettings;
1171 */
1172
1173 // Uncomment to enable HeapSizeLimit.
1174 /*
1175 static std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapSizeLimit;
1176 std::fill(heapSizeLimit.begin(), heapSizeLimit.end(), VK_WHOLE_SIZE);
1177 heapSizeLimit[0] = 512ull * 1024 * 1024;
1178 outInfo.pHeapSizeLimit = heapSizeLimit.data();
1179 */
1180}
1181
Adam Sawickie6e498f2017-06-16 17:21:31 +02001182static void InitializeApplication()
1183{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001184 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1185 {
1186 g_Allocs = &g_CpuAllocationCallbacks;
1187 }
1188
Adam Sawickie6e498f2017-06-16 17:21:31 +02001189 uint32_t instanceLayerPropCount = 0;
1190 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1191 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1192 if(instanceLayerPropCount > 0)
1193 {
1194 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1195 }
1196
1197 if(g_EnableValidationLayer == true)
1198 {
1199 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1200 {
1201 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1202 g_EnableValidationLayer = false;
1203 }
1204 }
1205
Adam Sawicki353e3672019-11-02 14:12:05 +01001206 uint32_t availableInstanceExtensionCount = 0;
1207 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
1208 std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
1209 if(availableInstanceExtensionCount > 0)
1210 {
1211 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
1212 }
1213
1214 std::vector<const char*> enabledInstanceExtensions;
1215 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1216 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001217
1218 std::vector<const char*> instanceLayers;
1219 if(g_EnableValidationLayer == true)
1220 {
1221 instanceLayers.push_back(VALIDATION_LAYER_NAME);
Adam Sawicki353e3672019-11-02 14:12:05 +01001222 enabledInstanceExtensions.push_back("VK_EXT_debug_report");
1223 }
1224
1225 for(const auto& extensionProperties : availableInstanceExtensions)
1226 {
1227 if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
1228 {
1229 enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1230 VK_KHR_get_physical_device_properties2_enabled = true;
1231 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001232 }
1233
1234 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1235 appInfo.pApplicationName = APP_TITLE_A;
1236 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1237 appInfo.pEngineName = "Adam Sawicki Engine";
1238 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
Adam Sawicki50882502020-02-07 16:51:31 +01001239 appInfo.apiVersion = GetVulkanApiVersion();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001240
1241 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1242 instInfo.pApplicationInfo = &appInfo;
Adam Sawicki353e3672019-11-02 14:12:05 +01001243 instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
1244 instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001245 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1246 instInfo.ppEnabledLayerNames = instanceLayers.data();
1247
Adam Sawicki1f84f622019-07-02 13:40:01 +02001248 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001249
1250 // Create VkSurfaceKHR.
1251 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1252 surfaceInfo.hinstance = g_hAppInstance;
1253 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001254 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001255 assert(result == VK_SUCCESS);
1256
1257 if(g_EnableValidationLayer == true)
1258 RegisterDebugCallbacks();
1259
1260 // Find physical device
1261
1262 uint32_t deviceCount = 0;
1263 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1264 assert(deviceCount > 0);
1265
1266 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1267 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1268
1269 g_hPhysicalDevice = physicalDevices[0];
1270
Adam Sawicki50882502020-02-07 16:51:31 +01001271 // Query for extensions
1272
1273 uint32_t physicalDeviceExtensionPropertyCount = 0;
1274 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &physicalDeviceExtensionPropertyCount, nullptr) );
1275 std::vector<VkExtensionProperties> physicalDeviceExtensionProperties{physicalDeviceExtensionPropertyCount};
1276 if(physicalDeviceExtensionPropertyCount)
1277 {
1278 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(
1279 g_hPhysicalDevice,
1280 nullptr,
1281 &physicalDeviceExtensionPropertyCount,
1282 physicalDeviceExtensionProperties.data()) );
1283 }
1284
1285 for(uint32_t i = 0; i < physicalDeviceExtensionPropertyCount; ++i)
1286 {
1287 if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1288 VK_KHR_get_memory_requirements2_enabled = true;
1289 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1290 VK_KHR_dedicated_allocation_enabled = true;
1291 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
1292 VK_KHR_bind_memory2_enabled = true;
1293 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
1294 VK_EXT_memory_budget_enabled = true;
1295 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) == 0)
1296 VK_AMD_device_coherent_memory_enabled = true;
1297 }
1298
Adam Sawickie6e498f2017-06-16 17:21:31 +02001299 // Query for features
1300
1301 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1302 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1303
Adam Sawicki50882502020-02-07 16:51:31 +01001304 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1305 VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };
1306 if(VK_AMD_device_coherent_memory_enabled)
1307 {
1308 physicalDeviceCoherentMemoryFeatures.pNext = physicalDeviceFeatures.pNext;
1309 physicalDeviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1310 }
1311 vkGetPhysicalDeviceFeatures2(g_hPhysicalDevice, &physicalDeviceFeatures);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001312
Adam Sawicki50882502020-02-07 16:51:31 +01001313 g_SparseBindingEnabled = physicalDeviceFeatures.features.sparseBinding != 0;
1314
1315 // The extension is supported as fake with no real support for this feature? Don't use it.
1316 if(VK_AMD_device_coherent_memory_enabled && !physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory)
1317 VK_AMD_device_coherent_memory_enabled = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001318
1319 // Find queue family index
1320
1321 uint32_t queueFamilyCount = 0;
1322 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1323 assert(queueFamilyCount > 0);
1324 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1325 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1326 for(uint32_t i = 0;
1327 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001328 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1329 g_PresentQueueFamilyIndex == UINT_MAX ||
1330 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001331 ++i)
1332 {
1333 if(queueFamilies[i].queueCount > 0)
1334 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001335 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001336 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001337 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001338 {
1339 g_GraphicsQueueFamilyIndex = i;
1340 }
1341
1342 VkBool32 surfaceSupported = 0;
1343 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1344 if((res >= 0) && (surfaceSupported == VK_TRUE))
1345 {
1346 g_PresentQueueFamilyIndex = i;
1347 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001348
1349 if(g_SparseBindingEnabled &&
1350 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1351 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1352 {
1353 g_SparseBindingQueueFamilyIndex = i;
1354 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001355 }
1356 }
1357 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1358
Adam Sawicki51fa9662018-10-03 13:44:29 +02001359 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1360
Adam Sawickie6e498f2017-06-16 17:21:31 +02001361 // Create logical device
1362
1363 const float queuePriority = 1.f;
1364
Adam Sawicki51fa9662018-10-03 13:44:29 +02001365 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1366 uint32_t queueCount = 1;
1367 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1368 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1369 queueCreateInfo[0].queueCount = 1;
1370 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1371
1372 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1373 {
1374
1375 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1376 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1377 queueCreateInfo[queueCount].queueCount = 1;
1378 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1379 ++queueCount;
1380 }
1381
1382 if(g_SparseBindingEnabled &&
1383 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1384 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1385 {
1386
1387 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1388 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1389 queueCreateInfo[queueCount].queueCount = 1;
1390 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1391 ++queueCount;
1392 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001393
Adam Sawickie6e498f2017-06-16 17:21:31 +02001394 std::vector<const char*> enabledDeviceExtensions;
1395 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki50882502020-02-07 16:51:31 +01001396 if(VK_KHR_get_memory_requirements2_enabled)
1397 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1398 if(VK_KHR_dedicated_allocation_enabled)
1399 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1400 if(VK_KHR_bind_memory2_enabled)
1401 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1402 if(VK_EXT_memory_budget_enabled)
1403 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
1404 if(VK_AMD_device_coherent_memory_enabled)
1405 enabledDeviceExtensions.push_back(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME);
1406
1407 VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1408 deviceFeatures.features.samplerAnisotropy = VK_TRUE;
1409 deviceFeatures.features.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
1410
1411 if(VK_AMD_device_coherent_memory_enabled)
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001412 {
Adam Sawicki50882502020-02-07 16:51:31 +01001413 physicalDeviceCoherentMemoryFeatures.pNext = deviceFeatures.pNext;
1414 deviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1415 physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory = VK_TRUE;
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001416 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001417
1418 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
Adam Sawicki50882502020-02-07 16:51:31 +01001419 deviceCreateInfo.pNext = &deviceFeatures;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001420 deviceCreateInfo.enabledLayerCount = 0;
1421 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1422 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001423 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001424 deviceCreateInfo.queueCreateInfoCount = queueCount;
1425 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001426
Adam Sawicki1f84f622019-07-02 13:40:01 +02001427 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001428
1429 // Create memory allocator
1430
1431 VmaAllocatorCreateInfo allocatorInfo = {};
Adam Sawicki50882502020-02-07 16:51:31 +01001432 SetAllocatorCreateInfo(allocatorInfo);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001433 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1434
Adam Sawicki51fa9662018-10-03 13:44:29 +02001435 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001436
1437 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1438 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1439 assert(g_hGraphicsQueue);
1440 assert(g_hPresentQueue);
1441
Adam Sawicki51fa9662018-10-03 13:44:29 +02001442 if(g_SparseBindingEnabled)
1443 {
1444 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1445 assert(g_hSparseBindingQueue);
1446 }
1447
Adam Sawickie6e498f2017-06-16 17:21:31 +02001448 // Create command pool
1449
1450 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1451 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1452 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001453 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001454
1455 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1456 commandBufferInfo.commandPool = g_hCommandPool;
1457 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1458 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1459 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1460
1461 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1462 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1463 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1464 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001465 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001466 }
1467
Adam Sawicki1f84f622019-07-02 13:40:01 +02001468 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001469
Adam Sawickie6e498f2017-06-16 17:21:31 +02001470 commandBufferInfo.commandBufferCount = 1;
1471 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1472
1473 // Create texture sampler
1474
1475 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1476 samplerInfo.magFilter = VK_FILTER_LINEAR;
1477 samplerInfo.minFilter = VK_FILTER_LINEAR;
1478 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1479 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1480 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1481 samplerInfo.anisotropyEnable = VK_TRUE;
1482 samplerInfo.maxAnisotropy = 16;
1483 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1484 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1485 samplerInfo.compareEnable = VK_FALSE;
1486 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1487 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1488 samplerInfo.mipLodBias = 0.f;
1489 samplerInfo.minLod = 0.f;
1490 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001491 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001492
1493 CreateTexture(128, 128);
1494 CreateMesh();
1495
1496 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1497 samplerLayoutBinding.binding = 1;
1498 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1499 samplerLayoutBinding.descriptorCount = 1;
1500 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1501
1502 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1503 descriptorSetLayoutInfo.bindingCount = 1;
1504 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001505 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001506
1507 // Create descriptor pool
1508
1509 VkDescriptorPoolSize descriptorPoolSizes[2];
1510 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1511 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1512 descriptorPoolSizes[0].descriptorCount = 1;
1513 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1514 descriptorPoolSizes[1].descriptorCount = 1;
1515
1516 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1517 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1518 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1519 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001520 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001521
1522 // Create descriptor set layout
1523
1524 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1525 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1526 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1527 descriptorSetInfo.descriptorSetCount = 1;
1528 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1529 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1530
1531 VkDescriptorImageInfo descriptorImageInfo = {};
1532 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1533 descriptorImageInfo.imageView = g_hTextureImageView;
1534 descriptorImageInfo.sampler = g_hSampler;
1535
1536 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1537 writeDescriptorSet.dstSet = g_hDescriptorSet;
1538 writeDescriptorSet.dstBinding = 1;
1539 writeDescriptorSet.dstArrayElement = 0;
1540 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1541 writeDescriptorSet.descriptorCount = 1;
1542 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1543
1544 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1545
1546 CreateSwapchain();
1547}
1548
1549static void FinalizeApplication()
1550{
1551 vkDeviceWaitIdle(g_hDevice);
1552
1553 DestroySwapchain(true);
1554
1555 if(g_hDescriptorPool != VK_NULL_HANDLE)
1556 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001557 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001558 g_hDescriptorPool = VK_NULL_HANDLE;
1559 }
1560
1561 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1562 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001563 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001564 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1565 }
1566
1567 if(g_hTextureImageView != VK_NULL_HANDLE)
1568 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001569 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001570 g_hTextureImageView = VK_NULL_HANDLE;
1571 }
1572 if(g_hTextureImage != VK_NULL_HANDLE)
1573 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001574 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001575 g_hTextureImage = VK_NULL_HANDLE;
1576 }
1577
1578 if(g_hIndexBuffer != VK_NULL_HANDLE)
1579 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001580 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001581 g_hIndexBuffer = VK_NULL_HANDLE;
1582 }
1583 if(g_hVertexBuffer != VK_NULL_HANDLE)
1584 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001585 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001586 g_hVertexBuffer = VK_NULL_HANDLE;
1587 }
1588
1589 if(g_hSampler != VK_NULL_HANDLE)
1590 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001591 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001592 g_hSampler = VK_NULL_HANDLE;
1593 }
1594
Adam Sawicki51fa9662018-10-03 13:44:29 +02001595 if(g_ImmediateFence)
1596 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001597 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001598 g_ImmediateFence = VK_NULL_HANDLE;
1599 }
1600
Adam Sawickie6e498f2017-06-16 17:21:31 +02001601 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1602 {
1603 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1604 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001605 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001606 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1607 }
1608 }
1609 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1610 {
1611 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1612 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1613 }
1614 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1615 {
1616 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1617 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1618 }
1619
1620 if(g_hCommandPool != VK_NULL_HANDLE)
1621 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001622 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001623 g_hCommandPool = VK_NULL_HANDLE;
1624 }
1625
1626 if(g_hAllocator != VK_NULL_HANDLE)
1627 {
1628 vmaDestroyAllocator(g_hAllocator);
1629 g_hAllocator = nullptr;
1630 }
1631
1632 if(g_hDevice != VK_NULL_HANDLE)
1633 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001634 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001635 g_hDevice = nullptr;
1636 }
1637
1638 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1639 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001640 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001641 g_hCallback = VK_NULL_HANDLE;
1642 }
1643
1644 if(g_hSurface != VK_NULL_HANDLE)
1645 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001646 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001647 g_hSurface = VK_NULL_HANDLE;
1648 }
1649
1650 if(g_hVulkanInstance != VK_NULL_HANDLE)
1651 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001652 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001653 g_hVulkanInstance = VK_NULL_HANDLE;
1654 }
1655}
1656
1657static void PrintAllocatorStats()
1658{
1659#if VMA_STATS_STRING_ENABLED
1660 char* statsString = nullptr;
1661 vmaBuildStatsString(g_hAllocator, &statsString, true);
1662 printf("%s\n", statsString);
1663 vmaFreeStatsString(g_hAllocator, statsString);
1664#endif
1665}
1666
1667static void RecreateSwapChain()
1668{
1669 vkDeviceWaitIdle(g_hDevice);
1670 DestroySwapchain(false);
1671 CreateSwapchain();
1672}
1673
1674static void DrawFrame()
1675{
1676 // Begin main command buffer
1677 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1678 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1679 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1680
1681 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1682 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1683
1684 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1685 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1686 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1687
1688 // Acquire swapchain image
1689 uint32_t imageIndex = 0;
1690 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1691 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1692 {
1693 RecreateSwapChain();
1694 return;
1695 }
1696 else if(res < 0)
1697 {
1698 ERR_GUARD_VULKAN(res);
1699 }
1700
1701 // Record geometry pass
1702
1703 VkClearValue clearValues[2];
1704 ZeroMemory(clearValues, sizeof(clearValues));
1705 clearValues[0].color.float32[0] = 0.25f;
1706 clearValues[0].color.float32[1] = 0.25f;
1707 clearValues[0].color.float32[2] = 0.5f;
1708 clearValues[0].color.float32[3] = 1.0f;
1709 clearValues[1].depthStencil.depth = 1.0f;
1710
1711 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1712 renderPassBeginInfo.renderPass = g_hRenderPass;
1713 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1714 renderPassBeginInfo.renderArea.offset.x = 0;
1715 renderPassBeginInfo.renderArea.offset.y = 0;
1716 renderPassBeginInfo.renderArea.extent = g_Extent;
1717 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1718 renderPassBeginInfo.pClearValues = clearValues;
1719 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1720
1721 vkCmdBindPipeline(
1722 hCommandBuffer,
1723 VK_PIPELINE_BIND_POINT_GRAPHICS,
1724 g_hPipeline);
1725
Adam Sawicki82c3f332018-06-11 15:27:33 +02001726 mat4 view = mat4::LookAt(
1727 vec3(0.f, 0.f, 0.f),
1728 vec3(0.f, -2.f, 4.f),
1729 vec3(0.f, 1.f, 0.f));
1730 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001731 1.0471975511966f, // 60 degrees
1732 (float)g_Extent.width / (float)g_Extent.height,
1733 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001734 1000.f);
1735 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001736
1737 vkCmdBindDescriptorSets(
1738 hCommandBuffer,
1739 VK_PIPELINE_BIND_POINT_GRAPHICS,
1740 g_hPipelineLayout,
1741 0,
1742 1,
1743 &g_hDescriptorSet,
1744 0,
1745 nullptr);
1746
Adam Sawicki82c3f332018-06-11 15:27:33 +02001747 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1748 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001749
1750 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001751 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001752 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1753
1754 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1755 VkDeviceSize offsets[] = { 0 };
1756 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1757
1758 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1759
1760 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1761
1762 vkCmdEndRenderPass(hCommandBuffer);
1763
1764 vkEndCommandBuffer(hCommandBuffer);
1765
1766 // Submit command buffer
1767
1768 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1769 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1770 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1771 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1772 submitInfo.waitSemaphoreCount = 1;
1773 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1774 submitInfo.pWaitDstStageMask = submitWaitStages;
1775 submitInfo.commandBufferCount = 1;
1776 submitInfo.pCommandBuffers = &hCommandBuffer;
1777 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1778 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1779 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1780
1781 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1782
1783 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1784 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1785 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1786 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1787 presentInfo.swapchainCount = 1;
1788 presentInfo.pSwapchains = swapchains;
1789 presentInfo.pImageIndices = &imageIndex;
1790 presentInfo.pResults = nullptr;
1791 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1792 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1793 {
1794 RecreateSwapChain();
1795 }
1796 else
1797 ERR_GUARD_VULKAN(res);
1798}
1799
1800static void HandlePossibleSizeChange()
1801{
1802 RECT clientRect;
1803 GetClientRect(g_hWnd, &clientRect);
1804 LONG newSizeX = clientRect.right - clientRect.left;
1805 LONG newSizeY = clientRect.bottom - clientRect.top;
1806 if((newSizeX > 0) &&
1807 (newSizeY > 0) &&
1808 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1809 {
1810 g_SizeX = newSizeX;
1811 g_SizeY = newSizeY;
1812
1813 RecreateSwapChain();
1814 }
1815}
1816
1817static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1818{
1819 switch(msg)
1820 {
1821 case WM_CREATE:
1822 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1823 g_hWnd = hWnd;
1824 InitializeApplication();
1825 PrintAllocatorStats();
1826 return 0;
1827
1828 case WM_DESTROY:
1829 FinalizeApplication();
1830 PostQuitMessage(0);
1831 return 0;
1832
1833 // This prevents app from freezing when left Alt is pressed
1834 // (which normally enters modal menu loop).
1835 case WM_SYSKEYDOWN:
1836 case WM_SYSKEYUP:
1837 return 0;
1838
1839 case WM_SIZE:
1840 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1841 HandlePossibleSizeChange();
1842 return 0;
1843
1844 case WM_EXITSIZEMOVE:
1845 HandlePossibleSizeChange();
1846 return 0;
1847
1848 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001849 switch(wParam)
1850 {
1851 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001852 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001853 break;
1854 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001855 try
1856 {
1857 Test();
1858 }
1859 catch(const std::exception& ex)
1860 {
1861 printf("ERROR: %s\n", ex.what());
1862 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001863 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001864 case 'S':
1865 try
1866 {
1867 if(g_SparseBindingEnabled)
1868 {
1869 TestSparseBinding();
1870 }
1871 else
1872 {
1873 printf("Sparse binding not supported.\n");
1874 }
1875 }
1876 catch(const std::exception& ex)
1877 {
1878 printf("ERROR: %s\n", ex.what());
1879 }
1880 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001881 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001882 return 0;
1883
1884 default:
1885 break;
1886 }
1887
1888 return DefWindowProc(hWnd, msg, wParam, lParam);
1889}
1890
1891int main()
1892{
1893 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1894
1895 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1896 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1897 wndClassDesc.hbrBackground = NULL;
1898 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1899 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1900 wndClassDesc.hInstance = g_hAppInstance;
1901 wndClassDesc.lpfnWndProc = WndProc;
1902 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1903
1904 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1905 assert(hWndClass);
1906
1907 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1908 const DWORD exStyle = 0;
1909
1910 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1911 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1912
Adam Sawicki86ccd632017-07-04 14:57:53 +02001913 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001914 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1915 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1916 NULL, NULL, g_hAppInstance, NULL);
1917
1918 MSG msg;
1919 for(;;)
1920 {
1921 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1922 {
1923 if(msg.message == WM_QUIT)
1924 break;
1925 TranslateMessage(&msg);
1926 DispatchMessage(&msg);
1927 }
1928 if(g_hDevice != VK_NULL_HANDLE)
1929 DrawFrame();
1930 }
1931
Adam Sawicki8317ba92019-11-18 13:14:11 +01001932 TEST(g_CpuAllocCount.load() == 0);
1933
Adam Sawickie6e498f2017-06-16 17:21:31 +02001934 return 0;
1935}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001936
Adam Sawickif1a793c2018-03-13 15:42:22 +01001937#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001938
Adam Sawickif1a793c2018-03-13 15:42:22 +01001939#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001940
1941int main()
1942{
1943}
1944
Adam Sawickif1a793c2018-03-13 15:42:22 +01001945#endif // #ifdef _WIN32