blob: 7b6774f4c801a9560ae5fde87415616395f14b78 [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 Sawickie9bfb532019-12-04 14:26:59 +010035static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.3.0";
36static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.3.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{
1121 return VMA_VULKAN_VERSION == 1001000 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0;
1122}
1123
1124void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
1125{
1126 outInfo = {};
1127
1128 outInfo.physicalDevice = g_hPhysicalDevice;
1129 outInfo.device = g_hDevice;
1130 outInfo.instance = g_hVulkanInstance;
1131 outInfo.vulkanApiVersion = GetVulkanApiVersion();
1132
1133 if(VK_KHR_dedicated_allocation_enabled)
1134 {
1135 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1136 }
1137 if(VK_KHR_bind_memory2_enabled)
1138 {
1139 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
1140 }
1141#if !defined(VMA_MEMORY_BUDGET) || VMA_MEMORY_BUDGET == 1
1142 if(VK_EXT_memory_budget_enabled && VK_KHR_get_physical_device_properties2_enabled)
1143 {
1144 outInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
1145 }
1146#endif
1147 if(VK_AMD_device_coherent_memory_enabled)
1148 {
1149 outInfo.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT;
1150 }
1151
1152 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1153 {
1154 outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
1155 }
1156
1157 // Uncomment to enable recording to CSV file.
1158 /*
1159 static VmaRecordSettings recordSettings = {};
1160 recordSettings.pFilePath = "VulkanSample.csv";
1161 outInfo.pRecordSettings = &recordSettings;
1162 */
1163
1164 // Uncomment to enable HeapSizeLimit.
1165 /*
1166 static std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapSizeLimit;
1167 std::fill(heapSizeLimit.begin(), heapSizeLimit.end(), VK_WHOLE_SIZE);
1168 heapSizeLimit[0] = 512ull * 1024 * 1024;
1169 outInfo.pHeapSizeLimit = heapSizeLimit.data();
1170 */
1171}
1172
Adam Sawickie6e498f2017-06-16 17:21:31 +02001173static void InitializeApplication()
1174{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001175 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1176 {
1177 g_Allocs = &g_CpuAllocationCallbacks;
1178 }
1179
Adam Sawickie6e498f2017-06-16 17:21:31 +02001180 uint32_t instanceLayerPropCount = 0;
1181 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1182 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1183 if(instanceLayerPropCount > 0)
1184 {
1185 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1186 }
1187
1188 if(g_EnableValidationLayer == true)
1189 {
1190 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1191 {
1192 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1193 g_EnableValidationLayer = false;
1194 }
1195 }
1196
Adam Sawicki353e3672019-11-02 14:12:05 +01001197 uint32_t availableInstanceExtensionCount = 0;
1198 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
1199 std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
1200 if(availableInstanceExtensionCount > 0)
1201 {
1202 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
1203 }
1204
1205 std::vector<const char*> enabledInstanceExtensions;
1206 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1207 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001208
1209 std::vector<const char*> instanceLayers;
1210 if(g_EnableValidationLayer == true)
1211 {
1212 instanceLayers.push_back(VALIDATION_LAYER_NAME);
Adam Sawicki353e3672019-11-02 14:12:05 +01001213 enabledInstanceExtensions.push_back("VK_EXT_debug_report");
1214 }
1215
1216 for(const auto& extensionProperties : availableInstanceExtensions)
1217 {
1218 if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
1219 {
1220 enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1221 VK_KHR_get_physical_device_properties2_enabled = true;
1222 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001223 }
1224
1225 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1226 appInfo.pApplicationName = APP_TITLE_A;
1227 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1228 appInfo.pEngineName = "Adam Sawicki Engine";
1229 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
Adam Sawicki50882502020-02-07 16:51:31 +01001230 appInfo.apiVersion = GetVulkanApiVersion();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001231
1232 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1233 instInfo.pApplicationInfo = &appInfo;
Adam Sawicki353e3672019-11-02 14:12:05 +01001234 instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
1235 instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001236 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1237 instInfo.ppEnabledLayerNames = instanceLayers.data();
1238
Adam Sawicki1f84f622019-07-02 13:40:01 +02001239 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001240
1241 // Create VkSurfaceKHR.
1242 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1243 surfaceInfo.hinstance = g_hAppInstance;
1244 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001245 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001246 assert(result == VK_SUCCESS);
1247
1248 if(g_EnableValidationLayer == true)
1249 RegisterDebugCallbacks();
1250
1251 // Find physical device
1252
1253 uint32_t deviceCount = 0;
1254 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1255 assert(deviceCount > 0);
1256
1257 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1258 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1259
1260 g_hPhysicalDevice = physicalDevices[0];
1261
Adam Sawicki50882502020-02-07 16:51:31 +01001262 // Query for extensions
1263
1264 uint32_t physicalDeviceExtensionPropertyCount = 0;
1265 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &physicalDeviceExtensionPropertyCount, nullptr) );
1266 std::vector<VkExtensionProperties> physicalDeviceExtensionProperties{physicalDeviceExtensionPropertyCount};
1267 if(physicalDeviceExtensionPropertyCount)
1268 {
1269 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(
1270 g_hPhysicalDevice,
1271 nullptr,
1272 &physicalDeviceExtensionPropertyCount,
1273 physicalDeviceExtensionProperties.data()) );
1274 }
1275
1276 for(uint32_t i = 0; i < physicalDeviceExtensionPropertyCount; ++i)
1277 {
1278 if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1279 VK_KHR_get_memory_requirements2_enabled = true;
1280 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1281 VK_KHR_dedicated_allocation_enabled = true;
1282 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
1283 VK_KHR_bind_memory2_enabled = true;
1284 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
1285 VK_EXT_memory_budget_enabled = true;
1286 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) == 0)
1287 VK_AMD_device_coherent_memory_enabled = true;
1288 }
1289
Adam Sawickie6e498f2017-06-16 17:21:31 +02001290 // Query for features
1291
1292 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1293 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1294
Adam Sawicki50882502020-02-07 16:51:31 +01001295 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1296 VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };
1297 if(VK_AMD_device_coherent_memory_enabled)
1298 {
1299 physicalDeviceCoherentMemoryFeatures.pNext = physicalDeviceFeatures.pNext;
1300 physicalDeviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1301 }
1302 vkGetPhysicalDeviceFeatures2(g_hPhysicalDevice, &physicalDeviceFeatures);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001303
Adam Sawicki50882502020-02-07 16:51:31 +01001304 g_SparseBindingEnabled = physicalDeviceFeatures.features.sparseBinding != 0;
1305
1306 // The extension is supported as fake with no real support for this feature? Don't use it.
1307 if(VK_AMD_device_coherent_memory_enabled && !physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory)
1308 VK_AMD_device_coherent_memory_enabled = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001309
1310 // Find queue family index
1311
1312 uint32_t queueFamilyCount = 0;
1313 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1314 assert(queueFamilyCount > 0);
1315 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1316 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1317 for(uint32_t i = 0;
1318 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001319 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1320 g_PresentQueueFamilyIndex == UINT_MAX ||
1321 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001322 ++i)
1323 {
1324 if(queueFamilies[i].queueCount > 0)
1325 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001326 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001327 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001328 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001329 {
1330 g_GraphicsQueueFamilyIndex = i;
1331 }
1332
1333 VkBool32 surfaceSupported = 0;
1334 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1335 if((res >= 0) && (surfaceSupported == VK_TRUE))
1336 {
1337 g_PresentQueueFamilyIndex = i;
1338 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001339
1340 if(g_SparseBindingEnabled &&
1341 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1342 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1343 {
1344 g_SparseBindingQueueFamilyIndex = i;
1345 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001346 }
1347 }
1348 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1349
Adam Sawicki51fa9662018-10-03 13:44:29 +02001350 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1351
Adam Sawickie6e498f2017-06-16 17:21:31 +02001352 // Create logical device
1353
1354 const float queuePriority = 1.f;
1355
Adam Sawicki51fa9662018-10-03 13:44:29 +02001356 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1357 uint32_t queueCount = 1;
1358 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1359 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1360 queueCreateInfo[0].queueCount = 1;
1361 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1362
1363 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1364 {
1365
1366 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1367 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1368 queueCreateInfo[queueCount].queueCount = 1;
1369 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1370 ++queueCount;
1371 }
1372
1373 if(g_SparseBindingEnabled &&
1374 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1375 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1376 {
1377
1378 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1379 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1380 queueCreateInfo[queueCount].queueCount = 1;
1381 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1382 ++queueCount;
1383 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001384
Adam Sawickie6e498f2017-06-16 17:21:31 +02001385 std::vector<const char*> enabledDeviceExtensions;
1386 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki50882502020-02-07 16:51:31 +01001387 if(VK_KHR_get_memory_requirements2_enabled)
1388 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1389 if(VK_KHR_dedicated_allocation_enabled)
1390 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1391 if(VK_KHR_bind_memory2_enabled)
1392 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1393 if(VK_EXT_memory_budget_enabled)
1394 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
1395 if(VK_AMD_device_coherent_memory_enabled)
1396 enabledDeviceExtensions.push_back(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME);
1397
1398 VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1399 deviceFeatures.features.samplerAnisotropy = VK_TRUE;
1400 deviceFeatures.features.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
1401
1402 if(VK_AMD_device_coherent_memory_enabled)
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001403 {
Adam Sawicki50882502020-02-07 16:51:31 +01001404 physicalDeviceCoherentMemoryFeatures.pNext = deviceFeatures.pNext;
1405 deviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1406 physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory = VK_TRUE;
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001407 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001408
1409 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
Adam Sawicki50882502020-02-07 16:51:31 +01001410 deviceCreateInfo.pNext = &deviceFeatures;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001411 deviceCreateInfo.enabledLayerCount = 0;
1412 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1413 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001414 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001415 deviceCreateInfo.queueCreateInfoCount = queueCount;
1416 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001417
Adam Sawicki1f84f622019-07-02 13:40:01 +02001418 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001419
1420 // Create memory allocator
1421
1422 VmaAllocatorCreateInfo allocatorInfo = {};
Adam Sawicki50882502020-02-07 16:51:31 +01001423 SetAllocatorCreateInfo(allocatorInfo);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001424 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1425
Adam Sawicki51fa9662018-10-03 13:44:29 +02001426 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001427
1428 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1429 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1430 assert(g_hGraphicsQueue);
1431 assert(g_hPresentQueue);
1432
Adam Sawicki51fa9662018-10-03 13:44:29 +02001433 if(g_SparseBindingEnabled)
1434 {
1435 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1436 assert(g_hSparseBindingQueue);
1437 }
1438
Adam Sawickie6e498f2017-06-16 17:21:31 +02001439 // Create command pool
1440
1441 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1442 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1443 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001444 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001445
1446 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1447 commandBufferInfo.commandPool = g_hCommandPool;
1448 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1449 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1450 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1451
1452 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1453 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1454 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1455 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001456 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001457 }
1458
Adam Sawicki1f84f622019-07-02 13:40:01 +02001459 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001460
Adam Sawickie6e498f2017-06-16 17:21:31 +02001461 commandBufferInfo.commandBufferCount = 1;
1462 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1463
1464 // Create texture sampler
1465
1466 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1467 samplerInfo.magFilter = VK_FILTER_LINEAR;
1468 samplerInfo.minFilter = VK_FILTER_LINEAR;
1469 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1470 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1471 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1472 samplerInfo.anisotropyEnable = VK_TRUE;
1473 samplerInfo.maxAnisotropy = 16;
1474 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1475 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1476 samplerInfo.compareEnable = VK_FALSE;
1477 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1478 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1479 samplerInfo.mipLodBias = 0.f;
1480 samplerInfo.minLod = 0.f;
1481 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001482 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001483
1484 CreateTexture(128, 128);
1485 CreateMesh();
1486
1487 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1488 samplerLayoutBinding.binding = 1;
1489 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1490 samplerLayoutBinding.descriptorCount = 1;
1491 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1492
1493 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1494 descriptorSetLayoutInfo.bindingCount = 1;
1495 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001496 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001497
1498 // Create descriptor pool
1499
1500 VkDescriptorPoolSize descriptorPoolSizes[2];
1501 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1502 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1503 descriptorPoolSizes[0].descriptorCount = 1;
1504 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1505 descriptorPoolSizes[1].descriptorCount = 1;
1506
1507 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1508 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1509 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1510 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001511 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001512
1513 // Create descriptor set layout
1514
1515 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1516 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1517 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1518 descriptorSetInfo.descriptorSetCount = 1;
1519 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1520 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1521
1522 VkDescriptorImageInfo descriptorImageInfo = {};
1523 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1524 descriptorImageInfo.imageView = g_hTextureImageView;
1525 descriptorImageInfo.sampler = g_hSampler;
1526
1527 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1528 writeDescriptorSet.dstSet = g_hDescriptorSet;
1529 writeDescriptorSet.dstBinding = 1;
1530 writeDescriptorSet.dstArrayElement = 0;
1531 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1532 writeDescriptorSet.descriptorCount = 1;
1533 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1534
1535 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1536
1537 CreateSwapchain();
1538}
1539
1540static void FinalizeApplication()
1541{
1542 vkDeviceWaitIdle(g_hDevice);
1543
1544 DestroySwapchain(true);
1545
1546 if(g_hDescriptorPool != VK_NULL_HANDLE)
1547 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001548 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001549 g_hDescriptorPool = VK_NULL_HANDLE;
1550 }
1551
1552 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1553 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001554 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001555 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1556 }
1557
1558 if(g_hTextureImageView != VK_NULL_HANDLE)
1559 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001560 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001561 g_hTextureImageView = VK_NULL_HANDLE;
1562 }
1563 if(g_hTextureImage != VK_NULL_HANDLE)
1564 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001565 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001566 g_hTextureImage = VK_NULL_HANDLE;
1567 }
1568
1569 if(g_hIndexBuffer != VK_NULL_HANDLE)
1570 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001571 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001572 g_hIndexBuffer = VK_NULL_HANDLE;
1573 }
1574 if(g_hVertexBuffer != VK_NULL_HANDLE)
1575 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001576 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001577 g_hVertexBuffer = VK_NULL_HANDLE;
1578 }
1579
1580 if(g_hSampler != VK_NULL_HANDLE)
1581 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001582 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001583 g_hSampler = VK_NULL_HANDLE;
1584 }
1585
Adam Sawicki51fa9662018-10-03 13:44:29 +02001586 if(g_ImmediateFence)
1587 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001588 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001589 g_ImmediateFence = VK_NULL_HANDLE;
1590 }
1591
Adam Sawickie6e498f2017-06-16 17:21:31 +02001592 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1593 {
1594 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1595 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001596 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001597 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1598 }
1599 }
1600 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1601 {
1602 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1603 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1604 }
1605 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1606 {
1607 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1608 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1609 }
1610
1611 if(g_hCommandPool != VK_NULL_HANDLE)
1612 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001613 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001614 g_hCommandPool = VK_NULL_HANDLE;
1615 }
1616
1617 if(g_hAllocator != VK_NULL_HANDLE)
1618 {
1619 vmaDestroyAllocator(g_hAllocator);
1620 g_hAllocator = nullptr;
1621 }
1622
1623 if(g_hDevice != VK_NULL_HANDLE)
1624 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001625 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001626 g_hDevice = nullptr;
1627 }
1628
1629 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1630 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001631 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001632 g_hCallback = VK_NULL_HANDLE;
1633 }
1634
1635 if(g_hSurface != VK_NULL_HANDLE)
1636 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001637 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001638 g_hSurface = VK_NULL_HANDLE;
1639 }
1640
1641 if(g_hVulkanInstance != VK_NULL_HANDLE)
1642 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001643 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001644 g_hVulkanInstance = VK_NULL_HANDLE;
1645 }
1646}
1647
1648static void PrintAllocatorStats()
1649{
1650#if VMA_STATS_STRING_ENABLED
1651 char* statsString = nullptr;
1652 vmaBuildStatsString(g_hAllocator, &statsString, true);
1653 printf("%s\n", statsString);
1654 vmaFreeStatsString(g_hAllocator, statsString);
1655#endif
1656}
1657
1658static void RecreateSwapChain()
1659{
1660 vkDeviceWaitIdle(g_hDevice);
1661 DestroySwapchain(false);
1662 CreateSwapchain();
1663}
1664
1665static void DrawFrame()
1666{
1667 // Begin main command buffer
1668 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1669 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1670 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1671
1672 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1673 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1674
1675 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1676 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1677 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1678
1679 // Acquire swapchain image
1680 uint32_t imageIndex = 0;
1681 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1682 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1683 {
1684 RecreateSwapChain();
1685 return;
1686 }
1687 else if(res < 0)
1688 {
1689 ERR_GUARD_VULKAN(res);
1690 }
1691
1692 // Record geometry pass
1693
1694 VkClearValue clearValues[2];
1695 ZeroMemory(clearValues, sizeof(clearValues));
1696 clearValues[0].color.float32[0] = 0.25f;
1697 clearValues[0].color.float32[1] = 0.25f;
1698 clearValues[0].color.float32[2] = 0.5f;
1699 clearValues[0].color.float32[3] = 1.0f;
1700 clearValues[1].depthStencil.depth = 1.0f;
1701
1702 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1703 renderPassBeginInfo.renderPass = g_hRenderPass;
1704 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1705 renderPassBeginInfo.renderArea.offset.x = 0;
1706 renderPassBeginInfo.renderArea.offset.y = 0;
1707 renderPassBeginInfo.renderArea.extent = g_Extent;
1708 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1709 renderPassBeginInfo.pClearValues = clearValues;
1710 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1711
1712 vkCmdBindPipeline(
1713 hCommandBuffer,
1714 VK_PIPELINE_BIND_POINT_GRAPHICS,
1715 g_hPipeline);
1716
Adam Sawicki82c3f332018-06-11 15:27:33 +02001717 mat4 view = mat4::LookAt(
1718 vec3(0.f, 0.f, 0.f),
1719 vec3(0.f, -2.f, 4.f),
1720 vec3(0.f, 1.f, 0.f));
1721 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001722 1.0471975511966f, // 60 degrees
1723 (float)g_Extent.width / (float)g_Extent.height,
1724 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001725 1000.f);
1726 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001727
1728 vkCmdBindDescriptorSets(
1729 hCommandBuffer,
1730 VK_PIPELINE_BIND_POINT_GRAPHICS,
1731 g_hPipelineLayout,
1732 0,
1733 1,
1734 &g_hDescriptorSet,
1735 0,
1736 nullptr);
1737
Adam Sawicki82c3f332018-06-11 15:27:33 +02001738 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1739 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001740
1741 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001742 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001743 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1744
1745 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1746 VkDeviceSize offsets[] = { 0 };
1747 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1748
1749 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1750
1751 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1752
1753 vkCmdEndRenderPass(hCommandBuffer);
1754
1755 vkEndCommandBuffer(hCommandBuffer);
1756
1757 // Submit command buffer
1758
1759 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1760 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1761 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1762 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1763 submitInfo.waitSemaphoreCount = 1;
1764 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1765 submitInfo.pWaitDstStageMask = submitWaitStages;
1766 submitInfo.commandBufferCount = 1;
1767 submitInfo.pCommandBuffers = &hCommandBuffer;
1768 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1769 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1770 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1771
1772 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1773
1774 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1775 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1776 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1777 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1778 presentInfo.swapchainCount = 1;
1779 presentInfo.pSwapchains = swapchains;
1780 presentInfo.pImageIndices = &imageIndex;
1781 presentInfo.pResults = nullptr;
1782 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1783 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1784 {
1785 RecreateSwapChain();
1786 }
1787 else
1788 ERR_GUARD_VULKAN(res);
1789}
1790
1791static void HandlePossibleSizeChange()
1792{
1793 RECT clientRect;
1794 GetClientRect(g_hWnd, &clientRect);
1795 LONG newSizeX = clientRect.right - clientRect.left;
1796 LONG newSizeY = clientRect.bottom - clientRect.top;
1797 if((newSizeX > 0) &&
1798 (newSizeY > 0) &&
1799 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1800 {
1801 g_SizeX = newSizeX;
1802 g_SizeY = newSizeY;
1803
1804 RecreateSwapChain();
1805 }
1806}
1807
1808static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1809{
1810 switch(msg)
1811 {
1812 case WM_CREATE:
1813 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1814 g_hWnd = hWnd;
1815 InitializeApplication();
1816 PrintAllocatorStats();
1817 return 0;
1818
1819 case WM_DESTROY:
1820 FinalizeApplication();
1821 PostQuitMessage(0);
1822 return 0;
1823
1824 // This prevents app from freezing when left Alt is pressed
1825 // (which normally enters modal menu loop).
1826 case WM_SYSKEYDOWN:
1827 case WM_SYSKEYUP:
1828 return 0;
1829
1830 case WM_SIZE:
1831 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1832 HandlePossibleSizeChange();
1833 return 0;
1834
1835 case WM_EXITSIZEMOVE:
1836 HandlePossibleSizeChange();
1837 return 0;
1838
1839 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001840 switch(wParam)
1841 {
1842 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001843 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001844 break;
1845 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001846 try
1847 {
1848 Test();
1849 }
1850 catch(const std::exception& ex)
1851 {
1852 printf("ERROR: %s\n", ex.what());
1853 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001854 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001855 case 'S':
1856 try
1857 {
1858 if(g_SparseBindingEnabled)
1859 {
1860 TestSparseBinding();
1861 }
1862 else
1863 {
1864 printf("Sparse binding not supported.\n");
1865 }
1866 }
1867 catch(const std::exception& ex)
1868 {
1869 printf("ERROR: %s\n", ex.what());
1870 }
1871 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001872 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001873 return 0;
1874
1875 default:
1876 break;
1877 }
1878
1879 return DefWindowProc(hWnd, msg, wParam, lParam);
1880}
1881
1882int main()
1883{
1884 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1885
1886 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1887 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1888 wndClassDesc.hbrBackground = NULL;
1889 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1890 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1891 wndClassDesc.hInstance = g_hAppInstance;
1892 wndClassDesc.lpfnWndProc = WndProc;
1893 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1894
1895 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1896 assert(hWndClass);
1897
1898 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1899 const DWORD exStyle = 0;
1900
1901 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1902 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1903
Adam Sawicki86ccd632017-07-04 14:57:53 +02001904 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001905 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1906 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1907 NULL, NULL, g_hAppInstance, NULL);
1908
1909 MSG msg;
1910 for(;;)
1911 {
1912 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1913 {
1914 if(msg.message == WM_QUIT)
1915 break;
1916 TranslateMessage(&msg);
1917 DispatchMessage(&msg);
1918 }
1919 if(g_hDevice != VK_NULL_HANDLE)
1920 DrawFrame();
1921 }
1922
Adam Sawicki8317ba92019-11-18 13:14:11 +01001923 TEST(g_CpuAllocCount.load() == 0);
1924
Adam Sawickie6e498f2017-06-16 17:21:31 +02001925 return 0;
1926}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001927
Adam Sawickif1a793c2018-03-13 15:42:22 +01001928#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001929
Adam Sawickif1a793c2018-03-13 15:42:22 +01001930#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001931
1932int main()
1933{
1934}
1935
Adam Sawickif1a793c2018-03-13 15:42:22 +01001936#endif // #ifdef _WIN32