blob: d289317e2d2caafdc057f478a2e2af8d8a9e820b [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 Sawickie6e498f2017-06-16 17:21:31 +02001340 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1341
Adam Sawicki51fa9662018-10-03 13:44:29 +02001342 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001343
1344 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1345 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1346 assert(g_hGraphicsQueue);
1347 assert(g_hPresentQueue);
1348
Adam Sawicki51fa9662018-10-03 13:44:29 +02001349 if(g_SparseBindingEnabled)
1350 {
1351 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1352 assert(g_hSparseBindingQueue);
1353 }
1354
Adam Sawickie6e498f2017-06-16 17:21:31 +02001355 // Create command pool
1356
1357 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1358 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1359 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001360 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001361
1362 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1363 commandBufferInfo.commandPool = g_hCommandPool;
1364 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1365 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1366 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1367
1368 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1369 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1370 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1371 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001372 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001373 }
1374
Adam Sawicki1f84f622019-07-02 13:40:01 +02001375 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001376
Adam Sawickie6e498f2017-06-16 17:21:31 +02001377 commandBufferInfo.commandBufferCount = 1;
1378 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1379
1380 // Create texture sampler
1381
1382 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1383 samplerInfo.magFilter = VK_FILTER_LINEAR;
1384 samplerInfo.minFilter = VK_FILTER_LINEAR;
1385 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1386 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1387 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1388 samplerInfo.anisotropyEnable = VK_TRUE;
1389 samplerInfo.maxAnisotropy = 16;
1390 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1391 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1392 samplerInfo.compareEnable = VK_FALSE;
1393 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1394 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1395 samplerInfo.mipLodBias = 0.f;
1396 samplerInfo.minLod = 0.f;
1397 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001398 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001399
1400 CreateTexture(128, 128);
1401 CreateMesh();
1402
1403 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1404 samplerLayoutBinding.binding = 1;
1405 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1406 samplerLayoutBinding.descriptorCount = 1;
1407 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1408
1409 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1410 descriptorSetLayoutInfo.bindingCount = 1;
1411 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001412 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001413
1414 // Create descriptor pool
1415
1416 VkDescriptorPoolSize descriptorPoolSizes[2];
1417 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1418 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1419 descriptorPoolSizes[0].descriptorCount = 1;
1420 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1421 descriptorPoolSizes[1].descriptorCount = 1;
1422
1423 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1424 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1425 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1426 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001427 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001428
1429 // Create descriptor set layout
1430
1431 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1432 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1433 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1434 descriptorSetInfo.descriptorSetCount = 1;
1435 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1436 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1437
1438 VkDescriptorImageInfo descriptorImageInfo = {};
1439 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1440 descriptorImageInfo.imageView = g_hTextureImageView;
1441 descriptorImageInfo.sampler = g_hSampler;
1442
1443 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1444 writeDescriptorSet.dstSet = g_hDescriptorSet;
1445 writeDescriptorSet.dstBinding = 1;
1446 writeDescriptorSet.dstArrayElement = 0;
1447 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1448 writeDescriptorSet.descriptorCount = 1;
1449 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1450
1451 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1452
1453 CreateSwapchain();
1454}
1455
1456static void FinalizeApplication()
1457{
1458 vkDeviceWaitIdle(g_hDevice);
1459
1460 DestroySwapchain(true);
1461
1462 if(g_hDescriptorPool != VK_NULL_HANDLE)
1463 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001464 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001465 g_hDescriptorPool = VK_NULL_HANDLE;
1466 }
1467
1468 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1469 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001470 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001471 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1472 }
1473
1474 if(g_hTextureImageView != VK_NULL_HANDLE)
1475 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001476 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001477 g_hTextureImageView = VK_NULL_HANDLE;
1478 }
1479 if(g_hTextureImage != VK_NULL_HANDLE)
1480 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001481 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001482 g_hTextureImage = VK_NULL_HANDLE;
1483 }
1484
1485 if(g_hIndexBuffer != VK_NULL_HANDLE)
1486 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001487 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001488 g_hIndexBuffer = VK_NULL_HANDLE;
1489 }
1490 if(g_hVertexBuffer != VK_NULL_HANDLE)
1491 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001492 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001493 g_hVertexBuffer = VK_NULL_HANDLE;
1494 }
1495
1496 if(g_hSampler != VK_NULL_HANDLE)
1497 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001498 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001499 g_hSampler = VK_NULL_HANDLE;
1500 }
1501
Adam Sawicki51fa9662018-10-03 13:44:29 +02001502 if(g_ImmediateFence)
1503 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001504 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001505 g_ImmediateFence = VK_NULL_HANDLE;
1506 }
1507
Adam Sawickie6e498f2017-06-16 17:21:31 +02001508 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1509 {
1510 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1511 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001512 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001513 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1514 }
1515 }
1516 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1517 {
1518 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1519 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1520 }
1521 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1522 {
1523 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1524 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1525 }
1526
1527 if(g_hCommandPool != VK_NULL_HANDLE)
1528 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001529 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001530 g_hCommandPool = VK_NULL_HANDLE;
1531 }
1532
1533 if(g_hAllocator != VK_NULL_HANDLE)
1534 {
1535 vmaDestroyAllocator(g_hAllocator);
1536 g_hAllocator = nullptr;
1537 }
1538
1539 if(g_hDevice != VK_NULL_HANDLE)
1540 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001541 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001542 g_hDevice = nullptr;
1543 }
1544
1545 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1546 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001547 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001548 g_hCallback = VK_NULL_HANDLE;
1549 }
1550
1551 if(g_hSurface != VK_NULL_HANDLE)
1552 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001553 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001554 g_hSurface = VK_NULL_HANDLE;
1555 }
1556
1557 if(g_hVulkanInstance != VK_NULL_HANDLE)
1558 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001559 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001560 g_hVulkanInstance = VK_NULL_HANDLE;
1561 }
1562}
1563
1564static void PrintAllocatorStats()
1565{
1566#if VMA_STATS_STRING_ENABLED
1567 char* statsString = nullptr;
1568 vmaBuildStatsString(g_hAllocator, &statsString, true);
1569 printf("%s\n", statsString);
1570 vmaFreeStatsString(g_hAllocator, statsString);
1571#endif
1572}
1573
1574static void RecreateSwapChain()
1575{
1576 vkDeviceWaitIdle(g_hDevice);
1577 DestroySwapchain(false);
1578 CreateSwapchain();
1579}
1580
1581static void DrawFrame()
1582{
1583 // Begin main command buffer
1584 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1585 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1586 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1587
1588 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1589 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1590
1591 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1592 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1593 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1594
1595 // Acquire swapchain image
1596 uint32_t imageIndex = 0;
1597 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1598 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1599 {
1600 RecreateSwapChain();
1601 return;
1602 }
1603 else if(res < 0)
1604 {
1605 ERR_GUARD_VULKAN(res);
1606 }
1607
1608 // Record geometry pass
1609
1610 VkClearValue clearValues[2];
1611 ZeroMemory(clearValues, sizeof(clearValues));
1612 clearValues[0].color.float32[0] = 0.25f;
1613 clearValues[0].color.float32[1] = 0.25f;
1614 clearValues[0].color.float32[2] = 0.5f;
1615 clearValues[0].color.float32[3] = 1.0f;
1616 clearValues[1].depthStencil.depth = 1.0f;
1617
1618 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1619 renderPassBeginInfo.renderPass = g_hRenderPass;
1620 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1621 renderPassBeginInfo.renderArea.offset.x = 0;
1622 renderPassBeginInfo.renderArea.offset.y = 0;
1623 renderPassBeginInfo.renderArea.extent = g_Extent;
1624 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1625 renderPassBeginInfo.pClearValues = clearValues;
1626 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1627
1628 vkCmdBindPipeline(
1629 hCommandBuffer,
1630 VK_PIPELINE_BIND_POINT_GRAPHICS,
1631 g_hPipeline);
1632
Adam Sawicki82c3f332018-06-11 15:27:33 +02001633 mat4 view = mat4::LookAt(
1634 vec3(0.f, 0.f, 0.f),
1635 vec3(0.f, -2.f, 4.f),
1636 vec3(0.f, 1.f, 0.f));
1637 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001638 1.0471975511966f, // 60 degrees
1639 (float)g_Extent.width / (float)g_Extent.height,
1640 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001641 1000.f);
1642 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001643
1644 vkCmdBindDescriptorSets(
1645 hCommandBuffer,
1646 VK_PIPELINE_BIND_POINT_GRAPHICS,
1647 g_hPipelineLayout,
1648 0,
1649 1,
1650 &g_hDescriptorSet,
1651 0,
1652 nullptr);
1653
Adam Sawicki82c3f332018-06-11 15:27:33 +02001654 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1655 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001656
1657 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001658 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001659 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1660
1661 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1662 VkDeviceSize offsets[] = { 0 };
1663 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1664
1665 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1666
1667 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1668
1669 vkCmdEndRenderPass(hCommandBuffer);
1670
1671 vkEndCommandBuffer(hCommandBuffer);
1672
1673 // Submit command buffer
1674
1675 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1676 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1677 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1678 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1679 submitInfo.waitSemaphoreCount = 1;
1680 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1681 submitInfo.pWaitDstStageMask = submitWaitStages;
1682 submitInfo.commandBufferCount = 1;
1683 submitInfo.pCommandBuffers = &hCommandBuffer;
1684 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1685 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1686 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1687
1688 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1689
1690 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1691 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1692 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1693 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1694 presentInfo.swapchainCount = 1;
1695 presentInfo.pSwapchains = swapchains;
1696 presentInfo.pImageIndices = &imageIndex;
1697 presentInfo.pResults = nullptr;
1698 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1699 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1700 {
1701 RecreateSwapChain();
1702 }
1703 else
1704 ERR_GUARD_VULKAN(res);
1705}
1706
1707static void HandlePossibleSizeChange()
1708{
1709 RECT clientRect;
1710 GetClientRect(g_hWnd, &clientRect);
1711 LONG newSizeX = clientRect.right - clientRect.left;
1712 LONG newSizeY = clientRect.bottom - clientRect.top;
1713 if((newSizeX > 0) &&
1714 (newSizeY > 0) &&
1715 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1716 {
1717 g_SizeX = newSizeX;
1718 g_SizeY = newSizeY;
1719
1720 RecreateSwapChain();
1721 }
1722}
1723
1724static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1725{
1726 switch(msg)
1727 {
1728 case WM_CREATE:
1729 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1730 g_hWnd = hWnd;
1731 InitializeApplication();
1732 PrintAllocatorStats();
1733 return 0;
1734
1735 case WM_DESTROY:
1736 FinalizeApplication();
1737 PostQuitMessage(0);
1738 return 0;
1739
1740 // This prevents app from freezing when left Alt is pressed
1741 // (which normally enters modal menu loop).
1742 case WM_SYSKEYDOWN:
1743 case WM_SYSKEYUP:
1744 return 0;
1745
1746 case WM_SIZE:
1747 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1748 HandlePossibleSizeChange();
1749 return 0;
1750
1751 case WM_EXITSIZEMOVE:
1752 HandlePossibleSizeChange();
1753 return 0;
1754
1755 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001756 switch(wParam)
1757 {
1758 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001759 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001760 break;
1761 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001762 try
1763 {
1764 Test();
1765 }
1766 catch(const std::exception& ex)
1767 {
1768 printf("ERROR: %s\n", ex.what());
1769 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001770 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001771 case 'S':
1772 try
1773 {
1774 if(g_SparseBindingEnabled)
1775 {
1776 TestSparseBinding();
1777 }
1778 else
1779 {
1780 printf("Sparse binding not supported.\n");
1781 }
1782 }
1783 catch(const std::exception& ex)
1784 {
1785 printf("ERROR: %s\n", ex.what());
1786 }
1787 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001788 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001789 return 0;
1790
1791 default:
1792 break;
1793 }
1794
1795 return DefWindowProc(hWnd, msg, wParam, lParam);
1796}
1797
1798int main()
1799{
1800 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1801
1802 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1803 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1804 wndClassDesc.hbrBackground = NULL;
1805 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1806 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1807 wndClassDesc.hInstance = g_hAppInstance;
1808 wndClassDesc.lpfnWndProc = WndProc;
1809 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1810
1811 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1812 assert(hWndClass);
1813
1814 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1815 const DWORD exStyle = 0;
1816
1817 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1818 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1819
Adam Sawicki86ccd632017-07-04 14:57:53 +02001820 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001821 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1822 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1823 NULL, NULL, g_hAppInstance, NULL);
1824
1825 MSG msg;
1826 for(;;)
1827 {
1828 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1829 {
1830 if(msg.message == WM_QUIT)
1831 break;
1832 TranslateMessage(&msg);
1833 DispatchMessage(&msg);
1834 }
1835 if(g_hDevice != VK_NULL_HANDLE)
1836 DrawFrame();
1837 }
1838
1839 return 0;
1840}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001841
Adam Sawickif1a793c2018-03-13 15:42:22 +01001842#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001843
Adam Sawickif1a793c2018-03-13 15:42:22 +01001844#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001845
1846int main()
1847{
1848}
1849
Adam Sawickif1a793c2018-03-13 15:42:22 +01001850#endif // #ifdef _WIN32