blob: e9872d5e4b3866fab6087a4c3a05cf839819b222 [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawickiae5c4662019-01-02 10:23:35 +01002// Copyright (c) 2017-2019 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 Sawickia68c01c2018-03-13 16:40:45 +010049static bool g_EnableValidationLayer = true;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010050static bool VK_KHR_get_memory_requirements2_enabled = false;
Adam Sawicki353e3672019-11-02 14:12:05 +010051static bool VK_KHR_get_physical_device_properties2_enabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010052static bool VK_KHR_dedicated_allocation_enabled = false;
Adam Sawicki4abe30c2019-07-02 14:37:21 +020053static bool VK_KHR_bind_memory2_enabled = false;
Adam Sawicki353e3672019-11-02 14:12:05 +010054static bool VK_EXT_memory_budget_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020055bool g_SparseBindingEnabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010056
Adam Sawickie6e498f2017-06-16 17:21:31 +020057static HINSTANCE g_hAppInstance;
58static HWND g_hWnd;
59static LONG g_SizeX = 1280, g_SizeY = 720;
Adam Sawickie6e498f2017-06-16 17:21:31 +020060static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020061static VkQueue g_hPresentQueue;
62static VkSurfaceFormatKHR g_SurfaceFormat;
63static VkExtent2D g_Extent;
64static VkSwapchainKHR g_hSwapchain;
65static std::vector<VkImage> g_SwapchainImages;
66static std::vector<VkImageView> g_SwapchainImageViews;
67static std::vector<VkFramebuffer> g_Framebuffers;
68static VkCommandPool g_hCommandPool;
69static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
70static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020071VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020072static uint32_t g_NextCommandBufferIndex;
73static VkSemaphore g_hImageAvailableSemaphore;
74static VkSemaphore g_hRenderFinishedSemaphore;
75static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
76static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020077static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020078static VkDescriptorSetLayout g_hDescriptorSetLayout;
79static VkDescriptorPool g_hDescriptorPool;
80static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
81static VkSampler g_hSampler;
82static VkFormat g_DepthFormat;
83static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +020084static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +020085static VkImageView g_hDepthImageView;
86
87static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
88static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
89static std::vector<VkPresentModeKHR> g_PresentModes;
90
91static PFN_vkCreateDebugReportCallbackEXT g_pvkCreateDebugReportCallbackEXT;
92static PFN_vkDebugReportMessageEXT g_pvkDebugReportMessageEXT;
93static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
94static VkDebugReportCallbackEXT g_hCallback;
95
Adam Sawickie6e498f2017-06-16 17:21:31 +020096static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +020097VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +010098VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +020099
100static VkPipelineLayout g_hPipelineLayout;
101static VkRenderPass g_hRenderPass;
102static VkPipeline g_hPipeline;
103
104static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200105static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200106static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200107static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200108static uint32_t g_VertexCount;
109static uint32_t g_IndexCount;
110
111static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200112static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200113static VkImageView g_hTextureImageView;
114
Adam Sawicki8317ba92019-11-18 13:14:11 +0100115static std::atomic_uint32_t g_CpuAllocCount;
116
Adam Sawickia68c01c2018-03-13 16:40:45 +0100117static void* CustomCpuAllocation(
118 void* pUserData, size_t size, size_t alignment,
119 VkSystemAllocationScope allocationScope)
120{
121 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100122 void* const result = _aligned_malloc(size, alignment);
123 if(result)
124 {
125 ++g_CpuAllocCount;
126 }
127 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100128}
129
130static void* CustomCpuReallocation(
131 void* pUserData, void* pOriginal, size_t size, size_t alignment,
132 VkSystemAllocationScope allocationScope)
133{
134 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100135 void* const result = _aligned_realloc(pOriginal, size, alignment);
136 if(pOriginal && !result)
137 {
138 --g_CpuAllocCount;
139 }
140 else if(!pOriginal && result)
141 {
142 ++g_CpuAllocCount;
143 }
144 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100145}
146
147static void CustomCpuFree(void* pUserData, void* pMemory)
148{
149 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100150 if(pMemory)
151 {
152 const uint32_t oldAllocCount = g_CpuAllocCount.fetch_sub(1);
153 TEST(oldAllocCount > 0);
154 _aligned_free(pMemory);
155 }
Adam Sawickia68c01c2018-03-13 16:40:45 +0100156}
157
Adam Sawicki1f84f622019-07-02 13:40:01 +0200158static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
159 CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA, // pUserData
160 &CustomCpuAllocation, // pfnAllocation
161 &CustomCpuReallocation, // pfnReallocation
162 &CustomCpuFree // pfnFree
163};
164
165const VkAllocationCallbacks* g_Allocs;
166
Adam Sawicki978fcf52018-12-05 14:38:48 +0100167void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200168{
169 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
170 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
171 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
172}
173
Adam Sawicki978fcf52018-12-05 14:38:48 +0100174void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200175{
176 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
177
178 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
179 submitInfo.commandBufferCount = 1;
180 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
181
182 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
183 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
184}
185
Adam Sawickida6c1942018-12-05 17:34:34 +0100186void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200187{
188 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
189 if(file.is_open() == false)
190 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
191 assert(file.is_open());
192 size_t fileSize = (size_t)file.tellg();
193 if(fileSize > 0)
194 {
195 out.resize(fileSize);
196 file.seekg(0);
197 file.read(out.data(), fileSize);
198 file.close();
199 }
200 else
201 out.clear();
202}
203
204VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback(
205 VkDebugReportFlagsEXT flags,
206 VkDebugReportObjectTypeEXT objectType,
207 uint64_t object,
208 size_t location,
209 int32_t messageCode,
210 const char* pLayerPrefix,
211 const char* pMessage,
212 void* pUserData)
213{
Adam Sawickib8333fb2018-03-13 16:15:53 +0100214 // "Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug."
215 if(!g_MemoryAliasingWarningEnabled && flags == VK_DEBUG_REPORT_WARNING_BIT_EXT &&
216 (strstr(pMessage, " is aliased with non-linear ") || strstr(pMessage, " is aliased with linear ")))
217 {
218 return VK_FALSE;
219 }
220
221 // Ignoring because when VK_KHR_dedicated_allocation extension is enabled,
222 // vkGetBufferMemoryRequirements2KHR function is used instead, while Validation
223 // Layer seems to be unaware of it.
224 if (strstr(pMessage, "but vkGetBufferMemoryRequirements() has not been called on that buffer") != nullptr)
225 {
226 return VK_FALSE;
227 }
228 if (strstr(pMessage, "but vkGetImageMemoryRequirements() has not been called on that image") != nullptr)
229 {
230 return VK_FALSE;
231 }
Adam Sawicki94e82062018-08-20 11:12:51 +0200232
233 /*
234 "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."
235 Ignoring because we map entire VkDeviceMemory blocks, where different types of
236 images and buffers may end up together, especially on GPUs with unified memory
237 like Intel.
238 */
239 if(strstr(pMessage, "Mapping an image with layout") != nullptr &&
240 strstr(pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr)
241 {
242 return VK_FALSE;
243 }
Adam Sawickib8333fb2018-03-13 16:15:53 +0100244
245 switch(flags)
246 {
247 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
248 SetConsoleColor(CONSOLE_COLOR::WARNING);
249 break;
250 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
251 SetConsoleColor(CONSOLE_COLOR::ERROR_);
252 break;
253 default:
254 SetConsoleColor(CONSOLE_COLOR::INFO);
255 }
256
Adam Sawickie6e498f2017-06-16 17:21:31 +0200257 printf("%s \xBA %s\n", pLayerPrefix, pMessage);
258
Adam Sawickib8333fb2018-03-13 16:15:53 +0100259 SetConsoleColor(CONSOLE_COLOR::NORMAL);
260
261 if(flags == VK_DEBUG_REPORT_WARNING_BIT_EXT ||
262 flags == VK_DEBUG_REPORT_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200263 {
264 OutputDebugStringA(pMessage);
265 OutputDebugStringA("\n");
266 }
267
268 return VK_FALSE;
269}
270
271static VkSurfaceFormatKHR ChooseSurfaceFormat()
272{
273 assert(!g_SurfaceFormats.empty());
274
275 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
276 {
277 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
278 return result;
279 }
280
281 for(const auto& format : g_SurfaceFormats)
282 {
283 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
284 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
285 {
286 return format;
287 }
288 }
289
290 return g_SurfaceFormats[0];
291}
292
293VkPresentModeKHR ChooseSwapPresentMode()
294{
295 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
296
297 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
298 g_PresentModes.end())
299 {
300 return preferredMode;
301 }
302
303 return VK_PRESENT_MODE_FIFO_KHR;
304}
305
306static VkExtent2D ChooseSwapExtent()
307{
308 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
309 return g_SurfaceCapabilities.currentExtent;
310
311 VkExtent2D result = {
312 std::max(g_SurfaceCapabilities.minImageExtent.width,
313 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
314 std::max(g_SurfaceCapabilities.minImageExtent.height,
315 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
316 return result;
317}
318
319struct Vertex
320{
321 float pos[3];
322 float color[3];
323 float texCoord[2];
324};
325
326static void CreateMesh()
327{
328 assert(g_hAllocator);
329
330 static Vertex vertices[] = {
331 // -X
332 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
333 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
334 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
335 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
336 // +X
337 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
338 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
339 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
340 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
341 // -Z
342 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
343 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
344 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
345 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
346 // +Z
347 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
348 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
349 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
350 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
351 // -Y
352 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
353 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
354 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
355 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
356 // +Y
357 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
358 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
359 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
360 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
361 };
362 static uint16_t indices[] = {
363 0, 1, 2, 3, USHRT_MAX,
364 4, 5, 6, 7, USHRT_MAX,
365 8, 9, 10, 11, USHRT_MAX,
366 12, 13, 14, 15, USHRT_MAX,
367 16, 17, 18, 19, USHRT_MAX,
368 20, 21, 22, 23, USHRT_MAX,
369 };
370
371 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
372 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
373 g_IndexCount = (uint32_t)_countof(indices);
374
375 // Create vertex buffer
376
377 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
378 vbInfo.size = vertexBufferSize;
379 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
380 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200381
Adam Sawicki976f9202017-09-12 20:45:14 +0200382 VmaAllocationCreateInfo vbAllocCreateInfo = {};
383 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100384 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200385
Adam Sawicki819860e2017-07-04 14:30:38 +0200386 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
387 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
388 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200389 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200390
391 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200392
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200393 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
394
Adam Sawickie6e498f2017-06-16 17:21:31 +0200395 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200396 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
397 vbAllocCreateInfo.flags = 0;
398 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200399
400 // Create index buffer
401
402 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
403 ibInfo.size = indexBufferSize;
404 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
405 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200406
Adam Sawicki976f9202017-09-12 20:45:14 +0200407 VmaAllocationCreateInfo ibAllocCreateInfo = {};
408 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100409 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200410
Adam Sawickie6e498f2017-06-16 17:21:31 +0200411 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200412 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
413 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200414 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200415
Adam Sawicki819860e2017-07-04 14:30:38 +0200416 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200417
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200418 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
419
Adam Sawickie6e498f2017-06-16 17:21:31 +0200420 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200421 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
422 ibAllocCreateInfo.flags = 0;
423 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200424
425 // Copy buffers
426
427 BeginSingleTimeCommands();
428
429 VkBufferCopy vbCopyRegion = {};
430 vbCopyRegion.srcOffset = 0;
431 vbCopyRegion.dstOffset = 0;
432 vbCopyRegion.size = vbInfo.size;
433 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
434
435 VkBufferCopy ibCopyRegion = {};
436 ibCopyRegion.srcOffset = 0;
437 ibCopyRegion.dstOffset = 0;
438 ibCopyRegion.size = ibInfo.size;
439 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
440
441 EndSingleTimeCommands();
442
Adam Sawicki819860e2017-07-04 14:30:38 +0200443 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
444 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200445}
446
Adam Sawickie6e498f2017-06-16 17:21:31 +0200447static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
448{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100449 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200450
451 const VkDeviceSize imageSize = sizeX * sizeY * 4;
452
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100453 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
454 stagingBufInfo.size = imageSize;
455 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
456
457 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
458 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
459 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200460
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100461 VkBuffer stagingBuf = VK_NULL_HANDLE;
462 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
463 VmaAllocationInfo stagingBufAllocInfo = {};
464 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200465
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100466 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
467 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200468 for(uint32_t y = 0; y < sizeY; ++y)
469 {
470 uint32_t* pPixelData = (uint32_t*)pRowData;
471 for(uint32_t x = 0; x < sizeY; ++x)
472 {
473 *pPixelData =
474 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
475 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
476 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
477 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
478 ++pPixelData;
479 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100480 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200481 }
482
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200483 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
484
Adam Sawicki10844a82017-08-16 17:32:09 +0200485 // Create g_hTextureImage in GPU memory.
486
Adam Sawickie6e498f2017-06-16 17:21:31 +0200487 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
488 imageInfo.imageType = VK_IMAGE_TYPE_2D;
489 imageInfo.extent.width = sizeX;
490 imageInfo.extent.height = sizeY;
491 imageInfo.extent.depth = 1;
492 imageInfo.mipLevels = 1;
493 imageInfo.arrayLayers = 1;
494 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
495 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
496 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
497 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
498 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
499 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
500 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200501
Adam Sawicki976f9202017-09-12 20:45:14 +0200502 VmaAllocationCreateInfo imageAllocCreateInfo = {};
503 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200504
Adam Sawicki976f9202017-09-12 20:45:14 +0200505 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200506
Adam Sawicki10844a82017-08-16 17:32:09 +0200507 // Transition image layouts, copy image.
508
509 BeginSingleTimeCommands();
510
511 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200512 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
513 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200514 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
515 imgMemBarrier.subresourceRange.baseMipLevel = 0;
516 imgMemBarrier.subresourceRange.levelCount = 1;
517 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
518 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200519 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
520 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
521 imgMemBarrier.image = g_hTextureImage;
522 imgMemBarrier.srcAccessMask = 0;
523 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
524
525 vkCmdPipelineBarrier(
526 g_hTemporaryCommandBuffer,
527 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
528 VK_PIPELINE_STAGE_TRANSFER_BIT,
529 0,
530 0, nullptr,
531 0, nullptr,
532 1, &imgMemBarrier);
533
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100534 VkBufferImageCopy region = {};
535 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
536 region.imageSubresource.layerCount = 1;
537 region.imageExtent.width = sizeX;
538 region.imageExtent.height = sizeY;
539 region.imageExtent.depth = 1;
540
541 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200542
543 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
544 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
545 imgMemBarrier.image = g_hTextureImage;
546 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
547 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
548
549 vkCmdPipelineBarrier(
550 g_hTemporaryCommandBuffer,
551 VK_PIPELINE_STAGE_TRANSFER_BIT,
552 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
553 0,
554 0, nullptr,
555 0, nullptr,
556 1, &imgMemBarrier);
557
558 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200559
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100560 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200561
562 // Create ImageView
563
564 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
565 textureImageViewInfo.image = g_hTextureImage;
566 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
567 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
568 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
569 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
570 textureImageViewInfo.subresourceRange.levelCount = 1;
571 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
572 textureImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200573 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200574}
575
576struct UniformBufferObject
577{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200578 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200579};
580
581static void RegisterDebugCallbacks()
582{
583 g_pvkCreateDebugReportCallbackEXT =
584 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
585 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
586 g_pvkDebugReportMessageEXT =
587 reinterpret_cast<PFN_vkDebugReportMessageEXT>
588 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
589 g_pvkDestroyDebugReportCallbackEXT =
590 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
591 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
592 assert(g_pvkCreateDebugReportCallbackEXT);
593 assert(g_pvkDebugReportMessageEXT);
594 assert(g_pvkDestroyDebugReportCallbackEXT);
595
596 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
597 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
598 callbackCreateInfo.pNext = nullptr;
599 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
600 VK_DEBUG_REPORT_ERROR_BIT_EXT |
601 VK_DEBUG_REPORT_WARNING_BIT_EXT |
602 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
603 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
604 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
605 callbackCreateInfo.pUserData = nullptr;
606
Adam Sawicki1f84f622019-07-02 13:40:01 +0200607 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, g_Allocs, &g_hCallback) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200608}
609
610static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
611{
612 const VkLayerProperties* propsEnd = pProps + propCount;
613 return std::find_if(
614 pProps,
615 propsEnd,
616 [pLayerName](const VkLayerProperties& prop) -> bool {
617 return strcmp(pLayerName, prop.layerName) == 0;
618 }) != propsEnd;
619}
620
621static VkFormat FindSupportedFormat(
622 const std::vector<VkFormat>& candidates,
623 VkImageTiling tiling,
624 VkFormatFeatureFlags features)
625{
626 for (VkFormat format : candidates)
627 {
628 VkFormatProperties props;
629 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
630
631 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
632 ((props.linearTilingFeatures & features) == features))
633 {
634 return format;
635 }
636 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
637 ((props.optimalTilingFeatures & features) == features))
638 {
639 return format;
640 }
641 }
642 return VK_FORMAT_UNDEFINED;
643}
644
645static VkFormat FindDepthFormat()
646{
647 std::vector<VkFormat> formats;
648 formats.push_back(VK_FORMAT_D32_SFLOAT);
649 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
650 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
651
652 return FindSupportedFormat(
653 formats,
654 VK_IMAGE_TILING_OPTIMAL,
655 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
656}
657
658static void CreateSwapchain()
659{
660 // Query surface formats.
661
662 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
663
664 uint32_t formatCount = 0;
665 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
666 g_SurfaceFormats.resize(formatCount);
667 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
668
669 uint32_t presentModeCount = 0;
670 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
671 g_PresentModes.resize(presentModeCount);
672 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
673
674 // Create swap chain
675
676 g_SurfaceFormat = ChooseSurfaceFormat();
677 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
678 g_Extent = ChooseSwapExtent();
679
680 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
681 if((g_SurfaceCapabilities.maxImageCount > 0) &&
682 (imageCount > g_SurfaceCapabilities.maxImageCount))
683 {
684 imageCount = g_SurfaceCapabilities.maxImageCount;
685 }
686
687 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
688 swapChainInfo.surface = g_hSurface;
689 swapChainInfo.minImageCount = imageCount;
690 swapChainInfo.imageFormat = g_SurfaceFormat.format;
691 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
692 swapChainInfo.imageExtent = g_Extent;
693 swapChainInfo.imageArrayLayers = 1;
694 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
695 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
696 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
697 swapChainInfo.presentMode = presentMode;
698 swapChainInfo.clipped = VK_TRUE;
699 swapChainInfo.oldSwapchain = g_hSwapchain;
700
701 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
702 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
703 {
704 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
705 swapChainInfo.queueFamilyIndexCount = 2;
706 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
707 }
708 else
709 {
710 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
711 }
712
713 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200714 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, g_Allocs, &hNewSwapchain) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200715 if(g_hSwapchain != VK_NULL_HANDLE)
Adam Sawicki1f84f622019-07-02 13:40:01 +0200716 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200717 g_hSwapchain = hNewSwapchain;
718
719 // Retrieve swapchain images.
720
721 uint32_t swapchainImageCount = 0;
722 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
723 g_SwapchainImages.resize(swapchainImageCount);
724 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
725
726 // Create swapchain image views.
727
728 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +0200729 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200730 g_SwapchainImageViews.clear();
731
732 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
733 g_SwapchainImageViews.resize(swapchainImageCount);
734 for(uint32_t i = 0; i < swapchainImageCount; ++i)
735 {
736 swapchainImageViewInfo.image = g_SwapchainImages[i];
737 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
738 swapchainImageViewInfo.format = g_SurfaceFormat.format;
739 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
740 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
741 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
742 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
743 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
744 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
745 swapchainImageViewInfo.subresourceRange.levelCount = 1;
746 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
747 swapchainImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200748 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200749 }
750
751 // Create depth buffer
752
753 g_DepthFormat = FindDepthFormat();
754 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
755
756 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
757 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
758 depthImageInfo.extent.width = g_Extent.width;
759 depthImageInfo.extent.height = g_Extent.height;
760 depthImageInfo.extent.depth = 1;
761 depthImageInfo.mipLevels = 1;
762 depthImageInfo.arrayLayers = 1;
763 depthImageInfo.format = g_DepthFormat;
764 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
765 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
766 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
767 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
768 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
769 depthImageInfo.flags = 0;
770
Adam Sawicki976f9202017-09-12 20:45:14 +0200771 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
772 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200773
Adam Sawicki976f9202017-09-12 20:45:14 +0200774 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200775
776 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
777 depthImageViewInfo.image = g_hDepthImage;
778 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
779 depthImageViewInfo.format = g_DepthFormat;
780 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
781 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
782 depthImageViewInfo.subresourceRange.levelCount = 1;
783 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
784 depthImageViewInfo.subresourceRange.layerCount = 1;
785
Adam Sawicki1f84f622019-07-02 13:40:01 +0200786 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200787
Adam Sawickie6e498f2017-06-16 17:21:31 +0200788 // Create pipeline layout
789 {
790 if(g_hPipelineLayout != VK_NULL_HANDLE)
791 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200792 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200793 g_hPipelineLayout = VK_NULL_HANDLE;
794 }
795
796 VkPushConstantRange pushConstantRanges[1];
797 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
798 pushConstantRanges[0].offset = 0;
799 pushConstantRanges[0].size = sizeof(UniformBufferObject);
800 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
801
802 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
803 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
804 pipelineLayoutInfo.setLayoutCount = 1;
805 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
806 pipelineLayoutInfo.pushConstantRangeCount = 1;
807 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200808 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200809 }
810
811 // Create render pass
812 {
813 if(g_hRenderPass != VK_NULL_HANDLE)
814 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200815 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200816 g_hRenderPass = VK_NULL_HANDLE;
817 }
818
819 VkAttachmentDescription attachments[2];
820 ZeroMemory(attachments, sizeof(attachments));
821
822 attachments[0].format = g_SurfaceFormat.format;
823 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
824 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
825 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
826 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
827 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100828 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200829 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
830
831 attachments[1].format = g_DepthFormat;
832 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
833 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
834 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
835 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
836 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100837 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200838 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
839
840 VkAttachmentReference colorAttachmentRef = {};
841 colorAttachmentRef.attachment = 0;
842 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
843
844 VkAttachmentReference depthStencilAttachmentRef = {};
845 depthStencilAttachmentRef.attachment = 1;
846 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
847
848 VkSubpassDescription subpassDesc = {};
849 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
850 subpassDesc.colorAttachmentCount = 1;
851 subpassDesc.pColorAttachments = &colorAttachmentRef;
852 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
853
Adam Sawickie6e498f2017-06-16 17:21:31 +0200854 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
855 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
856 renderPassInfo.pAttachments = attachments;
857 renderPassInfo.subpassCount = 1;
858 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200859 renderPassInfo.dependencyCount = 0;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200860 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200861 }
862
863 // Create pipeline
864 {
865 std::vector<char> vertShaderCode;
866 LoadShader(vertShaderCode, "Shader.vert.spv");
867 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
868 shaderModuleInfo.codeSize = vertShaderCode.size();
869 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
870 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200871 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200872
873 std::vector<char> hFragShaderCode;
874 LoadShader(hFragShaderCode, "Shader.frag.spv");
875 shaderModuleInfo.codeSize = hFragShaderCode.size();
876 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
877 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200878 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200879
880 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
881 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
882 vertPipelineShaderStageInfo.module = hVertShaderModule;
883 vertPipelineShaderStageInfo.pName = "main";
884
885 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
886 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
887 fragPipelineShaderStageInfo.module = fragShaderModule;
888 fragPipelineShaderStageInfo.pName = "main";
889
890 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
891 vertPipelineShaderStageInfo,
892 fragPipelineShaderStageInfo
893 };
894
895 VkVertexInputBindingDescription bindingDescription = {};
896 bindingDescription.binding = 0;
897 bindingDescription.stride = sizeof(Vertex);
898 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
899
900 VkVertexInputAttributeDescription attributeDescriptions[3];
901 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
902
903 attributeDescriptions[0].binding = 0;
904 attributeDescriptions[0].location = 0;
905 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
906 attributeDescriptions[0].offset = offsetof(Vertex, pos);
907
908 attributeDescriptions[1].binding = 0;
909 attributeDescriptions[1].location = 1;
910 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
911 attributeDescriptions[1].offset = offsetof(Vertex, color);
912
913 attributeDescriptions[2].binding = 0;
914 attributeDescriptions[2].location = 2;
915 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
916 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
917
918 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
919 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
920 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
921 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
922 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
923
924 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
925 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
926 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
927
928 VkViewport viewport = {};
929 viewport.x = 0.f;
930 viewport.y = 0.f;
931 viewport.width = (float)g_Extent.width;
932 viewport.height = (float)g_Extent.height;
933 viewport.minDepth = 0.f;
934 viewport.maxDepth = 1.f;
935
936 VkRect2D scissor = {};
937 scissor.offset.x = 0;
938 scissor.offset.y = 0;
939 scissor.extent = g_Extent;
940
941 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
942 pipelineViewportStateInfo.viewportCount = 1;
943 pipelineViewportStateInfo.pViewports = &viewport;
944 pipelineViewportStateInfo.scissorCount = 1;
945 pipelineViewportStateInfo.pScissors = &scissor;
946
947 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
948 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
949 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
950 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
951 pipelineRasterizationStateInfo.lineWidth = 1.f;
952 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
953 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
954 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
955 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
956 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
957 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
958
959 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
960 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
961 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
962 pipelineMultisampleStateInfo.minSampleShading = 1.f;
963 pipelineMultisampleStateInfo.pSampleMask = nullptr;
964 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
965 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
966
967 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
968 pipelineColorBlendAttachmentState.colorWriteMask =
969 VK_COLOR_COMPONENT_R_BIT |
970 VK_COLOR_COMPONENT_G_BIT |
971 VK_COLOR_COMPONENT_B_BIT |
972 VK_COLOR_COMPONENT_A_BIT;
973 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
974 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
975 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
976 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
977 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
978 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
979 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
980
981 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
982 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
983 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
984 pipelineColorBlendStateInfo.attachmentCount = 1;
985 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
986
987 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
988 depthStencilStateInfo.depthTestEnable = VK_TRUE;
989 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
990 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
991 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
992 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
993
994 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
995 pipelineInfo.stageCount = 2;
996 pipelineInfo.pStages = pipelineShaderStageInfos;
997 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
998 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
999 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
1000 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
1001 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
1002 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
1003 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
1004 pipelineInfo.pDynamicState = nullptr;
1005 pipelineInfo.layout = g_hPipelineLayout;
1006 pipelineInfo.renderPass = g_hRenderPass;
1007 pipelineInfo.subpass = 0;
1008 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
1009 pipelineInfo.basePipelineIndex = -1;
1010 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
1011 g_hDevice,
1012 VK_NULL_HANDLE,
1013 1,
Adam Sawicki1f84f622019-07-02 13:40:01 +02001014 &pipelineInfo,
1015 g_Allocs,
Adam Sawickie6e498f2017-06-16 17:21:31 +02001016 &g_hPipeline) );
1017
Adam Sawicki1f84f622019-07-02 13:40:01 +02001018 vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
1019 vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001020 }
1021
1022 // Create frambuffers
1023
1024 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001025 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001026 g_Framebuffers.clear();
1027
1028 g_Framebuffers.resize(g_SwapchainImageViews.size());
1029 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1030 {
1031 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1032
1033 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1034 framebufferInfo.renderPass = g_hRenderPass;
1035 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1036 framebufferInfo.pAttachments = attachments;
1037 framebufferInfo.width = g_Extent.width;
1038 framebufferInfo.height = g_Extent.height;
1039 framebufferInfo.layers = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001040 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001041 }
1042
1043 // Create semaphores
1044
1045 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1046 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001047 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001048 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1049 }
1050 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1051 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001052 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001053 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1054 }
1055
1056 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
Adam Sawicki1f84f622019-07-02 13:40:01 +02001057 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
1058 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001059}
1060
1061static void DestroySwapchain(bool destroyActualSwapchain)
1062{
1063 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1064 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001065 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001066 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1067 }
1068 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1069 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001070 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001071 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1072 }
1073
1074 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001075 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001076 g_Framebuffers.clear();
1077
1078 if(g_hDepthImageView != VK_NULL_HANDLE)
1079 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001080 vkDestroyImageView(g_hDevice, g_hDepthImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001081 g_hDepthImageView = VK_NULL_HANDLE;
1082 }
1083 if(g_hDepthImage != VK_NULL_HANDLE)
1084 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001085 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001086 g_hDepthImage = VK_NULL_HANDLE;
1087 }
1088
1089 if(g_hPipeline != VK_NULL_HANDLE)
1090 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001091 vkDestroyPipeline(g_hDevice, g_hPipeline, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001092 g_hPipeline = VK_NULL_HANDLE;
1093 }
1094
1095 if(g_hRenderPass != VK_NULL_HANDLE)
1096 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001097 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001098 g_hRenderPass = VK_NULL_HANDLE;
1099 }
1100
1101 if(g_hPipelineLayout != VK_NULL_HANDLE)
1102 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001103 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001104 g_hPipelineLayout = VK_NULL_HANDLE;
1105 }
1106
1107 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001108 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001109 g_SwapchainImageViews.clear();
1110
1111 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1112 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001113 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001114 g_hSwapchain = VK_NULL_HANDLE;
1115 }
1116}
1117
1118static void InitializeApplication()
1119{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001120 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1121 {
1122 g_Allocs = &g_CpuAllocationCallbacks;
1123 }
1124
Adam Sawickie6e498f2017-06-16 17:21:31 +02001125 uint32_t instanceLayerPropCount = 0;
1126 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1127 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1128 if(instanceLayerPropCount > 0)
1129 {
1130 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1131 }
1132
1133 if(g_EnableValidationLayer == true)
1134 {
1135 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1136 {
1137 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1138 g_EnableValidationLayer = false;
1139 }
1140 }
1141
Adam Sawicki353e3672019-11-02 14:12:05 +01001142 uint32_t availableInstanceExtensionCount = 0;
1143 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
1144 std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
1145 if(availableInstanceExtensionCount > 0)
1146 {
1147 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
1148 }
1149
1150 std::vector<const char*> enabledInstanceExtensions;
1151 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1152 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001153
1154 std::vector<const char*> instanceLayers;
1155 if(g_EnableValidationLayer == true)
1156 {
1157 instanceLayers.push_back(VALIDATION_LAYER_NAME);
Adam Sawicki353e3672019-11-02 14:12:05 +01001158 enabledInstanceExtensions.push_back("VK_EXT_debug_report");
1159 }
1160
1161 for(const auto& extensionProperties : availableInstanceExtensions)
1162 {
1163 if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
1164 {
1165 enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1166 VK_KHR_get_physical_device_properties2_enabled = true;
1167 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001168 }
1169
1170 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1171 appInfo.pApplicationName = APP_TITLE_A;
1172 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1173 appInfo.pEngineName = "Adam Sawicki Engine";
1174 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
Adam Sawicki10f68cb2019-11-22 17:41:59 +01001175 appInfo.apiVersion = VMA_VULKAN_VERSION == 1001000 ? VK_API_VERSION_1_1 : VK_API_VERSION_1_0;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001176
1177 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1178 instInfo.pApplicationInfo = &appInfo;
Adam Sawicki353e3672019-11-02 14:12:05 +01001179 instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
1180 instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001181 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1182 instInfo.ppEnabledLayerNames = instanceLayers.data();
1183
Adam Sawicki1f84f622019-07-02 13:40:01 +02001184 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001185
1186 // Create VkSurfaceKHR.
1187 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1188 surfaceInfo.hinstance = g_hAppInstance;
1189 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001190 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001191 assert(result == VK_SUCCESS);
1192
1193 if(g_EnableValidationLayer == true)
1194 RegisterDebugCallbacks();
1195
1196 // Find physical device
1197
1198 uint32_t deviceCount = 0;
1199 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1200 assert(deviceCount > 0);
1201
1202 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1203 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1204
1205 g_hPhysicalDevice = physicalDevices[0];
1206
1207 // Query for features
1208
1209 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1210 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1211
Adam Sawicki51fa9662018-10-03 13:44:29 +02001212 VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
1213 vkGetPhysicalDeviceFeatures(g_hPhysicalDevice, &physicalDeviceFeatures);
1214
1215 g_SparseBindingEnabled = physicalDeviceFeatures.sparseBinding != 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001216
1217 // Find queue family index
1218
1219 uint32_t queueFamilyCount = 0;
1220 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1221 assert(queueFamilyCount > 0);
1222 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1223 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1224 for(uint32_t i = 0;
1225 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001226 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1227 g_PresentQueueFamilyIndex == UINT_MAX ||
1228 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001229 ++i)
1230 {
1231 if(queueFamilies[i].queueCount > 0)
1232 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001233 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001234 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001235 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001236 {
1237 g_GraphicsQueueFamilyIndex = i;
1238 }
1239
1240 VkBool32 surfaceSupported = 0;
1241 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1242 if((res >= 0) && (surfaceSupported == VK_TRUE))
1243 {
1244 g_PresentQueueFamilyIndex = i;
1245 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001246
1247 if(g_SparseBindingEnabled &&
1248 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1249 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1250 {
1251 g_SparseBindingQueueFamilyIndex = i;
1252 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001253 }
1254 }
1255 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1256
Adam Sawicki51fa9662018-10-03 13:44:29 +02001257 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1258
Adam Sawickie6e498f2017-06-16 17:21:31 +02001259 // Create logical device
1260
1261 const float queuePriority = 1.f;
1262
Adam Sawicki51fa9662018-10-03 13:44:29 +02001263 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1264 uint32_t queueCount = 1;
1265 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1266 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1267 queueCreateInfo[0].queueCount = 1;
1268 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1269
1270 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1271 {
1272
1273 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1274 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1275 queueCreateInfo[queueCount].queueCount = 1;
1276 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1277 ++queueCount;
1278 }
1279
1280 if(g_SparseBindingEnabled &&
1281 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1282 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1283 {
1284
1285 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1286 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1287 queueCreateInfo[queueCount].queueCount = 1;
1288 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1289 ++queueCount;
1290 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001291
1292 VkPhysicalDeviceFeatures deviceFeatures = {};
Adam Sawicki51fa9662018-10-03 13:44:29 +02001293 //deviceFeatures.fillModeNonSolid = VK_TRUE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001294 deviceFeatures.samplerAnisotropy = VK_TRUE;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001295 deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001296
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001297 // Determine list of device extensions to enable.
Adam Sawickie6e498f2017-06-16 17:21:31 +02001298 std::vector<const char*> enabledDeviceExtensions;
1299 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001300 {
1301 uint32_t propertyCount = 0;
1302 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, nullptr) );
1303
1304 if(propertyCount)
1305 {
1306 std::vector<VkExtensionProperties> properties{propertyCount};
1307 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, properties.data()) );
1308
1309 for(uint32_t i = 0; i < propertyCount; ++i)
1310 {
1311 if(strcmp(properties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1312 {
1313 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1314 VK_KHR_get_memory_requirements2_enabled = true;
1315 }
1316 else if(strcmp(properties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1317 {
1318 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1319 VK_KHR_dedicated_allocation_enabled = true;
1320 }
Adam Sawicki4abe30c2019-07-02 14:37:21 +02001321 else if(strcmp(properties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
1322 {
1323 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1324 VK_KHR_bind_memory2_enabled = true;
1325 }
Adam Sawicki353e3672019-11-02 14:12:05 +01001326 else if(strcmp(properties[i].extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
1327 {
1328 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
1329 VK_EXT_memory_budget_enabled = true;
1330 }
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001331 }
1332 }
1333 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001334
1335 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1336 deviceCreateInfo.enabledLayerCount = 0;
1337 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1338 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001339 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001340 deviceCreateInfo.queueCreateInfoCount = queueCount;
1341 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001342 deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
1343
Adam Sawicki1f84f622019-07-02 13:40:01 +02001344 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001345
1346 // Create memory allocator
1347
1348 VmaAllocatorCreateInfo allocatorInfo = {};
1349 allocatorInfo.physicalDevice = g_hPhysicalDevice;
1350 allocatorInfo.device = g_hDevice;
Adam Sawicki353e3672019-11-02 14:12:05 +01001351 allocatorInfo.instance = g_hVulkanInstance;
Adam Sawicki10f68cb2019-11-22 17:41:59 +01001352 allocatorInfo.vulkanApiVersion = appInfo.apiVersion;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001353
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001354 if(VK_KHR_dedicated_allocation_enabled)
1355 {
1356 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1357 }
Adam Sawicki4abe30c2019-07-02 14:37:21 +02001358 if(VK_KHR_bind_memory2_enabled)
1359 {
1360 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
1361 }
Adam Sawicki4ac8ff82019-11-18 14:47:33 +01001362#if !defined(VMA_MEMORY_BUDGET) || VMA_MEMORY_BUDGET == 1
Adam Sawicki353e3672019-11-02 14:12:05 +01001363 if(VK_EXT_memory_budget_enabled && VK_KHR_get_physical_device_properties2_enabled)
1364 {
1365 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
1366 }
Adam Sawicki4ac8ff82019-11-18 14:47:33 +01001367#endif
Adam Sawickia68c01c2018-03-13 16:40:45 +01001368
Adam Sawickia68c01c2018-03-13 16:40:45 +01001369 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1370 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001371 allocatorInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001372 }
1373
Adam Sawickib0c36362018-11-13 16:17:38 +01001374 // Uncomment to enable recording to CSV file.
1375 /*
1376 {
1377 VmaRecordSettings recordSettings = {};
1378 recordSettings.pFilePath = "VulkanSample.csv";
1379 allocatorInfo.pRecordSettings = &recordSettings;
1380 }
1381 */
1382
Adam Sawicki5f573f52019-10-11 15:59:58 +02001383 // Uncomment to enable HeapSizeLimit.
1384 /*
1385 std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapSizeLimit;
1386 std::fill(heapSizeLimit.begin(), heapSizeLimit.end(), VK_WHOLE_SIZE);
Adam Sawicki353e3672019-11-02 14:12:05 +01001387 heapSizeLimit[0] = 512ull * 1024 * 1024;
Adam Sawicki5f573f52019-10-11 15:59:58 +02001388 allocatorInfo.pHeapSizeLimit = heapSizeLimit.data();
1389 */
1390
Adam Sawickie6e498f2017-06-16 17:21:31 +02001391 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1392
Adam Sawicki51fa9662018-10-03 13:44:29 +02001393 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001394
1395 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1396 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1397 assert(g_hGraphicsQueue);
1398 assert(g_hPresentQueue);
1399
Adam Sawicki51fa9662018-10-03 13:44:29 +02001400 if(g_SparseBindingEnabled)
1401 {
1402 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1403 assert(g_hSparseBindingQueue);
1404 }
1405
Adam Sawickie6e498f2017-06-16 17:21:31 +02001406 // Create command pool
1407
1408 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1409 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1410 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001411 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001412
1413 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1414 commandBufferInfo.commandPool = g_hCommandPool;
1415 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1416 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1417 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1418
1419 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1420 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1421 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1422 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001423 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001424 }
1425
Adam Sawicki1f84f622019-07-02 13:40:01 +02001426 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001427
Adam Sawickie6e498f2017-06-16 17:21:31 +02001428 commandBufferInfo.commandBufferCount = 1;
1429 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1430
1431 // Create texture sampler
1432
1433 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1434 samplerInfo.magFilter = VK_FILTER_LINEAR;
1435 samplerInfo.minFilter = VK_FILTER_LINEAR;
1436 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1437 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1438 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1439 samplerInfo.anisotropyEnable = VK_TRUE;
1440 samplerInfo.maxAnisotropy = 16;
1441 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1442 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1443 samplerInfo.compareEnable = VK_FALSE;
1444 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1445 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1446 samplerInfo.mipLodBias = 0.f;
1447 samplerInfo.minLod = 0.f;
1448 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001449 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001450
1451 CreateTexture(128, 128);
1452 CreateMesh();
1453
1454 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1455 samplerLayoutBinding.binding = 1;
1456 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1457 samplerLayoutBinding.descriptorCount = 1;
1458 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1459
1460 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1461 descriptorSetLayoutInfo.bindingCount = 1;
1462 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001463 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001464
1465 // Create descriptor pool
1466
1467 VkDescriptorPoolSize descriptorPoolSizes[2];
1468 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1469 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1470 descriptorPoolSizes[0].descriptorCount = 1;
1471 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1472 descriptorPoolSizes[1].descriptorCount = 1;
1473
1474 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1475 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1476 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1477 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001478 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001479
1480 // Create descriptor set layout
1481
1482 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1483 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1484 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1485 descriptorSetInfo.descriptorSetCount = 1;
1486 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1487 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1488
1489 VkDescriptorImageInfo descriptorImageInfo = {};
1490 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1491 descriptorImageInfo.imageView = g_hTextureImageView;
1492 descriptorImageInfo.sampler = g_hSampler;
1493
1494 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1495 writeDescriptorSet.dstSet = g_hDescriptorSet;
1496 writeDescriptorSet.dstBinding = 1;
1497 writeDescriptorSet.dstArrayElement = 0;
1498 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1499 writeDescriptorSet.descriptorCount = 1;
1500 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1501
1502 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1503
1504 CreateSwapchain();
1505}
1506
1507static void FinalizeApplication()
1508{
1509 vkDeviceWaitIdle(g_hDevice);
1510
1511 DestroySwapchain(true);
1512
1513 if(g_hDescriptorPool != VK_NULL_HANDLE)
1514 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001515 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001516 g_hDescriptorPool = VK_NULL_HANDLE;
1517 }
1518
1519 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1520 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001521 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001522 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1523 }
1524
1525 if(g_hTextureImageView != VK_NULL_HANDLE)
1526 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001527 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001528 g_hTextureImageView = VK_NULL_HANDLE;
1529 }
1530 if(g_hTextureImage != VK_NULL_HANDLE)
1531 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001532 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001533 g_hTextureImage = VK_NULL_HANDLE;
1534 }
1535
1536 if(g_hIndexBuffer != VK_NULL_HANDLE)
1537 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001538 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001539 g_hIndexBuffer = VK_NULL_HANDLE;
1540 }
1541 if(g_hVertexBuffer != VK_NULL_HANDLE)
1542 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001543 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001544 g_hVertexBuffer = VK_NULL_HANDLE;
1545 }
1546
1547 if(g_hSampler != VK_NULL_HANDLE)
1548 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001549 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001550 g_hSampler = VK_NULL_HANDLE;
1551 }
1552
Adam Sawicki51fa9662018-10-03 13:44:29 +02001553 if(g_ImmediateFence)
1554 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001555 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001556 g_ImmediateFence = VK_NULL_HANDLE;
1557 }
1558
Adam Sawickie6e498f2017-06-16 17:21:31 +02001559 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1560 {
1561 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1562 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001563 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001564 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1565 }
1566 }
1567 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1568 {
1569 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1570 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1571 }
1572 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1573 {
1574 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1575 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1576 }
1577
1578 if(g_hCommandPool != VK_NULL_HANDLE)
1579 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001580 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001581 g_hCommandPool = VK_NULL_HANDLE;
1582 }
1583
1584 if(g_hAllocator != VK_NULL_HANDLE)
1585 {
1586 vmaDestroyAllocator(g_hAllocator);
1587 g_hAllocator = nullptr;
1588 }
1589
1590 if(g_hDevice != VK_NULL_HANDLE)
1591 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001592 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001593 g_hDevice = nullptr;
1594 }
1595
1596 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1597 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001598 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001599 g_hCallback = VK_NULL_HANDLE;
1600 }
1601
1602 if(g_hSurface != VK_NULL_HANDLE)
1603 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001604 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001605 g_hSurface = VK_NULL_HANDLE;
1606 }
1607
1608 if(g_hVulkanInstance != VK_NULL_HANDLE)
1609 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001610 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001611 g_hVulkanInstance = VK_NULL_HANDLE;
1612 }
1613}
1614
1615static void PrintAllocatorStats()
1616{
1617#if VMA_STATS_STRING_ENABLED
1618 char* statsString = nullptr;
1619 vmaBuildStatsString(g_hAllocator, &statsString, true);
1620 printf("%s\n", statsString);
1621 vmaFreeStatsString(g_hAllocator, statsString);
1622#endif
1623}
1624
1625static void RecreateSwapChain()
1626{
1627 vkDeviceWaitIdle(g_hDevice);
1628 DestroySwapchain(false);
1629 CreateSwapchain();
1630}
1631
1632static void DrawFrame()
1633{
1634 // Begin main command buffer
1635 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1636 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1637 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1638
1639 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1640 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1641
1642 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1643 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1644 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1645
1646 // Acquire swapchain image
1647 uint32_t imageIndex = 0;
1648 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1649 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1650 {
1651 RecreateSwapChain();
1652 return;
1653 }
1654 else if(res < 0)
1655 {
1656 ERR_GUARD_VULKAN(res);
1657 }
1658
1659 // Record geometry pass
1660
1661 VkClearValue clearValues[2];
1662 ZeroMemory(clearValues, sizeof(clearValues));
1663 clearValues[0].color.float32[0] = 0.25f;
1664 clearValues[0].color.float32[1] = 0.25f;
1665 clearValues[0].color.float32[2] = 0.5f;
1666 clearValues[0].color.float32[3] = 1.0f;
1667 clearValues[1].depthStencil.depth = 1.0f;
1668
1669 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1670 renderPassBeginInfo.renderPass = g_hRenderPass;
1671 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1672 renderPassBeginInfo.renderArea.offset.x = 0;
1673 renderPassBeginInfo.renderArea.offset.y = 0;
1674 renderPassBeginInfo.renderArea.extent = g_Extent;
1675 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1676 renderPassBeginInfo.pClearValues = clearValues;
1677 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1678
1679 vkCmdBindPipeline(
1680 hCommandBuffer,
1681 VK_PIPELINE_BIND_POINT_GRAPHICS,
1682 g_hPipeline);
1683
Adam Sawicki82c3f332018-06-11 15:27:33 +02001684 mat4 view = mat4::LookAt(
1685 vec3(0.f, 0.f, 0.f),
1686 vec3(0.f, -2.f, 4.f),
1687 vec3(0.f, 1.f, 0.f));
1688 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001689 1.0471975511966f, // 60 degrees
1690 (float)g_Extent.width / (float)g_Extent.height,
1691 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001692 1000.f);
1693 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001694
1695 vkCmdBindDescriptorSets(
1696 hCommandBuffer,
1697 VK_PIPELINE_BIND_POINT_GRAPHICS,
1698 g_hPipelineLayout,
1699 0,
1700 1,
1701 &g_hDescriptorSet,
1702 0,
1703 nullptr);
1704
Adam Sawicki82c3f332018-06-11 15:27:33 +02001705 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1706 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001707
1708 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001709 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001710 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1711
1712 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1713 VkDeviceSize offsets[] = { 0 };
1714 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1715
1716 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1717
1718 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1719
1720 vkCmdEndRenderPass(hCommandBuffer);
1721
1722 vkEndCommandBuffer(hCommandBuffer);
1723
1724 // Submit command buffer
1725
1726 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1727 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1728 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1729 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1730 submitInfo.waitSemaphoreCount = 1;
1731 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1732 submitInfo.pWaitDstStageMask = submitWaitStages;
1733 submitInfo.commandBufferCount = 1;
1734 submitInfo.pCommandBuffers = &hCommandBuffer;
1735 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1736 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1737 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1738
1739 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1740
1741 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1742 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1743 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1744 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1745 presentInfo.swapchainCount = 1;
1746 presentInfo.pSwapchains = swapchains;
1747 presentInfo.pImageIndices = &imageIndex;
1748 presentInfo.pResults = nullptr;
1749 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1750 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1751 {
1752 RecreateSwapChain();
1753 }
1754 else
1755 ERR_GUARD_VULKAN(res);
1756}
1757
1758static void HandlePossibleSizeChange()
1759{
1760 RECT clientRect;
1761 GetClientRect(g_hWnd, &clientRect);
1762 LONG newSizeX = clientRect.right - clientRect.left;
1763 LONG newSizeY = clientRect.bottom - clientRect.top;
1764 if((newSizeX > 0) &&
1765 (newSizeY > 0) &&
1766 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1767 {
1768 g_SizeX = newSizeX;
1769 g_SizeY = newSizeY;
1770
1771 RecreateSwapChain();
1772 }
1773}
1774
1775static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1776{
1777 switch(msg)
1778 {
1779 case WM_CREATE:
1780 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1781 g_hWnd = hWnd;
1782 InitializeApplication();
1783 PrintAllocatorStats();
1784 return 0;
1785
1786 case WM_DESTROY:
1787 FinalizeApplication();
1788 PostQuitMessage(0);
1789 return 0;
1790
1791 // This prevents app from freezing when left Alt is pressed
1792 // (which normally enters modal menu loop).
1793 case WM_SYSKEYDOWN:
1794 case WM_SYSKEYUP:
1795 return 0;
1796
1797 case WM_SIZE:
1798 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1799 HandlePossibleSizeChange();
1800 return 0;
1801
1802 case WM_EXITSIZEMOVE:
1803 HandlePossibleSizeChange();
1804 return 0;
1805
1806 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001807 switch(wParam)
1808 {
1809 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001810 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001811 break;
1812 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001813 try
1814 {
1815 Test();
1816 }
1817 catch(const std::exception& ex)
1818 {
1819 printf("ERROR: %s\n", ex.what());
1820 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001821 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001822 case 'S':
1823 try
1824 {
1825 if(g_SparseBindingEnabled)
1826 {
1827 TestSparseBinding();
1828 }
1829 else
1830 {
1831 printf("Sparse binding not supported.\n");
1832 }
1833 }
1834 catch(const std::exception& ex)
1835 {
1836 printf("ERROR: %s\n", ex.what());
1837 }
1838 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001839 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001840 return 0;
1841
1842 default:
1843 break;
1844 }
1845
1846 return DefWindowProc(hWnd, msg, wParam, lParam);
1847}
1848
1849int main()
1850{
1851 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1852
1853 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1854 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1855 wndClassDesc.hbrBackground = NULL;
1856 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1857 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1858 wndClassDesc.hInstance = g_hAppInstance;
1859 wndClassDesc.lpfnWndProc = WndProc;
1860 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1861
1862 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1863 assert(hWndClass);
1864
1865 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1866 const DWORD exStyle = 0;
1867
1868 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1869 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1870
Adam Sawicki86ccd632017-07-04 14:57:53 +02001871 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001872 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1873 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1874 NULL, NULL, g_hAppInstance, NULL);
1875
1876 MSG msg;
1877 for(;;)
1878 {
1879 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1880 {
1881 if(msg.message == WM_QUIT)
1882 break;
1883 TranslateMessage(&msg);
1884 DispatchMessage(&msg);
1885 }
1886 if(g_hDevice != VK_NULL_HANDLE)
1887 DrawFrame();
1888 }
1889
Adam Sawicki8317ba92019-11-18 13:14:11 +01001890 TEST(g_CpuAllocCount.load() == 0);
1891
Adam Sawickie6e498f2017-06-16 17:21:31 +02001892 return 0;
1893}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001894
Adam Sawickif1a793c2018-03-13 15:42:22 +01001895#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001896
Adam Sawickif1a793c2018-03-13 15:42:22 +01001897#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001898
1899int main()
1900{
1901}
1902
Adam Sawickif1a793c2018-03-13 15:42:22 +01001903#endif // #ifdef _WIN32