blob: dc9e76cdafe8b44668c9866490f5156ef2ab86b1 [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 Sawickie6e498f2017-06-16 17:21:31 +020029
30static const char* const SHADER_PATH1 = "./";
31static const char* const SHADER_PATH2 = "../bin/";
32static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
33static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_LUNARG_standard_validation";
Adam Sawicki6c8b7a22019-03-05 13:40:29 +010034static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.3.0-development";
35static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.3.0-development";
Adam Sawickie6e498f2017-06-16 17:21:31 +020036
37static const bool VSYNC = true;
38static const uint32_t COMMAND_BUFFER_COUNT = 2;
Adam Sawickia68c01c2018-03-13 16:40:45 +010039static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
40static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +020041
Adam Sawickib8333fb2018-03-13 16:15:53 +010042VkPhysicalDevice g_hPhysicalDevice;
43VkDevice g_hDevice;
44VmaAllocator g_hAllocator;
45bool g_MemoryAliasingWarningEnabled = true;
46
Adam Sawickia68c01c2018-03-13 16:40:45 +010047static bool g_EnableValidationLayer = true;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010048static bool VK_KHR_get_memory_requirements2_enabled = false;
49static bool VK_KHR_dedicated_allocation_enabled = false;
Adam Sawicki4abe30c2019-07-02 14:37:21 +020050static bool VK_KHR_bind_memory2_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020051bool g_SparseBindingEnabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010052
Adam Sawickie6e498f2017-06-16 17:21:31 +020053static HINSTANCE g_hAppInstance;
54static HWND g_hWnd;
55static LONG g_SizeX = 1280, g_SizeY = 720;
56static VkInstance g_hVulkanInstance;
57static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020058static VkQueue g_hPresentQueue;
59static VkSurfaceFormatKHR g_SurfaceFormat;
60static VkExtent2D g_Extent;
61static VkSwapchainKHR g_hSwapchain;
62static std::vector<VkImage> g_SwapchainImages;
63static std::vector<VkImageView> g_SwapchainImageViews;
64static std::vector<VkFramebuffer> g_Framebuffers;
65static VkCommandPool g_hCommandPool;
66static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
67static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020068VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020069static uint32_t g_NextCommandBufferIndex;
70static VkSemaphore g_hImageAvailableSemaphore;
71static VkSemaphore g_hRenderFinishedSemaphore;
72static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
73static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020074static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020075static VkDescriptorSetLayout g_hDescriptorSetLayout;
76static VkDescriptorPool g_hDescriptorPool;
77static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
78static VkSampler g_hSampler;
79static VkFormat g_DepthFormat;
80static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +020081static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +020082static VkImageView g_hDepthImageView;
83
84static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
85static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
86static std::vector<VkPresentModeKHR> g_PresentModes;
87
88static PFN_vkCreateDebugReportCallbackEXT g_pvkCreateDebugReportCallbackEXT;
89static PFN_vkDebugReportMessageEXT g_pvkDebugReportMessageEXT;
90static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
91static VkDebugReportCallbackEXT g_hCallback;
92
Adam Sawickie6e498f2017-06-16 17:21:31 +020093static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +020094VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +010095VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +020096
97static VkPipelineLayout g_hPipelineLayout;
98static VkRenderPass g_hRenderPass;
99static VkPipeline g_hPipeline;
100
101static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200102static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200103static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200104static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200105static uint32_t g_VertexCount;
106static uint32_t g_IndexCount;
107
108static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200109static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200110static VkImageView g_hTextureImageView;
111
Adam Sawickia68c01c2018-03-13 16:40:45 +0100112static void* CustomCpuAllocation(
113 void* pUserData, size_t size, size_t alignment,
114 VkSystemAllocationScope allocationScope)
115{
116 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
117 return _aligned_malloc(size, alignment);
118}
119
120static void* CustomCpuReallocation(
121 void* pUserData, void* pOriginal, size_t size, size_t alignment,
122 VkSystemAllocationScope allocationScope)
123{
124 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
125 return _aligned_realloc(pOriginal, size, alignment);
126}
127
128static void CustomCpuFree(void* pUserData, void* pMemory)
129{
130 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
131 _aligned_free(pMemory);
132}
133
Adam Sawicki1f84f622019-07-02 13:40:01 +0200134static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
135 CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA, // pUserData
136 &CustomCpuAllocation, // pfnAllocation
137 &CustomCpuReallocation, // pfnReallocation
138 &CustomCpuFree // pfnFree
139};
140
141const VkAllocationCallbacks* g_Allocs;
142
Adam Sawicki978fcf52018-12-05 14:38:48 +0100143void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200144{
145 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
146 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
147 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
148}
149
Adam Sawicki978fcf52018-12-05 14:38:48 +0100150void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200151{
152 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
153
154 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
155 submitInfo.commandBufferCount = 1;
156 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
157
158 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
159 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
160}
161
Adam Sawickida6c1942018-12-05 17:34:34 +0100162void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200163{
164 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
165 if(file.is_open() == false)
166 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
167 assert(file.is_open());
168 size_t fileSize = (size_t)file.tellg();
169 if(fileSize > 0)
170 {
171 out.resize(fileSize);
172 file.seekg(0);
173 file.read(out.data(), fileSize);
174 file.close();
175 }
176 else
177 out.clear();
178}
179
180VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback(
181 VkDebugReportFlagsEXT flags,
182 VkDebugReportObjectTypeEXT objectType,
183 uint64_t object,
184 size_t location,
185 int32_t messageCode,
186 const char* pLayerPrefix,
187 const char* pMessage,
188 void* pUserData)
189{
Adam Sawickib8333fb2018-03-13 16:15:53 +0100190 // "Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug."
191 if(!g_MemoryAliasingWarningEnabled && flags == VK_DEBUG_REPORT_WARNING_BIT_EXT &&
192 (strstr(pMessage, " is aliased with non-linear ") || strstr(pMessage, " is aliased with linear ")))
193 {
194 return VK_FALSE;
195 }
196
197 // Ignoring because when VK_KHR_dedicated_allocation extension is enabled,
198 // vkGetBufferMemoryRequirements2KHR function is used instead, while Validation
199 // Layer seems to be unaware of it.
200 if (strstr(pMessage, "but vkGetBufferMemoryRequirements() has not been called on that buffer") != nullptr)
201 {
202 return VK_FALSE;
203 }
204 if (strstr(pMessage, "but vkGetImageMemoryRequirements() has not been called on that image") != nullptr)
205 {
206 return VK_FALSE;
207 }
Adam Sawicki94e82062018-08-20 11:12:51 +0200208
209 /*
210 "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."
211 Ignoring because we map entire VkDeviceMemory blocks, where different types of
212 images and buffers may end up together, especially on GPUs with unified memory
213 like Intel.
214 */
215 if(strstr(pMessage, "Mapping an image with layout") != nullptr &&
216 strstr(pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr)
217 {
218 return VK_FALSE;
219 }
Adam Sawickib8333fb2018-03-13 16:15:53 +0100220
221 switch(flags)
222 {
223 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
224 SetConsoleColor(CONSOLE_COLOR::WARNING);
225 break;
226 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
227 SetConsoleColor(CONSOLE_COLOR::ERROR_);
228 break;
229 default:
230 SetConsoleColor(CONSOLE_COLOR::INFO);
231 }
232
Adam Sawickie6e498f2017-06-16 17:21:31 +0200233 printf("%s \xBA %s\n", pLayerPrefix, pMessage);
234
Adam Sawickib8333fb2018-03-13 16:15:53 +0100235 SetConsoleColor(CONSOLE_COLOR::NORMAL);
236
237 if(flags == VK_DEBUG_REPORT_WARNING_BIT_EXT ||
238 flags == VK_DEBUG_REPORT_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200239 {
240 OutputDebugStringA(pMessage);
241 OutputDebugStringA("\n");
242 }
243
244 return VK_FALSE;
245}
246
247static VkSurfaceFormatKHR ChooseSurfaceFormat()
248{
249 assert(!g_SurfaceFormats.empty());
250
251 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
252 {
253 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
254 return result;
255 }
256
257 for(const auto& format : g_SurfaceFormats)
258 {
259 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
260 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
261 {
262 return format;
263 }
264 }
265
266 return g_SurfaceFormats[0];
267}
268
269VkPresentModeKHR ChooseSwapPresentMode()
270{
271 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
272
273 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
274 g_PresentModes.end())
275 {
276 return preferredMode;
277 }
278
279 return VK_PRESENT_MODE_FIFO_KHR;
280}
281
282static VkExtent2D ChooseSwapExtent()
283{
284 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
285 return g_SurfaceCapabilities.currentExtent;
286
287 VkExtent2D result = {
288 std::max(g_SurfaceCapabilities.minImageExtent.width,
289 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
290 std::max(g_SurfaceCapabilities.minImageExtent.height,
291 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
292 return result;
293}
294
295struct Vertex
296{
297 float pos[3];
298 float color[3];
299 float texCoord[2];
300};
301
302static void CreateMesh()
303{
304 assert(g_hAllocator);
305
306 static Vertex vertices[] = {
307 // -X
308 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
309 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
310 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
311 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
312 // +X
313 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
314 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
315 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
316 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
317 // -Z
318 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
319 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
320 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
321 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
322 // +Z
323 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
324 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
325 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
326 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
327 // -Y
328 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
329 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
330 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
331 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
332 // +Y
333 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
334 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
335 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
336 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
337 };
338 static uint16_t indices[] = {
339 0, 1, 2, 3, USHRT_MAX,
340 4, 5, 6, 7, USHRT_MAX,
341 8, 9, 10, 11, USHRT_MAX,
342 12, 13, 14, 15, USHRT_MAX,
343 16, 17, 18, 19, USHRT_MAX,
344 20, 21, 22, 23, USHRT_MAX,
345 };
346
347 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
348 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
349 g_IndexCount = (uint32_t)_countof(indices);
350
351 // Create vertex buffer
352
353 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
354 vbInfo.size = vertexBufferSize;
355 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
356 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200357
Adam Sawicki976f9202017-09-12 20:45:14 +0200358 VmaAllocationCreateInfo vbAllocCreateInfo = {};
359 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100360 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200361
Adam Sawicki819860e2017-07-04 14:30:38 +0200362 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
363 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
364 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200365 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200366
367 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200368
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200369 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
370
Adam Sawickie6e498f2017-06-16 17:21:31 +0200371 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200372 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
373 vbAllocCreateInfo.flags = 0;
374 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200375
376 // Create index buffer
377
378 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
379 ibInfo.size = indexBufferSize;
380 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
381 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200382
Adam Sawicki976f9202017-09-12 20:45:14 +0200383 VmaAllocationCreateInfo ibAllocCreateInfo = {};
384 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100385 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200386
Adam Sawickie6e498f2017-06-16 17:21:31 +0200387 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200388 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
389 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200390 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200391
Adam Sawicki819860e2017-07-04 14:30:38 +0200392 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200393
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200394 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
395
Adam Sawickie6e498f2017-06-16 17:21:31 +0200396 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200397 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
398 ibAllocCreateInfo.flags = 0;
399 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200400
401 // Copy buffers
402
403 BeginSingleTimeCommands();
404
405 VkBufferCopy vbCopyRegion = {};
406 vbCopyRegion.srcOffset = 0;
407 vbCopyRegion.dstOffset = 0;
408 vbCopyRegion.size = vbInfo.size;
409 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
410
411 VkBufferCopy ibCopyRegion = {};
412 ibCopyRegion.srcOffset = 0;
413 ibCopyRegion.dstOffset = 0;
414 ibCopyRegion.size = ibInfo.size;
415 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
416
417 EndSingleTimeCommands();
418
Adam Sawicki819860e2017-07-04 14:30:38 +0200419 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
420 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200421}
422
Adam Sawickie6e498f2017-06-16 17:21:31 +0200423static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
424{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100425 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200426
427 const VkDeviceSize imageSize = sizeX * sizeY * 4;
428
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100429 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
430 stagingBufInfo.size = imageSize;
431 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
432
433 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
434 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
435 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200436
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100437 VkBuffer stagingBuf = VK_NULL_HANDLE;
438 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
439 VmaAllocationInfo stagingBufAllocInfo = {};
440 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200441
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100442 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
443 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200444 for(uint32_t y = 0; y < sizeY; ++y)
445 {
446 uint32_t* pPixelData = (uint32_t*)pRowData;
447 for(uint32_t x = 0; x < sizeY; ++x)
448 {
449 *pPixelData =
450 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
451 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
452 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
453 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
454 ++pPixelData;
455 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100456 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200457 }
458
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200459 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
460
Adam Sawicki10844a82017-08-16 17:32:09 +0200461 // Create g_hTextureImage in GPU memory.
462
Adam Sawickie6e498f2017-06-16 17:21:31 +0200463 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
464 imageInfo.imageType = VK_IMAGE_TYPE_2D;
465 imageInfo.extent.width = sizeX;
466 imageInfo.extent.height = sizeY;
467 imageInfo.extent.depth = 1;
468 imageInfo.mipLevels = 1;
469 imageInfo.arrayLayers = 1;
470 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
471 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
472 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
473 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
474 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
475 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
476 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200477
Adam Sawicki976f9202017-09-12 20:45:14 +0200478 VmaAllocationCreateInfo imageAllocCreateInfo = {};
479 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200480
Adam Sawicki976f9202017-09-12 20:45:14 +0200481 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200482
Adam Sawicki10844a82017-08-16 17:32:09 +0200483 // Transition image layouts, copy image.
484
485 BeginSingleTimeCommands();
486
487 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200488 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
489 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200490 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
491 imgMemBarrier.subresourceRange.baseMipLevel = 0;
492 imgMemBarrier.subresourceRange.levelCount = 1;
493 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
494 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200495 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
496 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
497 imgMemBarrier.image = g_hTextureImage;
498 imgMemBarrier.srcAccessMask = 0;
499 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
500
501 vkCmdPipelineBarrier(
502 g_hTemporaryCommandBuffer,
503 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
504 VK_PIPELINE_STAGE_TRANSFER_BIT,
505 0,
506 0, nullptr,
507 0, nullptr,
508 1, &imgMemBarrier);
509
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100510 VkBufferImageCopy region = {};
511 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
512 region.imageSubresource.layerCount = 1;
513 region.imageExtent.width = sizeX;
514 region.imageExtent.height = sizeY;
515 region.imageExtent.depth = 1;
516
517 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200518
519 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
520 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
521 imgMemBarrier.image = g_hTextureImage;
522 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
523 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
524
525 vkCmdPipelineBarrier(
526 g_hTemporaryCommandBuffer,
527 VK_PIPELINE_STAGE_TRANSFER_BIT,
528 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
529 0,
530 0, nullptr,
531 0, nullptr,
532 1, &imgMemBarrier);
533
534 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200535
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100536 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200537
538 // Create ImageView
539
540 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
541 textureImageViewInfo.image = g_hTextureImage;
542 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
543 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
544 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
545 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
546 textureImageViewInfo.subresourceRange.levelCount = 1;
547 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
548 textureImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200549 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200550}
551
552struct UniformBufferObject
553{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200554 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200555};
556
557static void RegisterDebugCallbacks()
558{
559 g_pvkCreateDebugReportCallbackEXT =
560 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
561 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
562 g_pvkDebugReportMessageEXT =
563 reinterpret_cast<PFN_vkDebugReportMessageEXT>
564 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
565 g_pvkDestroyDebugReportCallbackEXT =
566 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
567 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
568 assert(g_pvkCreateDebugReportCallbackEXT);
569 assert(g_pvkDebugReportMessageEXT);
570 assert(g_pvkDestroyDebugReportCallbackEXT);
571
572 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
573 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
574 callbackCreateInfo.pNext = nullptr;
575 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
576 VK_DEBUG_REPORT_ERROR_BIT_EXT |
577 VK_DEBUG_REPORT_WARNING_BIT_EXT |
578 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
579 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
580 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
581 callbackCreateInfo.pUserData = nullptr;
582
Adam Sawicki1f84f622019-07-02 13:40:01 +0200583 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, g_Allocs, &g_hCallback) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200584}
585
586static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
587{
588 const VkLayerProperties* propsEnd = pProps + propCount;
589 return std::find_if(
590 pProps,
591 propsEnd,
592 [pLayerName](const VkLayerProperties& prop) -> bool {
593 return strcmp(pLayerName, prop.layerName) == 0;
594 }) != propsEnd;
595}
596
597static VkFormat FindSupportedFormat(
598 const std::vector<VkFormat>& candidates,
599 VkImageTiling tiling,
600 VkFormatFeatureFlags features)
601{
602 for (VkFormat format : candidates)
603 {
604 VkFormatProperties props;
605 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
606
607 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
608 ((props.linearTilingFeatures & features) == features))
609 {
610 return format;
611 }
612 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
613 ((props.optimalTilingFeatures & features) == features))
614 {
615 return format;
616 }
617 }
618 return VK_FORMAT_UNDEFINED;
619}
620
621static VkFormat FindDepthFormat()
622{
623 std::vector<VkFormat> formats;
624 formats.push_back(VK_FORMAT_D32_SFLOAT);
625 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
626 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
627
628 return FindSupportedFormat(
629 formats,
630 VK_IMAGE_TILING_OPTIMAL,
631 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
632}
633
634static void CreateSwapchain()
635{
636 // Query surface formats.
637
638 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
639
640 uint32_t formatCount = 0;
641 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
642 g_SurfaceFormats.resize(formatCount);
643 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
644
645 uint32_t presentModeCount = 0;
646 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
647 g_PresentModes.resize(presentModeCount);
648 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
649
650 // Create swap chain
651
652 g_SurfaceFormat = ChooseSurfaceFormat();
653 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
654 g_Extent = ChooseSwapExtent();
655
656 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
657 if((g_SurfaceCapabilities.maxImageCount > 0) &&
658 (imageCount > g_SurfaceCapabilities.maxImageCount))
659 {
660 imageCount = g_SurfaceCapabilities.maxImageCount;
661 }
662
663 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
664 swapChainInfo.surface = g_hSurface;
665 swapChainInfo.minImageCount = imageCount;
666 swapChainInfo.imageFormat = g_SurfaceFormat.format;
667 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
668 swapChainInfo.imageExtent = g_Extent;
669 swapChainInfo.imageArrayLayers = 1;
670 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
671 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
672 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
673 swapChainInfo.presentMode = presentMode;
674 swapChainInfo.clipped = VK_TRUE;
675 swapChainInfo.oldSwapchain = g_hSwapchain;
676
677 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
678 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
679 {
680 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
681 swapChainInfo.queueFamilyIndexCount = 2;
682 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
683 }
684 else
685 {
686 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
687 }
688
689 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200690 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, g_Allocs, &hNewSwapchain) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200691 if(g_hSwapchain != VK_NULL_HANDLE)
Adam Sawicki1f84f622019-07-02 13:40:01 +0200692 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200693 g_hSwapchain = hNewSwapchain;
694
695 // Retrieve swapchain images.
696
697 uint32_t swapchainImageCount = 0;
698 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
699 g_SwapchainImages.resize(swapchainImageCount);
700 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
701
702 // Create swapchain image views.
703
704 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +0200705 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200706 g_SwapchainImageViews.clear();
707
708 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
709 g_SwapchainImageViews.resize(swapchainImageCount);
710 for(uint32_t i = 0; i < swapchainImageCount; ++i)
711 {
712 swapchainImageViewInfo.image = g_SwapchainImages[i];
713 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
714 swapchainImageViewInfo.format = g_SurfaceFormat.format;
715 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
716 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
717 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
718 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
719 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
720 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
721 swapchainImageViewInfo.subresourceRange.levelCount = 1;
722 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
723 swapchainImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200724 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200725 }
726
727 // Create depth buffer
728
729 g_DepthFormat = FindDepthFormat();
730 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
731
732 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
733 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
734 depthImageInfo.extent.width = g_Extent.width;
735 depthImageInfo.extent.height = g_Extent.height;
736 depthImageInfo.extent.depth = 1;
737 depthImageInfo.mipLevels = 1;
738 depthImageInfo.arrayLayers = 1;
739 depthImageInfo.format = g_DepthFormat;
740 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
741 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
742 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
743 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
744 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
745 depthImageInfo.flags = 0;
746
Adam Sawicki976f9202017-09-12 20:45:14 +0200747 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
748 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200749
Adam Sawicki976f9202017-09-12 20:45:14 +0200750 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200751
752 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
753 depthImageViewInfo.image = g_hDepthImage;
754 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
755 depthImageViewInfo.format = g_DepthFormat;
756 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
757 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
758 depthImageViewInfo.subresourceRange.levelCount = 1;
759 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
760 depthImageViewInfo.subresourceRange.layerCount = 1;
761
Adam Sawicki1f84f622019-07-02 13:40:01 +0200762 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200763
Adam Sawickie6e498f2017-06-16 17:21:31 +0200764 // Create pipeline layout
765 {
766 if(g_hPipelineLayout != VK_NULL_HANDLE)
767 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200768 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200769 g_hPipelineLayout = VK_NULL_HANDLE;
770 }
771
772 VkPushConstantRange pushConstantRanges[1];
773 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
774 pushConstantRanges[0].offset = 0;
775 pushConstantRanges[0].size = sizeof(UniformBufferObject);
776 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
777
778 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
779 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
780 pipelineLayoutInfo.setLayoutCount = 1;
781 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
782 pipelineLayoutInfo.pushConstantRangeCount = 1;
783 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200784 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200785 }
786
787 // Create render pass
788 {
789 if(g_hRenderPass != VK_NULL_HANDLE)
790 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200791 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200792 g_hRenderPass = VK_NULL_HANDLE;
793 }
794
795 VkAttachmentDescription attachments[2];
796 ZeroMemory(attachments, sizeof(attachments));
797
798 attachments[0].format = g_SurfaceFormat.format;
799 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
800 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
801 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
802 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
803 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100804 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200805 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
806
807 attachments[1].format = g_DepthFormat;
808 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
809 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
810 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
811 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
812 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100813 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200814 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
815
816 VkAttachmentReference colorAttachmentRef = {};
817 colorAttachmentRef.attachment = 0;
818 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
819
820 VkAttachmentReference depthStencilAttachmentRef = {};
821 depthStencilAttachmentRef.attachment = 1;
822 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
823
824 VkSubpassDescription subpassDesc = {};
825 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
826 subpassDesc.colorAttachmentCount = 1;
827 subpassDesc.pColorAttachments = &colorAttachmentRef;
828 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
829
Adam Sawickie6e498f2017-06-16 17:21:31 +0200830 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
831 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
832 renderPassInfo.pAttachments = attachments;
833 renderPassInfo.subpassCount = 1;
834 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200835 renderPassInfo.dependencyCount = 0;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200836 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200837 }
838
839 // Create pipeline
840 {
841 std::vector<char> vertShaderCode;
842 LoadShader(vertShaderCode, "Shader.vert.spv");
843 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
844 shaderModuleInfo.codeSize = vertShaderCode.size();
845 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
846 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200847 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200848
849 std::vector<char> hFragShaderCode;
850 LoadShader(hFragShaderCode, "Shader.frag.spv");
851 shaderModuleInfo.codeSize = hFragShaderCode.size();
852 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
853 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200854 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200855
856 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
857 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
858 vertPipelineShaderStageInfo.module = hVertShaderModule;
859 vertPipelineShaderStageInfo.pName = "main";
860
861 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
862 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
863 fragPipelineShaderStageInfo.module = fragShaderModule;
864 fragPipelineShaderStageInfo.pName = "main";
865
866 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
867 vertPipelineShaderStageInfo,
868 fragPipelineShaderStageInfo
869 };
870
871 VkVertexInputBindingDescription bindingDescription = {};
872 bindingDescription.binding = 0;
873 bindingDescription.stride = sizeof(Vertex);
874 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
875
876 VkVertexInputAttributeDescription attributeDescriptions[3];
877 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
878
879 attributeDescriptions[0].binding = 0;
880 attributeDescriptions[0].location = 0;
881 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
882 attributeDescriptions[0].offset = offsetof(Vertex, pos);
883
884 attributeDescriptions[1].binding = 0;
885 attributeDescriptions[1].location = 1;
886 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
887 attributeDescriptions[1].offset = offsetof(Vertex, color);
888
889 attributeDescriptions[2].binding = 0;
890 attributeDescriptions[2].location = 2;
891 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
892 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
893
894 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
895 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
896 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
897 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
898 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
899
900 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
901 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
902 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
903
904 VkViewport viewport = {};
905 viewport.x = 0.f;
906 viewport.y = 0.f;
907 viewport.width = (float)g_Extent.width;
908 viewport.height = (float)g_Extent.height;
909 viewport.minDepth = 0.f;
910 viewport.maxDepth = 1.f;
911
912 VkRect2D scissor = {};
913 scissor.offset.x = 0;
914 scissor.offset.y = 0;
915 scissor.extent = g_Extent;
916
917 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
918 pipelineViewportStateInfo.viewportCount = 1;
919 pipelineViewportStateInfo.pViewports = &viewport;
920 pipelineViewportStateInfo.scissorCount = 1;
921 pipelineViewportStateInfo.pScissors = &scissor;
922
923 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
924 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
925 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
926 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
927 pipelineRasterizationStateInfo.lineWidth = 1.f;
928 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
929 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
930 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
931 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
932 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
933 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
934
935 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
936 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
937 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
938 pipelineMultisampleStateInfo.minSampleShading = 1.f;
939 pipelineMultisampleStateInfo.pSampleMask = nullptr;
940 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
941 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
942
943 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
944 pipelineColorBlendAttachmentState.colorWriteMask =
945 VK_COLOR_COMPONENT_R_BIT |
946 VK_COLOR_COMPONENT_G_BIT |
947 VK_COLOR_COMPONENT_B_BIT |
948 VK_COLOR_COMPONENT_A_BIT;
949 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
950 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
951 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
952 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
953 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
954 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
955 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
956
957 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
958 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
959 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
960 pipelineColorBlendStateInfo.attachmentCount = 1;
961 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
962
963 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
964 depthStencilStateInfo.depthTestEnable = VK_TRUE;
965 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
966 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
967 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
968 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
969
970 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
971 pipelineInfo.stageCount = 2;
972 pipelineInfo.pStages = pipelineShaderStageInfos;
973 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
974 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
975 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
976 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
977 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
978 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
979 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
980 pipelineInfo.pDynamicState = nullptr;
981 pipelineInfo.layout = g_hPipelineLayout;
982 pipelineInfo.renderPass = g_hRenderPass;
983 pipelineInfo.subpass = 0;
984 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
985 pipelineInfo.basePipelineIndex = -1;
986 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
987 g_hDevice,
988 VK_NULL_HANDLE,
989 1,
Adam Sawicki1f84f622019-07-02 13:40:01 +0200990 &pipelineInfo,
991 g_Allocs,
Adam Sawickie6e498f2017-06-16 17:21:31 +0200992 &g_hPipeline) );
993
Adam Sawicki1f84f622019-07-02 13:40:01 +0200994 vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
995 vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200996 }
997
998 // Create frambuffers
999
1000 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001001 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001002 g_Framebuffers.clear();
1003
1004 g_Framebuffers.resize(g_SwapchainImageViews.size());
1005 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1006 {
1007 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1008
1009 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1010 framebufferInfo.renderPass = g_hRenderPass;
1011 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1012 framebufferInfo.pAttachments = attachments;
1013 framebufferInfo.width = g_Extent.width;
1014 framebufferInfo.height = g_Extent.height;
1015 framebufferInfo.layers = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001016 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001017 }
1018
1019 // Create semaphores
1020
1021 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1022 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001023 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001024 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1025 }
1026 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1027 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001028 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001029 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1030 }
1031
1032 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
Adam Sawicki1f84f622019-07-02 13:40:01 +02001033 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
1034 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001035}
1036
1037static void DestroySwapchain(bool destroyActualSwapchain)
1038{
1039 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1040 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001041 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001042 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1043 }
1044 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1045 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001046 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001047 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1048 }
1049
1050 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001051 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001052 g_Framebuffers.clear();
1053
1054 if(g_hDepthImageView != VK_NULL_HANDLE)
1055 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001056 vkDestroyImageView(g_hDevice, g_hDepthImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001057 g_hDepthImageView = VK_NULL_HANDLE;
1058 }
1059 if(g_hDepthImage != VK_NULL_HANDLE)
1060 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001061 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001062 g_hDepthImage = VK_NULL_HANDLE;
1063 }
1064
1065 if(g_hPipeline != VK_NULL_HANDLE)
1066 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001067 vkDestroyPipeline(g_hDevice, g_hPipeline, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001068 g_hPipeline = VK_NULL_HANDLE;
1069 }
1070
1071 if(g_hRenderPass != VK_NULL_HANDLE)
1072 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001073 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001074 g_hRenderPass = VK_NULL_HANDLE;
1075 }
1076
1077 if(g_hPipelineLayout != VK_NULL_HANDLE)
1078 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001079 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001080 g_hPipelineLayout = VK_NULL_HANDLE;
1081 }
1082
1083 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001084 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001085 g_SwapchainImageViews.clear();
1086
1087 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1088 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001089 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001090 g_hSwapchain = VK_NULL_HANDLE;
1091 }
1092}
1093
1094static void InitializeApplication()
1095{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001096 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1097 {
1098 g_Allocs = &g_CpuAllocationCallbacks;
1099 }
1100
Adam Sawickie6e498f2017-06-16 17:21:31 +02001101 uint32_t instanceLayerPropCount = 0;
1102 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1103 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1104 if(instanceLayerPropCount > 0)
1105 {
1106 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1107 }
1108
1109 if(g_EnableValidationLayer == true)
1110 {
1111 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1112 {
1113 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1114 g_EnableValidationLayer = false;
1115 }
1116 }
1117
1118 std::vector<const char*> instanceExtensions;
1119 instanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1120 instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
1121
1122 std::vector<const char*> instanceLayers;
1123 if(g_EnableValidationLayer == true)
1124 {
1125 instanceLayers.push_back(VALIDATION_LAYER_NAME);
1126 instanceExtensions.push_back("VK_EXT_debug_report");
1127 }
1128
1129 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1130 appInfo.pApplicationName = APP_TITLE_A;
1131 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1132 appInfo.pEngineName = "Adam Sawicki Engine";
1133 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
1134 appInfo.apiVersion = VK_API_VERSION_1_0;
1135
1136 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1137 instInfo.pApplicationInfo = &appInfo;
1138 instInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
1139 instInfo.ppEnabledExtensionNames = instanceExtensions.data();
1140 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1141 instInfo.ppEnabledLayerNames = instanceLayers.data();
1142
Adam Sawicki1f84f622019-07-02 13:40:01 +02001143 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001144
1145 // Create VkSurfaceKHR.
1146 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1147 surfaceInfo.hinstance = g_hAppInstance;
1148 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001149 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001150 assert(result == VK_SUCCESS);
1151
1152 if(g_EnableValidationLayer == true)
1153 RegisterDebugCallbacks();
1154
1155 // Find physical device
1156
1157 uint32_t deviceCount = 0;
1158 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1159 assert(deviceCount > 0);
1160
1161 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1162 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1163
1164 g_hPhysicalDevice = physicalDevices[0];
1165
1166 // Query for features
1167
1168 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1169 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1170
Adam Sawicki51fa9662018-10-03 13:44:29 +02001171 VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
1172 vkGetPhysicalDeviceFeatures(g_hPhysicalDevice, &physicalDeviceFeatures);
1173
1174 g_SparseBindingEnabled = physicalDeviceFeatures.sparseBinding != 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001175
1176 // Find queue family index
1177
1178 uint32_t queueFamilyCount = 0;
1179 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1180 assert(queueFamilyCount > 0);
1181 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1182 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1183 for(uint32_t i = 0;
1184 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001185 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1186 g_PresentQueueFamilyIndex == UINT_MAX ||
1187 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001188 ++i)
1189 {
1190 if(queueFamilies[i].queueCount > 0)
1191 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001192 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001193 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001194 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001195 {
1196 g_GraphicsQueueFamilyIndex = i;
1197 }
1198
1199 VkBool32 surfaceSupported = 0;
1200 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1201 if((res >= 0) && (surfaceSupported == VK_TRUE))
1202 {
1203 g_PresentQueueFamilyIndex = i;
1204 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001205
1206 if(g_SparseBindingEnabled &&
1207 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1208 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1209 {
1210 g_SparseBindingQueueFamilyIndex = i;
1211 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001212 }
1213 }
1214 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1215
Adam Sawicki51fa9662018-10-03 13:44:29 +02001216 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1217
Adam Sawickie6e498f2017-06-16 17:21:31 +02001218 // Create logical device
1219
1220 const float queuePriority = 1.f;
1221
Adam Sawicki51fa9662018-10-03 13:44:29 +02001222 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1223 uint32_t queueCount = 1;
1224 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1225 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1226 queueCreateInfo[0].queueCount = 1;
1227 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1228
1229 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1230 {
1231
1232 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1233 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1234 queueCreateInfo[queueCount].queueCount = 1;
1235 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1236 ++queueCount;
1237 }
1238
1239 if(g_SparseBindingEnabled &&
1240 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1241 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1242 {
1243
1244 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1245 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1246 queueCreateInfo[queueCount].queueCount = 1;
1247 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1248 ++queueCount;
1249 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001250
1251 VkPhysicalDeviceFeatures deviceFeatures = {};
Adam Sawicki51fa9662018-10-03 13:44:29 +02001252 //deviceFeatures.fillModeNonSolid = VK_TRUE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001253 deviceFeatures.samplerAnisotropy = VK_TRUE;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001254 deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001255
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001256 // Determine list of device extensions to enable.
Adam Sawickie6e498f2017-06-16 17:21:31 +02001257 std::vector<const char*> enabledDeviceExtensions;
1258 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001259 {
1260 uint32_t propertyCount = 0;
1261 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, nullptr) );
1262
1263 if(propertyCount)
1264 {
1265 std::vector<VkExtensionProperties> properties{propertyCount};
1266 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, properties.data()) );
1267
1268 for(uint32_t i = 0; i < propertyCount; ++i)
1269 {
1270 if(strcmp(properties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1271 {
1272 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1273 VK_KHR_get_memory_requirements2_enabled = true;
1274 }
1275 else if(strcmp(properties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1276 {
1277 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1278 VK_KHR_dedicated_allocation_enabled = true;
1279 }
Adam Sawicki4abe30c2019-07-02 14:37:21 +02001280 else if(strcmp(properties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
1281 {
1282 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1283 VK_KHR_bind_memory2_enabled = true;
1284 }
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001285 }
1286 }
1287 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001288
1289 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1290 deviceCreateInfo.enabledLayerCount = 0;
1291 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1292 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001293 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001294 deviceCreateInfo.queueCreateInfoCount = queueCount;
1295 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001296 deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
1297
Adam Sawicki1f84f622019-07-02 13:40:01 +02001298 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001299
1300 // Create memory allocator
1301
1302 VmaAllocatorCreateInfo allocatorInfo = {};
1303 allocatorInfo.physicalDevice = g_hPhysicalDevice;
1304 allocatorInfo.device = g_hDevice;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001305
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001306 if(VK_KHR_dedicated_allocation_enabled)
1307 {
Adam Sawickif48896d2019-04-16 12:55:35 +02001308 /*
1309 Comment out this line to make the app working with RenderDoc.
Adam Sawicki4fb254e2019-04-23 11:29:57 +02001310
1311 Currently there is a problem with compatibility of this app with RenderDoc due
1312 to a known bug in Vulkan validation layers:
Adam Sawickif48896d2019-04-16 12:55:35 +02001313
Adam Sawicki4fb254e2019-04-23 11:29:57 +02001314 https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/579
1315
1316 It occurs because this app uses Vulkan 1.0 and VK_KHR_dedicated_allocation
1317 extension instead of equivalent functionality embedded into Vulkan 1.1.
Adam Sawickif48896d2019-04-16 12:55:35 +02001318 */
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001319 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1320 }
Adam Sawicki4abe30c2019-07-02 14:37:21 +02001321 if(VK_KHR_bind_memory2_enabled)
1322 {
1323 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
1324 }
Adam Sawickia68c01c2018-03-13 16:40:45 +01001325
Adam Sawickia68c01c2018-03-13 16:40:45 +01001326 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1327 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001328 allocatorInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001329 }
1330
Adam Sawickib0c36362018-11-13 16:17:38 +01001331 // Uncomment to enable recording to CSV file.
1332 /*
1333 {
1334 VmaRecordSettings recordSettings = {};
1335 recordSettings.pFilePath = "VulkanSample.csv";
1336 allocatorInfo.pRecordSettings = &recordSettings;
1337 }
1338 */
1339
Adam Sawicki5f573f52019-10-11 15:59:58 +02001340 // Uncomment to enable HeapSizeLimit.
1341 /*
1342 std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapSizeLimit;
1343 std::fill(heapSizeLimit.begin(), heapSizeLimit.end(), VK_WHOLE_SIZE);
1344 heapSizeLimit[0] = 100ull * 1024 * 1024;
1345 allocatorInfo.pHeapSizeLimit = heapSizeLimit.data();
1346 */
1347
Adam Sawickie6e498f2017-06-16 17:21:31 +02001348 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1349
Adam Sawicki51fa9662018-10-03 13:44:29 +02001350 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001351
1352 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1353 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1354 assert(g_hGraphicsQueue);
1355 assert(g_hPresentQueue);
1356
Adam Sawicki51fa9662018-10-03 13:44:29 +02001357 if(g_SparseBindingEnabled)
1358 {
1359 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1360 assert(g_hSparseBindingQueue);
1361 }
1362
Adam Sawickie6e498f2017-06-16 17:21:31 +02001363 // Create command pool
1364
1365 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1366 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1367 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001368 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001369
1370 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1371 commandBufferInfo.commandPool = g_hCommandPool;
1372 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1373 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1374 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1375
1376 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1377 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1378 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1379 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001380 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001381 }
1382
Adam Sawicki1f84f622019-07-02 13:40:01 +02001383 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001384
Adam Sawickie6e498f2017-06-16 17:21:31 +02001385 commandBufferInfo.commandBufferCount = 1;
1386 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1387
1388 // Create texture sampler
1389
1390 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1391 samplerInfo.magFilter = VK_FILTER_LINEAR;
1392 samplerInfo.minFilter = VK_FILTER_LINEAR;
1393 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1394 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1395 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1396 samplerInfo.anisotropyEnable = VK_TRUE;
1397 samplerInfo.maxAnisotropy = 16;
1398 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1399 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1400 samplerInfo.compareEnable = VK_FALSE;
1401 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1402 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1403 samplerInfo.mipLodBias = 0.f;
1404 samplerInfo.minLod = 0.f;
1405 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001406 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001407
1408 CreateTexture(128, 128);
1409 CreateMesh();
1410
1411 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1412 samplerLayoutBinding.binding = 1;
1413 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1414 samplerLayoutBinding.descriptorCount = 1;
1415 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1416
1417 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1418 descriptorSetLayoutInfo.bindingCount = 1;
1419 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001420 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001421
1422 // Create descriptor pool
1423
1424 VkDescriptorPoolSize descriptorPoolSizes[2];
1425 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1426 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1427 descriptorPoolSizes[0].descriptorCount = 1;
1428 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1429 descriptorPoolSizes[1].descriptorCount = 1;
1430
1431 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1432 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1433 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1434 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001435 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001436
1437 // Create descriptor set layout
1438
1439 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1440 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1441 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1442 descriptorSetInfo.descriptorSetCount = 1;
1443 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1444 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1445
1446 VkDescriptorImageInfo descriptorImageInfo = {};
1447 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1448 descriptorImageInfo.imageView = g_hTextureImageView;
1449 descriptorImageInfo.sampler = g_hSampler;
1450
1451 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1452 writeDescriptorSet.dstSet = g_hDescriptorSet;
1453 writeDescriptorSet.dstBinding = 1;
1454 writeDescriptorSet.dstArrayElement = 0;
1455 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1456 writeDescriptorSet.descriptorCount = 1;
1457 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1458
1459 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1460
1461 CreateSwapchain();
1462}
1463
1464static void FinalizeApplication()
1465{
1466 vkDeviceWaitIdle(g_hDevice);
1467
1468 DestroySwapchain(true);
1469
1470 if(g_hDescriptorPool != VK_NULL_HANDLE)
1471 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001472 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001473 g_hDescriptorPool = VK_NULL_HANDLE;
1474 }
1475
1476 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1477 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001478 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001479 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1480 }
1481
1482 if(g_hTextureImageView != VK_NULL_HANDLE)
1483 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001484 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001485 g_hTextureImageView = VK_NULL_HANDLE;
1486 }
1487 if(g_hTextureImage != VK_NULL_HANDLE)
1488 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001489 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001490 g_hTextureImage = VK_NULL_HANDLE;
1491 }
1492
1493 if(g_hIndexBuffer != VK_NULL_HANDLE)
1494 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001495 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001496 g_hIndexBuffer = VK_NULL_HANDLE;
1497 }
1498 if(g_hVertexBuffer != VK_NULL_HANDLE)
1499 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001500 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001501 g_hVertexBuffer = VK_NULL_HANDLE;
1502 }
1503
1504 if(g_hSampler != VK_NULL_HANDLE)
1505 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001506 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001507 g_hSampler = VK_NULL_HANDLE;
1508 }
1509
Adam Sawicki51fa9662018-10-03 13:44:29 +02001510 if(g_ImmediateFence)
1511 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001512 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001513 g_ImmediateFence = VK_NULL_HANDLE;
1514 }
1515
Adam Sawickie6e498f2017-06-16 17:21:31 +02001516 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1517 {
1518 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1519 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001520 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001521 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1522 }
1523 }
1524 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1525 {
1526 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1527 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1528 }
1529 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1530 {
1531 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1532 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1533 }
1534
1535 if(g_hCommandPool != VK_NULL_HANDLE)
1536 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001537 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001538 g_hCommandPool = VK_NULL_HANDLE;
1539 }
1540
1541 if(g_hAllocator != VK_NULL_HANDLE)
1542 {
1543 vmaDestroyAllocator(g_hAllocator);
1544 g_hAllocator = nullptr;
1545 }
1546
1547 if(g_hDevice != VK_NULL_HANDLE)
1548 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001549 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001550 g_hDevice = nullptr;
1551 }
1552
1553 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1554 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001555 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001556 g_hCallback = VK_NULL_HANDLE;
1557 }
1558
1559 if(g_hSurface != VK_NULL_HANDLE)
1560 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001561 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001562 g_hSurface = VK_NULL_HANDLE;
1563 }
1564
1565 if(g_hVulkanInstance != VK_NULL_HANDLE)
1566 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001567 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001568 g_hVulkanInstance = VK_NULL_HANDLE;
1569 }
1570}
1571
1572static void PrintAllocatorStats()
1573{
1574#if VMA_STATS_STRING_ENABLED
1575 char* statsString = nullptr;
1576 vmaBuildStatsString(g_hAllocator, &statsString, true);
1577 printf("%s\n", statsString);
1578 vmaFreeStatsString(g_hAllocator, statsString);
1579#endif
1580}
1581
1582static void RecreateSwapChain()
1583{
1584 vkDeviceWaitIdle(g_hDevice);
1585 DestroySwapchain(false);
1586 CreateSwapchain();
1587}
1588
1589static void DrawFrame()
1590{
1591 // Begin main command buffer
1592 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1593 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1594 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1595
1596 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1597 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1598
1599 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1600 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1601 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1602
1603 // Acquire swapchain image
1604 uint32_t imageIndex = 0;
1605 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1606 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1607 {
1608 RecreateSwapChain();
1609 return;
1610 }
1611 else if(res < 0)
1612 {
1613 ERR_GUARD_VULKAN(res);
1614 }
1615
1616 // Record geometry pass
1617
1618 VkClearValue clearValues[2];
1619 ZeroMemory(clearValues, sizeof(clearValues));
1620 clearValues[0].color.float32[0] = 0.25f;
1621 clearValues[0].color.float32[1] = 0.25f;
1622 clearValues[0].color.float32[2] = 0.5f;
1623 clearValues[0].color.float32[3] = 1.0f;
1624 clearValues[1].depthStencil.depth = 1.0f;
1625
1626 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1627 renderPassBeginInfo.renderPass = g_hRenderPass;
1628 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1629 renderPassBeginInfo.renderArea.offset.x = 0;
1630 renderPassBeginInfo.renderArea.offset.y = 0;
1631 renderPassBeginInfo.renderArea.extent = g_Extent;
1632 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1633 renderPassBeginInfo.pClearValues = clearValues;
1634 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1635
1636 vkCmdBindPipeline(
1637 hCommandBuffer,
1638 VK_PIPELINE_BIND_POINT_GRAPHICS,
1639 g_hPipeline);
1640
Adam Sawicki82c3f332018-06-11 15:27:33 +02001641 mat4 view = mat4::LookAt(
1642 vec3(0.f, 0.f, 0.f),
1643 vec3(0.f, -2.f, 4.f),
1644 vec3(0.f, 1.f, 0.f));
1645 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001646 1.0471975511966f, // 60 degrees
1647 (float)g_Extent.width / (float)g_Extent.height,
1648 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001649 1000.f);
1650 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001651
1652 vkCmdBindDescriptorSets(
1653 hCommandBuffer,
1654 VK_PIPELINE_BIND_POINT_GRAPHICS,
1655 g_hPipelineLayout,
1656 0,
1657 1,
1658 &g_hDescriptorSet,
1659 0,
1660 nullptr);
1661
Adam Sawicki82c3f332018-06-11 15:27:33 +02001662 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1663 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001664
1665 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001666 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001667 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1668
1669 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1670 VkDeviceSize offsets[] = { 0 };
1671 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1672
1673 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1674
1675 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1676
1677 vkCmdEndRenderPass(hCommandBuffer);
1678
1679 vkEndCommandBuffer(hCommandBuffer);
1680
1681 // Submit command buffer
1682
1683 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1684 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1685 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1686 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1687 submitInfo.waitSemaphoreCount = 1;
1688 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1689 submitInfo.pWaitDstStageMask = submitWaitStages;
1690 submitInfo.commandBufferCount = 1;
1691 submitInfo.pCommandBuffers = &hCommandBuffer;
1692 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1693 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1694 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1695
1696 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1697
1698 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1699 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1700 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1701 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1702 presentInfo.swapchainCount = 1;
1703 presentInfo.pSwapchains = swapchains;
1704 presentInfo.pImageIndices = &imageIndex;
1705 presentInfo.pResults = nullptr;
1706 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1707 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1708 {
1709 RecreateSwapChain();
1710 }
1711 else
1712 ERR_GUARD_VULKAN(res);
1713}
1714
1715static void HandlePossibleSizeChange()
1716{
1717 RECT clientRect;
1718 GetClientRect(g_hWnd, &clientRect);
1719 LONG newSizeX = clientRect.right - clientRect.left;
1720 LONG newSizeY = clientRect.bottom - clientRect.top;
1721 if((newSizeX > 0) &&
1722 (newSizeY > 0) &&
1723 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1724 {
1725 g_SizeX = newSizeX;
1726 g_SizeY = newSizeY;
1727
1728 RecreateSwapChain();
1729 }
1730}
1731
1732static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1733{
1734 switch(msg)
1735 {
1736 case WM_CREATE:
1737 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1738 g_hWnd = hWnd;
1739 InitializeApplication();
1740 PrintAllocatorStats();
1741 return 0;
1742
1743 case WM_DESTROY:
1744 FinalizeApplication();
1745 PostQuitMessage(0);
1746 return 0;
1747
1748 // This prevents app from freezing when left Alt is pressed
1749 // (which normally enters modal menu loop).
1750 case WM_SYSKEYDOWN:
1751 case WM_SYSKEYUP:
1752 return 0;
1753
1754 case WM_SIZE:
1755 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1756 HandlePossibleSizeChange();
1757 return 0;
1758
1759 case WM_EXITSIZEMOVE:
1760 HandlePossibleSizeChange();
1761 return 0;
1762
1763 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001764 switch(wParam)
1765 {
1766 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001767 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001768 break;
1769 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001770 try
1771 {
1772 Test();
1773 }
1774 catch(const std::exception& ex)
1775 {
1776 printf("ERROR: %s\n", ex.what());
1777 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001778 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001779 case 'S':
1780 try
1781 {
1782 if(g_SparseBindingEnabled)
1783 {
1784 TestSparseBinding();
1785 }
1786 else
1787 {
1788 printf("Sparse binding not supported.\n");
1789 }
1790 }
1791 catch(const std::exception& ex)
1792 {
1793 printf("ERROR: %s\n", ex.what());
1794 }
1795 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001796 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001797 return 0;
1798
1799 default:
1800 break;
1801 }
1802
1803 return DefWindowProc(hWnd, msg, wParam, lParam);
1804}
1805
1806int main()
1807{
1808 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1809
1810 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1811 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1812 wndClassDesc.hbrBackground = NULL;
1813 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1814 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1815 wndClassDesc.hInstance = g_hAppInstance;
1816 wndClassDesc.lpfnWndProc = WndProc;
1817 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1818
1819 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1820 assert(hWndClass);
1821
1822 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1823 const DWORD exStyle = 0;
1824
1825 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1826 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1827
Adam Sawicki86ccd632017-07-04 14:57:53 +02001828 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001829 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1830 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1831 NULL, NULL, g_hAppInstance, NULL);
1832
1833 MSG msg;
1834 for(;;)
1835 {
1836 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1837 {
1838 if(msg.message == WM_QUIT)
1839 break;
1840 TranslateMessage(&msg);
1841 DispatchMessage(&msg);
1842 }
1843 if(g_hDevice != VK_NULL_HANDLE)
1844 DrawFrame();
1845 }
1846
1847 return 0;
1848}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001849
Adam Sawickif1a793c2018-03-13 15:42:22 +01001850#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001851
Adam Sawickif1a793c2018-03-13 15:42:22 +01001852#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001853
1854int main()
1855{
1856}
1857
Adam Sawickif1a793c2018-03-13 15:42:22 +01001858#endif // #ifdef _WIN32