blob: 6f0db10927de3b845908f016d3fdcd0fe16b8605 [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawickiae5c4662019-01-02 10:23:35 +01002// Copyright (c) 2017-2019 Advanced Micro Devices, Inc. All rights reserved.
Adam Sawickie6e498f2017-06-16 17:21:31 +02003//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21//
22
Adam Sawickif1a793c2018-03-13 15:42:22 +010023#ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +020024
Adam Sawicki51fa9662018-10-03 13:44:29 +020025#include "SparseBindingTest.h"
Adam Sawickif1a793c2018-03-13 15:42:22 +010026#include "Tests.h"
27#include "VmaUsage.h"
28#include "Common.h"
Adam Sawicki8317ba92019-11-18 13:14:11 +010029#include <atomic>
Adam Sawickie6e498f2017-06-16 17:21:31 +020030
31static const char* const SHADER_PATH1 = "./";
32static const char* const SHADER_PATH2 = "../bin/";
33static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
34static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_LUNARG_standard_validation";
Adam Sawicki6c8b7a22019-03-05 13:40:29 +010035static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.3.0-development";
36static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.3.0-development";
Adam Sawickie6e498f2017-06-16 17:21:31 +020037
38static const bool VSYNC = true;
39static const uint32_t COMMAND_BUFFER_COUNT = 2;
Adam Sawickia68c01c2018-03-13 16:40:45 +010040static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
Adam Sawicki8317ba92019-11-18 13:14:11 +010041static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = true;
Adam Sawickie6e498f2017-06-16 17:21:31 +020042
Adam Sawickib8333fb2018-03-13 16:15:53 +010043VkPhysicalDevice g_hPhysicalDevice;
44VkDevice g_hDevice;
45VmaAllocator g_hAllocator;
46bool g_MemoryAliasingWarningEnabled = true;
47
Adam Sawickia68c01c2018-03-13 16:40:45 +010048static bool g_EnableValidationLayer = true;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010049static bool VK_KHR_get_memory_requirements2_enabled = false;
50static bool VK_KHR_dedicated_allocation_enabled = false;
Adam Sawicki4abe30c2019-07-02 14:37:21 +020051static bool VK_KHR_bind_memory2_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020052bool g_SparseBindingEnabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010053
Adam Sawickie6e498f2017-06-16 17:21:31 +020054static HINSTANCE g_hAppInstance;
55static HWND g_hWnd;
56static LONG g_SizeX = 1280, g_SizeY = 720;
57static VkInstance g_hVulkanInstance;
58static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020059static VkQueue g_hPresentQueue;
60static VkSurfaceFormatKHR g_SurfaceFormat;
61static VkExtent2D g_Extent;
62static VkSwapchainKHR g_hSwapchain;
63static std::vector<VkImage> g_SwapchainImages;
64static std::vector<VkImageView> g_SwapchainImageViews;
65static std::vector<VkFramebuffer> g_Framebuffers;
66static VkCommandPool g_hCommandPool;
67static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
68static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020069VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020070static uint32_t g_NextCommandBufferIndex;
71static VkSemaphore g_hImageAvailableSemaphore;
72static VkSemaphore g_hRenderFinishedSemaphore;
73static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
74static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020075static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020076static VkDescriptorSetLayout g_hDescriptorSetLayout;
77static VkDescriptorPool g_hDescriptorPool;
78static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
79static VkSampler g_hSampler;
80static VkFormat g_DepthFormat;
81static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +020082static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +020083static VkImageView g_hDepthImageView;
84
85static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
86static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
87static std::vector<VkPresentModeKHR> g_PresentModes;
88
89static PFN_vkCreateDebugReportCallbackEXT g_pvkCreateDebugReportCallbackEXT;
90static PFN_vkDebugReportMessageEXT g_pvkDebugReportMessageEXT;
91static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
92static VkDebugReportCallbackEXT g_hCallback;
93
Adam Sawickie6e498f2017-06-16 17:21:31 +020094static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +020095VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +010096VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +020097
98static VkPipelineLayout g_hPipelineLayout;
99static VkRenderPass g_hRenderPass;
100static VkPipeline g_hPipeline;
101
102static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200103static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200104static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200105static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200106static uint32_t g_VertexCount;
107static uint32_t g_IndexCount;
108
109static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200110static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200111static VkImageView g_hTextureImageView;
112
Adam Sawicki8317ba92019-11-18 13:14:11 +0100113static std::atomic_uint32_t g_CpuAllocCount;
114
Adam Sawickia68c01c2018-03-13 16:40:45 +0100115static void* CustomCpuAllocation(
116 void* pUserData, size_t size, size_t alignment,
117 VkSystemAllocationScope allocationScope)
118{
119 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100120 void* const result = _aligned_malloc(size, alignment);
121 if(result)
122 {
123 ++g_CpuAllocCount;
124 }
125 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100126}
127
128static void* CustomCpuReallocation(
129 void* pUserData, void* pOriginal, size_t size, size_t alignment,
130 VkSystemAllocationScope allocationScope)
131{
132 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100133 void* const result = _aligned_realloc(pOriginal, size, alignment);
134 if(pOriginal && !result)
135 {
136 --g_CpuAllocCount;
137 }
138 else if(!pOriginal && result)
139 {
140 ++g_CpuAllocCount;
141 }
142 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100143}
144
145static void CustomCpuFree(void* pUserData, void* pMemory)
146{
147 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100148 if(pMemory)
149 {
150 const uint32_t oldAllocCount = g_CpuAllocCount.fetch_sub(1);
151 TEST(oldAllocCount > 0);
152 _aligned_free(pMemory);
153 }
Adam Sawickia68c01c2018-03-13 16:40:45 +0100154}
155
Adam Sawicki1f84f622019-07-02 13:40:01 +0200156static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
157 CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA, // pUserData
158 &CustomCpuAllocation, // pfnAllocation
159 &CustomCpuReallocation, // pfnReallocation
160 &CustomCpuFree // pfnFree
161};
162
163const VkAllocationCallbacks* g_Allocs;
164
Adam Sawicki978fcf52018-12-05 14:38:48 +0100165void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200166{
167 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
168 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
169 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
170}
171
Adam Sawicki978fcf52018-12-05 14:38:48 +0100172void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200173{
174 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
175
176 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
177 submitInfo.commandBufferCount = 1;
178 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
179
180 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
181 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
182}
183
Adam Sawickida6c1942018-12-05 17:34:34 +0100184void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200185{
186 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
187 if(file.is_open() == false)
188 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
189 assert(file.is_open());
190 size_t fileSize = (size_t)file.tellg();
191 if(fileSize > 0)
192 {
193 out.resize(fileSize);
194 file.seekg(0);
195 file.read(out.data(), fileSize);
196 file.close();
197 }
198 else
199 out.clear();
200}
201
202VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback(
203 VkDebugReportFlagsEXT flags,
204 VkDebugReportObjectTypeEXT objectType,
205 uint64_t object,
206 size_t location,
207 int32_t messageCode,
208 const char* pLayerPrefix,
209 const char* pMessage,
210 void* pUserData)
211{
Adam Sawickib8333fb2018-03-13 16:15:53 +0100212 // "Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug."
213 if(!g_MemoryAliasingWarningEnabled && flags == VK_DEBUG_REPORT_WARNING_BIT_EXT &&
214 (strstr(pMessage, " is aliased with non-linear ") || strstr(pMessage, " is aliased with linear ")))
215 {
216 return VK_FALSE;
217 }
218
219 // Ignoring because when VK_KHR_dedicated_allocation extension is enabled,
220 // vkGetBufferMemoryRequirements2KHR function is used instead, while Validation
221 // Layer seems to be unaware of it.
222 if (strstr(pMessage, "but vkGetBufferMemoryRequirements() has not been called on that buffer") != nullptr)
223 {
224 return VK_FALSE;
225 }
226 if (strstr(pMessage, "but vkGetImageMemoryRequirements() has not been called on that image") != nullptr)
227 {
228 return VK_FALSE;
229 }
Adam Sawicki94e82062018-08-20 11:12:51 +0200230
231 /*
232 "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."
233 Ignoring because we map entire VkDeviceMemory blocks, where different types of
234 images and buffers may end up together, especially on GPUs with unified memory
235 like Intel.
236 */
237 if(strstr(pMessage, "Mapping an image with layout") != nullptr &&
238 strstr(pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr)
239 {
240 return VK_FALSE;
241 }
Adam Sawickib8333fb2018-03-13 16:15:53 +0100242
243 switch(flags)
244 {
245 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
246 SetConsoleColor(CONSOLE_COLOR::WARNING);
247 break;
248 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
249 SetConsoleColor(CONSOLE_COLOR::ERROR_);
250 break;
251 default:
252 SetConsoleColor(CONSOLE_COLOR::INFO);
253 }
254
Adam Sawickie6e498f2017-06-16 17:21:31 +0200255 printf("%s \xBA %s\n", pLayerPrefix, pMessage);
256
Adam Sawickib8333fb2018-03-13 16:15:53 +0100257 SetConsoleColor(CONSOLE_COLOR::NORMAL);
258
259 if(flags == VK_DEBUG_REPORT_WARNING_BIT_EXT ||
260 flags == VK_DEBUG_REPORT_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200261 {
262 OutputDebugStringA(pMessage);
263 OutputDebugStringA("\n");
264 }
265
266 return VK_FALSE;
267}
268
269static VkSurfaceFormatKHR ChooseSurfaceFormat()
270{
271 assert(!g_SurfaceFormats.empty());
272
273 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
274 {
275 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
276 return result;
277 }
278
279 for(const auto& format : g_SurfaceFormats)
280 {
281 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
282 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
283 {
284 return format;
285 }
286 }
287
288 return g_SurfaceFormats[0];
289}
290
291VkPresentModeKHR ChooseSwapPresentMode()
292{
293 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
294
295 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
296 g_PresentModes.end())
297 {
298 return preferredMode;
299 }
300
301 return VK_PRESENT_MODE_FIFO_KHR;
302}
303
304static VkExtent2D ChooseSwapExtent()
305{
306 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
307 return g_SurfaceCapabilities.currentExtent;
308
309 VkExtent2D result = {
310 std::max(g_SurfaceCapabilities.minImageExtent.width,
311 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
312 std::max(g_SurfaceCapabilities.minImageExtent.height,
313 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
314 return result;
315}
316
317struct Vertex
318{
319 float pos[3];
320 float color[3];
321 float texCoord[2];
322};
323
324static void CreateMesh()
325{
326 assert(g_hAllocator);
327
328 static Vertex vertices[] = {
329 // -X
330 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
331 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
332 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
333 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
334 // +X
335 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
336 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
337 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
338 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
339 // -Z
340 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
341 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
342 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
343 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
344 // +Z
345 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
346 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
347 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
348 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
349 // -Y
350 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
351 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
352 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
353 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
354 // +Y
355 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
356 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
357 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
358 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
359 };
360 static uint16_t indices[] = {
361 0, 1, 2, 3, USHRT_MAX,
362 4, 5, 6, 7, USHRT_MAX,
363 8, 9, 10, 11, USHRT_MAX,
364 12, 13, 14, 15, USHRT_MAX,
365 16, 17, 18, 19, USHRT_MAX,
366 20, 21, 22, 23, USHRT_MAX,
367 };
368
369 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
370 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
371 g_IndexCount = (uint32_t)_countof(indices);
372
373 // Create vertex buffer
374
375 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
376 vbInfo.size = vertexBufferSize;
377 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
378 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200379
Adam Sawicki976f9202017-09-12 20:45:14 +0200380 VmaAllocationCreateInfo vbAllocCreateInfo = {};
381 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100382 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200383
Adam Sawicki819860e2017-07-04 14:30:38 +0200384 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
385 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
386 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200387 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200388
389 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200390
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200391 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
392
Adam Sawickie6e498f2017-06-16 17:21:31 +0200393 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200394 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
395 vbAllocCreateInfo.flags = 0;
396 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200397
398 // Create index buffer
399
400 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
401 ibInfo.size = indexBufferSize;
402 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
403 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200404
Adam Sawicki976f9202017-09-12 20:45:14 +0200405 VmaAllocationCreateInfo ibAllocCreateInfo = {};
406 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100407 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200408
Adam Sawickie6e498f2017-06-16 17:21:31 +0200409 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200410 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
411 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200412 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200413
Adam Sawicki819860e2017-07-04 14:30:38 +0200414 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200415
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200416 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
417
Adam Sawickie6e498f2017-06-16 17:21:31 +0200418 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200419 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
420 ibAllocCreateInfo.flags = 0;
421 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200422
423 // Copy buffers
424
425 BeginSingleTimeCommands();
426
427 VkBufferCopy vbCopyRegion = {};
428 vbCopyRegion.srcOffset = 0;
429 vbCopyRegion.dstOffset = 0;
430 vbCopyRegion.size = vbInfo.size;
431 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
432
433 VkBufferCopy ibCopyRegion = {};
434 ibCopyRegion.srcOffset = 0;
435 ibCopyRegion.dstOffset = 0;
436 ibCopyRegion.size = ibInfo.size;
437 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
438
439 EndSingleTimeCommands();
440
Adam Sawicki819860e2017-07-04 14:30:38 +0200441 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
442 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200443}
444
Adam Sawickie6e498f2017-06-16 17:21:31 +0200445static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
446{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100447 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200448
449 const VkDeviceSize imageSize = sizeX * sizeY * 4;
450
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100451 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
452 stagingBufInfo.size = imageSize;
453 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
454
455 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
456 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
457 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200458
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100459 VkBuffer stagingBuf = VK_NULL_HANDLE;
460 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
461 VmaAllocationInfo stagingBufAllocInfo = {};
462 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200463
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100464 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
465 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200466 for(uint32_t y = 0; y < sizeY; ++y)
467 {
468 uint32_t* pPixelData = (uint32_t*)pRowData;
469 for(uint32_t x = 0; x < sizeY; ++x)
470 {
471 *pPixelData =
472 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
473 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
474 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
475 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
476 ++pPixelData;
477 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100478 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200479 }
480
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200481 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
482
Adam Sawicki10844a82017-08-16 17:32:09 +0200483 // Create g_hTextureImage in GPU memory.
484
Adam Sawickie6e498f2017-06-16 17:21:31 +0200485 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
486 imageInfo.imageType = VK_IMAGE_TYPE_2D;
487 imageInfo.extent.width = sizeX;
488 imageInfo.extent.height = sizeY;
489 imageInfo.extent.depth = 1;
490 imageInfo.mipLevels = 1;
491 imageInfo.arrayLayers = 1;
492 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
493 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
494 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
495 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
496 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
497 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
498 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200499
Adam Sawicki976f9202017-09-12 20:45:14 +0200500 VmaAllocationCreateInfo imageAllocCreateInfo = {};
501 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200502
Adam Sawicki976f9202017-09-12 20:45:14 +0200503 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200504
Adam Sawicki10844a82017-08-16 17:32:09 +0200505 // Transition image layouts, copy image.
506
507 BeginSingleTimeCommands();
508
509 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200510 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
511 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200512 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
513 imgMemBarrier.subresourceRange.baseMipLevel = 0;
514 imgMemBarrier.subresourceRange.levelCount = 1;
515 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
516 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200517 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
518 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
519 imgMemBarrier.image = g_hTextureImage;
520 imgMemBarrier.srcAccessMask = 0;
521 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
522
523 vkCmdPipelineBarrier(
524 g_hTemporaryCommandBuffer,
525 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
526 VK_PIPELINE_STAGE_TRANSFER_BIT,
527 0,
528 0, nullptr,
529 0, nullptr,
530 1, &imgMemBarrier);
531
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100532 VkBufferImageCopy region = {};
533 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
534 region.imageSubresource.layerCount = 1;
535 region.imageExtent.width = sizeX;
536 region.imageExtent.height = sizeY;
537 region.imageExtent.depth = 1;
538
539 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200540
541 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
542 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
543 imgMemBarrier.image = g_hTextureImage;
544 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
545 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
546
547 vkCmdPipelineBarrier(
548 g_hTemporaryCommandBuffer,
549 VK_PIPELINE_STAGE_TRANSFER_BIT,
550 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
551 0,
552 0, nullptr,
553 0, nullptr,
554 1, &imgMemBarrier);
555
556 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200557
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100558 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200559
560 // Create ImageView
561
562 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
563 textureImageViewInfo.image = g_hTextureImage;
564 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
565 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
566 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
567 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
568 textureImageViewInfo.subresourceRange.levelCount = 1;
569 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
570 textureImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200571 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200572}
573
574struct UniformBufferObject
575{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200576 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200577};
578
579static void RegisterDebugCallbacks()
580{
581 g_pvkCreateDebugReportCallbackEXT =
582 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
583 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
584 g_pvkDebugReportMessageEXT =
585 reinterpret_cast<PFN_vkDebugReportMessageEXT>
586 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
587 g_pvkDestroyDebugReportCallbackEXT =
588 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
589 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
590 assert(g_pvkCreateDebugReportCallbackEXT);
591 assert(g_pvkDebugReportMessageEXT);
592 assert(g_pvkDestroyDebugReportCallbackEXT);
593
594 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
595 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
596 callbackCreateInfo.pNext = nullptr;
597 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
598 VK_DEBUG_REPORT_ERROR_BIT_EXT |
599 VK_DEBUG_REPORT_WARNING_BIT_EXT |
600 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
601 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
602 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
603 callbackCreateInfo.pUserData = nullptr;
604
Adam Sawicki1f84f622019-07-02 13:40:01 +0200605 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, g_Allocs, &g_hCallback) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200606}
607
608static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
609{
610 const VkLayerProperties* propsEnd = pProps + propCount;
611 return std::find_if(
612 pProps,
613 propsEnd,
614 [pLayerName](const VkLayerProperties& prop) -> bool {
615 return strcmp(pLayerName, prop.layerName) == 0;
616 }) != propsEnd;
617}
618
619static VkFormat FindSupportedFormat(
620 const std::vector<VkFormat>& candidates,
621 VkImageTiling tiling,
622 VkFormatFeatureFlags features)
623{
624 for (VkFormat format : candidates)
625 {
626 VkFormatProperties props;
627 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
628
629 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
630 ((props.linearTilingFeatures & features) == features))
631 {
632 return format;
633 }
634 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
635 ((props.optimalTilingFeatures & features) == features))
636 {
637 return format;
638 }
639 }
640 return VK_FORMAT_UNDEFINED;
641}
642
643static VkFormat FindDepthFormat()
644{
645 std::vector<VkFormat> formats;
646 formats.push_back(VK_FORMAT_D32_SFLOAT);
647 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
648 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
649
650 return FindSupportedFormat(
651 formats,
652 VK_IMAGE_TILING_OPTIMAL,
653 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
654}
655
656static void CreateSwapchain()
657{
658 // Query surface formats.
659
660 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
661
662 uint32_t formatCount = 0;
663 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
664 g_SurfaceFormats.resize(formatCount);
665 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
666
667 uint32_t presentModeCount = 0;
668 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
669 g_PresentModes.resize(presentModeCount);
670 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
671
672 // Create swap chain
673
674 g_SurfaceFormat = ChooseSurfaceFormat();
675 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
676 g_Extent = ChooseSwapExtent();
677
678 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
679 if((g_SurfaceCapabilities.maxImageCount > 0) &&
680 (imageCount > g_SurfaceCapabilities.maxImageCount))
681 {
682 imageCount = g_SurfaceCapabilities.maxImageCount;
683 }
684
685 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
686 swapChainInfo.surface = g_hSurface;
687 swapChainInfo.minImageCount = imageCount;
688 swapChainInfo.imageFormat = g_SurfaceFormat.format;
689 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
690 swapChainInfo.imageExtent = g_Extent;
691 swapChainInfo.imageArrayLayers = 1;
692 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
693 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
694 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
695 swapChainInfo.presentMode = presentMode;
696 swapChainInfo.clipped = VK_TRUE;
697 swapChainInfo.oldSwapchain = g_hSwapchain;
698
699 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
700 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
701 {
702 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
703 swapChainInfo.queueFamilyIndexCount = 2;
704 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
705 }
706 else
707 {
708 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
709 }
710
711 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200712 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, g_Allocs, &hNewSwapchain) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200713 if(g_hSwapchain != VK_NULL_HANDLE)
Adam Sawicki1f84f622019-07-02 13:40:01 +0200714 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200715 g_hSwapchain = hNewSwapchain;
716
717 // Retrieve swapchain images.
718
719 uint32_t swapchainImageCount = 0;
720 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
721 g_SwapchainImages.resize(swapchainImageCount);
722 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
723
724 // Create swapchain image views.
725
726 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +0200727 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200728 g_SwapchainImageViews.clear();
729
730 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
731 g_SwapchainImageViews.resize(swapchainImageCount);
732 for(uint32_t i = 0; i < swapchainImageCount; ++i)
733 {
734 swapchainImageViewInfo.image = g_SwapchainImages[i];
735 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
736 swapchainImageViewInfo.format = g_SurfaceFormat.format;
737 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
738 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
739 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
740 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
741 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
742 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
743 swapchainImageViewInfo.subresourceRange.levelCount = 1;
744 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
745 swapchainImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200746 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200747 }
748
749 // Create depth buffer
750
751 g_DepthFormat = FindDepthFormat();
752 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
753
754 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
755 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
756 depthImageInfo.extent.width = g_Extent.width;
757 depthImageInfo.extent.height = g_Extent.height;
758 depthImageInfo.extent.depth = 1;
759 depthImageInfo.mipLevels = 1;
760 depthImageInfo.arrayLayers = 1;
761 depthImageInfo.format = g_DepthFormat;
762 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
763 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
764 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
765 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
766 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
767 depthImageInfo.flags = 0;
768
Adam Sawicki976f9202017-09-12 20:45:14 +0200769 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
770 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200771
Adam Sawicki976f9202017-09-12 20:45:14 +0200772 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200773
774 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
775 depthImageViewInfo.image = g_hDepthImage;
776 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
777 depthImageViewInfo.format = g_DepthFormat;
778 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
779 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
780 depthImageViewInfo.subresourceRange.levelCount = 1;
781 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
782 depthImageViewInfo.subresourceRange.layerCount = 1;
783
Adam Sawicki1f84f622019-07-02 13:40:01 +0200784 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200785
Adam Sawickie6e498f2017-06-16 17:21:31 +0200786 // Create pipeline layout
787 {
788 if(g_hPipelineLayout != VK_NULL_HANDLE)
789 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200790 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200791 g_hPipelineLayout = VK_NULL_HANDLE;
792 }
793
794 VkPushConstantRange pushConstantRanges[1];
795 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
796 pushConstantRanges[0].offset = 0;
797 pushConstantRanges[0].size = sizeof(UniformBufferObject);
798 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
799
800 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
801 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
802 pipelineLayoutInfo.setLayoutCount = 1;
803 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
804 pipelineLayoutInfo.pushConstantRangeCount = 1;
805 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200806 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200807 }
808
809 // Create render pass
810 {
811 if(g_hRenderPass != VK_NULL_HANDLE)
812 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200813 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200814 g_hRenderPass = VK_NULL_HANDLE;
815 }
816
817 VkAttachmentDescription attachments[2];
818 ZeroMemory(attachments, sizeof(attachments));
819
820 attachments[0].format = g_SurfaceFormat.format;
821 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
822 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
823 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
824 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
825 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100826 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200827 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
828
829 attachments[1].format = g_DepthFormat;
830 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
831 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
832 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
833 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
834 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100835 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200836 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
837
838 VkAttachmentReference colorAttachmentRef = {};
839 colorAttachmentRef.attachment = 0;
840 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
841
842 VkAttachmentReference depthStencilAttachmentRef = {};
843 depthStencilAttachmentRef.attachment = 1;
844 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
845
846 VkSubpassDescription subpassDesc = {};
847 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
848 subpassDesc.colorAttachmentCount = 1;
849 subpassDesc.pColorAttachments = &colorAttachmentRef;
850 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
851
Adam Sawickie6e498f2017-06-16 17:21:31 +0200852 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
853 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
854 renderPassInfo.pAttachments = attachments;
855 renderPassInfo.subpassCount = 1;
856 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200857 renderPassInfo.dependencyCount = 0;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200858 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200859 }
860
861 // Create pipeline
862 {
863 std::vector<char> vertShaderCode;
864 LoadShader(vertShaderCode, "Shader.vert.spv");
865 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
866 shaderModuleInfo.codeSize = vertShaderCode.size();
867 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
868 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200869 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200870
871 std::vector<char> hFragShaderCode;
872 LoadShader(hFragShaderCode, "Shader.frag.spv");
873 shaderModuleInfo.codeSize = hFragShaderCode.size();
874 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
875 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200876 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200877
878 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
879 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
880 vertPipelineShaderStageInfo.module = hVertShaderModule;
881 vertPipelineShaderStageInfo.pName = "main";
882
883 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
884 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
885 fragPipelineShaderStageInfo.module = fragShaderModule;
886 fragPipelineShaderStageInfo.pName = "main";
887
888 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
889 vertPipelineShaderStageInfo,
890 fragPipelineShaderStageInfo
891 };
892
893 VkVertexInputBindingDescription bindingDescription = {};
894 bindingDescription.binding = 0;
895 bindingDescription.stride = sizeof(Vertex);
896 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
897
898 VkVertexInputAttributeDescription attributeDescriptions[3];
899 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
900
901 attributeDescriptions[0].binding = 0;
902 attributeDescriptions[0].location = 0;
903 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
904 attributeDescriptions[0].offset = offsetof(Vertex, pos);
905
906 attributeDescriptions[1].binding = 0;
907 attributeDescriptions[1].location = 1;
908 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
909 attributeDescriptions[1].offset = offsetof(Vertex, color);
910
911 attributeDescriptions[2].binding = 0;
912 attributeDescriptions[2].location = 2;
913 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
914 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
915
916 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
917 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
918 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
919 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
920 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
921
922 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
923 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
924 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
925
926 VkViewport viewport = {};
927 viewport.x = 0.f;
928 viewport.y = 0.f;
929 viewport.width = (float)g_Extent.width;
930 viewport.height = (float)g_Extent.height;
931 viewport.minDepth = 0.f;
932 viewport.maxDepth = 1.f;
933
934 VkRect2D scissor = {};
935 scissor.offset.x = 0;
936 scissor.offset.y = 0;
937 scissor.extent = g_Extent;
938
939 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
940 pipelineViewportStateInfo.viewportCount = 1;
941 pipelineViewportStateInfo.pViewports = &viewport;
942 pipelineViewportStateInfo.scissorCount = 1;
943 pipelineViewportStateInfo.pScissors = &scissor;
944
945 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
946 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
947 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
948 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
949 pipelineRasterizationStateInfo.lineWidth = 1.f;
950 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
951 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
952 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
953 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
954 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
955 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
956
957 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
958 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
959 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
960 pipelineMultisampleStateInfo.minSampleShading = 1.f;
961 pipelineMultisampleStateInfo.pSampleMask = nullptr;
962 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
963 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
964
965 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
966 pipelineColorBlendAttachmentState.colorWriteMask =
967 VK_COLOR_COMPONENT_R_BIT |
968 VK_COLOR_COMPONENT_G_BIT |
969 VK_COLOR_COMPONENT_B_BIT |
970 VK_COLOR_COMPONENT_A_BIT;
971 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
972 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
973 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
974 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
975 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
976 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
977 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
978
979 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
980 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
981 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
982 pipelineColorBlendStateInfo.attachmentCount = 1;
983 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
984
985 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
986 depthStencilStateInfo.depthTestEnable = VK_TRUE;
987 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
988 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
989 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
990 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
991
992 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
993 pipelineInfo.stageCount = 2;
994 pipelineInfo.pStages = pipelineShaderStageInfos;
995 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
996 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
997 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
998 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
999 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
1000 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
1001 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
1002 pipelineInfo.pDynamicState = nullptr;
1003 pipelineInfo.layout = g_hPipelineLayout;
1004 pipelineInfo.renderPass = g_hRenderPass;
1005 pipelineInfo.subpass = 0;
1006 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
1007 pipelineInfo.basePipelineIndex = -1;
1008 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
1009 g_hDevice,
1010 VK_NULL_HANDLE,
1011 1,
Adam Sawicki1f84f622019-07-02 13:40:01 +02001012 &pipelineInfo,
1013 g_Allocs,
Adam Sawickie6e498f2017-06-16 17:21:31 +02001014 &g_hPipeline) );
1015
Adam Sawicki1f84f622019-07-02 13:40:01 +02001016 vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
1017 vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001018 }
1019
1020 // Create frambuffers
1021
1022 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001023 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001024 g_Framebuffers.clear();
1025
1026 g_Framebuffers.resize(g_SwapchainImageViews.size());
1027 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1028 {
1029 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1030
1031 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1032 framebufferInfo.renderPass = g_hRenderPass;
1033 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1034 framebufferInfo.pAttachments = attachments;
1035 framebufferInfo.width = g_Extent.width;
1036 framebufferInfo.height = g_Extent.height;
1037 framebufferInfo.layers = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001038 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001039 }
1040
1041 // Create semaphores
1042
1043 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1044 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001045 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001046 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1047 }
1048 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1049 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001050 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001051 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1052 }
1053
1054 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
Adam Sawicki1f84f622019-07-02 13:40:01 +02001055 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
1056 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001057}
1058
1059static void DestroySwapchain(bool destroyActualSwapchain)
1060{
1061 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1062 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001063 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001064 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1065 }
1066 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1067 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001068 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001069 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1070 }
1071
1072 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001073 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001074 g_Framebuffers.clear();
1075
1076 if(g_hDepthImageView != VK_NULL_HANDLE)
1077 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001078 vkDestroyImageView(g_hDevice, g_hDepthImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001079 g_hDepthImageView = VK_NULL_HANDLE;
1080 }
1081 if(g_hDepthImage != VK_NULL_HANDLE)
1082 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001083 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001084 g_hDepthImage = VK_NULL_HANDLE;
1085 }
1086
1087 if(g_hPipeline != VK_NULL_HANDLE)
1088 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001089 vkDestroyPipeline(g_hDevice, g_hPipeline, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001090 g_hPipeline = VK_NULL_HANDLE;
1091 }
1092
1093 if(g_hRenderPass != VK_NULL_HANDLE)
1094 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001095 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001096 g_hRenderPass = VK_NULL_HANDLE;
1097 }
1098
1099 if(g_hPipelineLayout != VK_NULL_HANDLE)
1100 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001101 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001102 g_hPipelineLayout = VK_NULL_HANDLE;
1103 }
1104
1105 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001106 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001107 g_SwapchainImageViews.clear();
1108
1109 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1110 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001111 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001112 g_hSwapchain = VK_NULL_HANDLE;
1113 }
1114}
1115
1116static void InitializeApplication()
1117{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001118 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1119 {
1120 g_Allocs = &g_CpuAllocationCallbacks;
1121 }
1122
Adam Sawickie6e498f2017-06-16 17:21:31 +02001123 uint32_t instanceLayerPropCount = 0;
1124 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1125 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1126 if(instanceLayerPropCount > 0)
1127 {
1128 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1129 }
1130
1131 if(g_EnableValidationLayer == true)
1132 {
1133 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1134 {
1135 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1136 g_EnableValidationLayer = false;
1137 }
1138 }
1139
1140 std::vector<const char*> instanceExtensions;
1141 instanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1142 instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
1143
1144 std::vector<const char*> instanceLayers;
1145 if(g_EnableValidationLayer == true)
1146 {
1147 instanceLayers.push_back(VALIDATION_LAYER_NAME);
1148 instanceExtensions.push_back("VK_EXT_debug_report");
1149 }
1150
1151 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1152 appInfo.pApplicationName = APP_TITLE_A;
1153 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1154 appInfo.pEngineName = "Adam Sawicki Engine";
1155 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
1156 appInfo.apiVersion = VK_API_VERSION_1_0;
1157
1158 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1159 instInfo.pApplicationInfo = &appInfo;
1160 instInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
1161 instInfo.ppEnabledExtensionNames = instanceExtensions.data();
1162 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1163 instInfo.ppEnabledLayerNames = instanceLayers.data();
1164
Adam Sawicki1f84f622019-07-02 13:40:01 +02001165 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001166
1167 // Create VkSurfaceKHR.
1168 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1169 surfaceInfo.hinstance = g_hAppInstance;
1170 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001171 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001172 assert(result == VK_SUCCESS);
1173
1174 if(g_EnableValidationLayer == true)
1175 RegisterDebugCallbacks();
1176
1177 // Find physical device
1178
1179 uint32_t deviceCount = 0;
1180 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1181 assert(deviceCount > 0);
1182
1183 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1184 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1185
1186 g_hPhysicalDevice = physicalDevices[0];
1187
1188 // Query for features
1189
1190 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1191 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1192
Adam Sawicki51fa9662018-10-03 13:44:29 +02001193 VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
1194 vkGetPhysicalDeviceFeatures(g_hPhysicalDevice, &physicalDeviceFeatures);
1195
1196 g_SparseBindingEnabled = physicalDeviceFeatures.sparseBinding != 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001197
1198 // Find queue family index
1199
1200 uint32_t queueFamilyCount = 0;
1201 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1202 assert(queueFamilyCount > 0);
1203 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1204 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1205 for(uint32_t i = 0;
1206 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001207 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1208 g_PresentQueueFamilyIndex == UINT_MAX ||
1209 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001210 ++i)
1211 {
1212 if(queueFamilies[i].queueCount > 0)
1213 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001214 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001215 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001216 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001217 {
1218 g_GraphicsQueueFamilyIndex = i;
1219 }
1220
1221 VkBool32 surfaceSupported = 0;
1222 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1223 if((res >= 0) && (surfaceSupported == VK_TRUE))
1224 {
1225 g_PresentQueueFamilyIndex = i;
1226 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001227
1228 if(g_SparseBindingEnabled &&
1229 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1230 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1231 {
1232 g_SparseBindingQueueFamilyIndex = i;
1233 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001234 }
1235 }
1236 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1237
Adam Sawicki51fa9662018-10-03 13:44:29 +02001238 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1239
Adam Sawickie6e498f2017-06-16 17:21:31 +02001240 // Create logical device
1241
1242 const float queuePriority = 1.f;
1243
Adam Sawicki51fa9662018-10-03 13:44:29 +02001244 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1245 uint32_t queueCount = 1;
1246 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1247 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1248 queueCreateInfo[0].queueCount = 1;
1249 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1250
1251 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1252 {
1253
1254 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1255 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1256 queueCreateInfo[queueCount].queueCount = 1;
1257 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1258 ++queueCount;
1259 }
1260
1261 if(g_SparseBindingEnabled &&
1262 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1263 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1264 {
1265
1266 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1267 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1268 queueCreateInfo[queueCount].queueCount = 1;
1269 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1270 ++queueCount;
1271 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001272
1273 VkPhysicalDeviceFeatures deviceFeatures = {};
Adam Sawicki51fa9662018-10-03 13:44:29 +02001274 //deviceFeatures.fillModeNonSolid = VK_TRUE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001275 deviceFeatures.samplerAnisotropy = VK_TRUE;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001276 deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001277
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001278 // Determine list of device extensions to enable.
Adam Sawickie6e498f2017-06-16 17:21:31 +02001279 std::vector<const char*> enabledDeviceExtensions;
1280 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001281 {
1282 uint32_t propertyCount = 0;
1283 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, nullptr) );
1284
1285 if(propertyCount)
1286 {
1287 std::vector<VkExtensionProperties> properties{propertyCount};
1288 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, properties.data()) );
1289
1290 for(uint32_t i = 0; i < propertyCount; ++i)
1291 {
1292 if(strcmp(properties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1293 {
1294 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1295 VK_KHR_get_memory_requirements2_enabled = true;
1296 }
1297 else if(strcmp(properties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1298 {
1299 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1300 VK_KHR_dedicated_allocation_enabled = true;
1301 }
Adam Sawicki4abe30c2019-07-02 14:37:21 +02001302 else if(strcmp(properties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
1303 {
1304 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1305 VK_KHR_bind_memory2_enabled = true;
1306 }
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001307 }
1308 }
1309 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001310
1311 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1312 deviceCreateInfo.enabledLayerCount = 0;
1313 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1314 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001315 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001316 deviceCreateInfo.queueCreateInfoCount = queueCount;
1317 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001318 deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
1319
Adam Sawicki1f84f622019-07-02 13:40:01 +02001320 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001321
1322 // Create memory allocator
1323
1324 VmaAllocatorCreateInfo allocatorInfo = {};
1325 allocatorInfo.physicalDevice = g_hPhysicalDevice;
1326 allocatorInfo.device = g_hDevice;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001327
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001328 if(VK_KHR_dedicated_allocation_enabled)
1329 {
Adam Sawickif48896d2019-04-16 12:55:35 +02001330 /*
1331 Comment out this line to make the app working with RenderDoc.
Adam Sawicki4fb254e2019-04-23 11:29:57 +02001332
1333 Currently there is a problem with compatibility of this app with RenderDoc due
1334 to a known bug in Vulkan validation layers:
Adam Sawickif48896d2019-04-16 12:55:35 +02001335
Adam Sawicki4fb254e2019-04-23 11:29:57 +02001336 https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/579
1337
1338 It occurs because this app uses Vulkan 1.0 and VK_KHR_dedicated_allocation
1339 extension instead of equivalent functionality embedded into Vulkan 1.1.
Adam Sawickif48896d2019-04-16 12:55:35 +02001340 */
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001341 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1342 }
Adam Sawicki4abe30c2019-07-02 14:37:21 +02001343 if(VK_KHR_bind_memory2_enabled)
1344 {
1345 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
1346 }
Adam Sawickia68c01c2018-03-13 16:40:45 +01001347
Adam Sawickia68c01c2018-03-13 16:40:45 +01001348 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1349 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001350 allocatorInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001351 }
1352
Adam Sawickib0c36362018-11-13 16:17:38 +01001353 // Uncomment to enable recording to CSV file.
1354 /*
1355 {
1356 VmaRecordSettings recordSettings = {};
1357 recordSettings.pFilePath = "VulkanSample.csv";
1358 allocatorInfo.pRecordSettings = &recordSettings;
1359 }
1360 */
1361
Adam Sawickie6e498f2017-06-16 17:21:31 +02001362 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1363
Adam Sawicki51fa9662018-10-03 13:44:29 +02001364 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001365
1366 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1367 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1368 assert(g_hGraphicsQueue);
1369 assert(g_hPresentQueue);
1370
Adam Sawicki51fa9662018-10-03 13:44:29 +02001371 if(g_SparseBindingEnabled)
1372 {
1373 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1374 assert(g_hSparseBindingQueue);
1375 }
1376
Adam Sawickie6e498f2017-06-16 17:21:31 +02001377 // Create command pool
1378
1379 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1380 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1381 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001382 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001383
1384 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1385 commandBufferInfo.commandPool = g_hCommandPool;
1386 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1387 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1388 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1389
1390 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1391 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1392 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1393 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001394 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001395 }
1396
Adam Sawicki1f84f622019-07-02 13:40:01 +02001397 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001398
Adam Sawickie6e498f2017-06-16 17:21:31 +02001399 commandBufferInfo.commandBufferCount = 1;
1400 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1401
1402 // Create texture sampler
1403
1404 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1405 samplerInfo.magFilter = VK_FILTER_LINEAR;
1406 samplerInfo.minFilter = VK_FILTER_LINEAR;
1407 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1408 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1409 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1410 samplerInfo.anisotropyEnable = VK_TRUE;
1411 samplerInfo.maxAnisotropy = 16;
1412 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1413 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1414 samplerInfo.compareEnable = VK_FALSE;
1415 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1416 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1417 samplerInfo.mipLodBias = 0.f;
1418 samplerInfo.minLod = 0.f;
1419 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001420 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001421
1422 CreateTexture(128, 128);
1423 CreateMesh();
1424
1425 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1426 samplerLayoutBinding.binding = 1;
1427 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1428 samplerLayoutBinding.descriptorCount = 1;
1429 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1430
1431 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1432 descriptorSetLayoutInfo.bindingCount = 1;
1433 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001434 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001435
1436 // Create descriptor pool
1437
1438 VkDescriptorPoolSize descriptorPoolSizes[2];
1439 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1440 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1441 descriptorPoolSizes[0].descriptorCount = 1;
1442 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1443 descriptorPoolSizes[1].descriptorCount = 1;
1444
1445 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1446 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1447 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1448 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001449 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001450
1451 // Create descriptor set layout
1452
1453 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1454 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1455 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1456 descriptorSetInfo.descriptorSetCount = 1;
1457 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1458 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1459
1460 VkDescriptorImageInfo descriptorImageInfo = {};
1461 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1462 descriptorImageInfo.imageView = g_hTextureImageView;
1463 descriptorImageInfo.sampler = g_hSampler;
1464
1465 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1466 writeDescriptorSet.dstSet = g_hDescriptorSet;
1467 writeDescriptorSet.dstBinding = 1;
1468 writeDescriptorSet.dstArrayElement = 0;
1469 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1470 writeDescriptorSet.descriptorCount = 1;
1471 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1472
1473 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1474
1475 CreateSwapchain();
1476}
1477
1478static void FinalizeApplication()
1479{
1480 vkDeviceWaitIdle(g_hDevice);
1481
1482 DestroySwapchain(true);
1483
1484 if(g_hDescriptorPool != VK_NULL_HANDLE)
1485 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001486 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001487 g_hDescriptorPool = VK_NULL_HANDLE;
1488 }
1489
1490 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1491 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001492 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001493 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1494 }
1495
1496 if(g_hTextureImageView != VK_NULL_HANDLE)
1497 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001498 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001499 g_hTextureImageView = VK_NULL_HANDLE;
1500 }
1501 if(g_hTextureImage != VK_NULL_HANDLE)
1502 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001503 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001504 g_hTextureImage = VK_NULL_HANDLE;
1505 }
1506
1507 if(g_hIndexBuffer != VK_NULL_HANDLE)
1508 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001509 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001510 g_hIndexBuffer = VK_NULL_HANDLE;
1511 }
1512 if(g_hVertexBuffer != VK_NULL_HANDLE)
1513 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001514 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001515 g_hVertexBuffer = VK_NULL_HANDLE;
1516 }
1517
1518 if(g_hSampler != VK_NULL_HANDLE)
1519 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001520 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001521 g_hSampler = VK_NULL_HANDLE;
1522 }
1523
Adam Sawicki51fa9662018-10-03 13:44:29 +02001524 if(g_ImmediateFence)
1525 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001526 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001527 g_ImmediateFence = VK_NULL_HANDLE;
1528 }
1529
Adam Sawickie6e498f2017-06-16 17:21:31 +02001530 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1531 {
1532 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1533 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001534 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001535 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1536 }
1537 }
1538 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1539 {
1540 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1541 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1542 }
1543 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1544 {
1545 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1546 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1547 }
1548
1549 if(g_hCommandPool != VK_NULL_HANDLE)
1550 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001551 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001552 g_hCommandPool = VK_NULL_HANDLE;
1553 }
1554
1555 if(g_hAllocator != VK_NULL_HANDLE)
1556 {
1557 vmaDestroyAllocator(g_hAllocator);
1558 g_hAllocator = nullptr;
1559 }
1560
1561 if(g_hDevice != VK_NULL_HANDLE)
1562 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001563 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001564 g_hDevice = nullptr;
1565 }
1566
1567 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1568 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001569 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001570 g_hCallback = VK_NULL_HANDLE;
1571 }
1572
1573 if(g_hSurface != VK_NULL_HANDLE)
1574 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001575 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001576 g_hSurface = VK_NULL_HANDLE;
1577 }
1578
1579 if(g_hVulkanInstance != VK_NULL_HANDLE)
1580 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001581 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001582 g_hVulkanInstance = VK_NULL_HANDLE;
1583 }
1584}
1585
1586static void PrintAllocatorStats()
1587{
1588#if VMA_STATS_STRING_ENABLED
1589 char* statsString = nullptr;
1590 vmaBuildStatsString(g_hAllocator, &statsString, true);
1591 printf("%s\n", statsString);
1592 vmaFreeStatsString(g_hAllocator, statsString);
1593#endif
1594}
1595
1596static void RecreateSwapChain()
1597{
1598 vkDeviceWaitIdle(g_hDevice);
1599 DestroySwapchain(false);
1600 CreateSwapchain();
1601}
1602
1603static void DrawFrame()
1604{
1605 // Begin main command buffer
1606 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1607 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1608 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1609
1610 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1611 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1612
1613 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1614 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1615 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1616
1617 // Acquire swapchain image
1618 uint32_t imageIndex = 0;
1619 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1620 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1621 {
1622 RecreateSwapChain();
1623 return;
1624 }
1625 else if(res < 0)
1626 {
1627 ERR_GUARD_VULKAN(res);
1628 }
1629
1630 // Record geometry pass
1631
1632 VkClearValue clearValues[2];
1633 ZeroMemory(clearValues, sizeof(clearValues));
1634 clearValues[0].color.float32[0] = 0.25f;
1635 clearValues[0].color.float32[1] = 0.25f;
1636 clearValues[0].color.float32[2] = 0.5f;
1637 clearValues[0].color.float32[3] = 1.0f;
1638 clearValues[1].depthStencil.depth = 1.0f;
1639
1640 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1641 renderPassBeginInfo.renderPass = g_hRenderPass;
1642 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1643 renderPassBeginInfo.renderArea.offset.x = 0;
1644 renderPassBeginInfo.renderArea.offset.y = 0;
1645 renderPassBeginInfo.renderArea.extent = g_Extent;
1646 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1647 renderPassBeginInfo.pClearValues = clearValues;
1648 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1649
1650 vkCmdBindPipeline(
1651 hCommandBuffer,
1652 VK_PIPELINE_BIND_POINT_GRAPHICS,
1653 g_hPipeline);
1654
Adam Sawicki82c3f332018-06-11 15:27:33 +02001655 mat4 view = mat4::LookAt(
1656 vec3(0.f, 0.f, 0.f),
1657 vec3(0.f, -2.f, 4.f),
1658 vec3(0.f, 1.f, 0.f));
1659 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001660 1.0471975511966f, // 60 degrees
1661 (float)g_Extent.width / (float)g_Extent.height,
1662 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001663 1000.f);
1664 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001665
1666 vkCmdBindDescriptorSets(
1667 hCommandBuffer,
1668 VK_PIPELINE_BIND_POINT_GRAPHICS,
1669 g_hPipelineLayout,
1670 0,
1671 1,
1672 &g_hDescriptorSet,
1673 0,
1674 nullptr);
1675
Adam Sawicki82c3f332018-06-11 15:27:33 +02001676 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1677 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001678
1679 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001680 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001681 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1682
1683 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1684 VkDeviceSize offsets[] = { 0 };
1685 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1686
1687 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1688
1689 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1690
1691 vkCmdEndRenderPass(hCommandBuffer);
1692
1693 vkEndCommandBuffer(hCommandBuffer);
1694
1695 // Submit command buffer
1696
1697 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1698 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1699 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1700 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1701 submitInfo.waitSemaphoreCount = 1;
1702 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1703 submitInfo.pWaitDstStageMask = submitWaitStages;
1704 submitInfo.commandBufferCount = 1;
1705 submitInfo.pCommandBuffers = &hCommandBuffer;
1706 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1707 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1708 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1709
1710 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1711
1712 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1713 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1714 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1715 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1716 presentInfo.swapchainCount = 1;
1717 presentInfo.pSwapchains = swapchains;
1718 presentInfo.pImageIndices = &imageIndex;
1719 presentInfo.pResults = nullptr;
1720 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1721 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1722 {
1723 RecreateSwapChain();
1724 }
1725 else
1726 ERR_GUARD_VULKAN(res);
1727}
1728
1729static void HandlePossibleSizeChange()
1730{
1731 RECT clientRect;
1732 GetClientRect(g_hWnd, &clientRect);
1733 LONG newSizeX = clientRect.right - clientRect.left;
1734 LONG newSizeY = clientRect.bottom - clientRect.top;
1735 if((newSizeX > 0) &&
1736 (newSizeY > 0) &&
1737 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1738 {
1739 g_SizeX = newSizeX;
1740 g_SizeY = newSizeY;
1741
1742 RecreateSwapChain();
1743 }
1744}
1745
1746static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1747{
1748 switch(msg)
1749 {
1750 case WM_CREATE:
1751 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1752 g_hWnd = hWnd;
1753 InitializeApplication();
1754 PrintAllocatorStats();
1755 return 0;
1756
1757 case WM_DESTROY:
1758 FinalizeApplication();
1759 PostQuitMessage(0);
1760 return 0;
1761
1762 // This prevents app from freezing when left Alt is pressed
1763 // (which normally enters modal menu loop).
1764 case WM_SYSKEYDOWN:
1765 case WM_SYSKEYUP:
1766 return 0;
1767
1768 case WM_SIZE:
1769 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1770 HandlePossibleSizeChange();
1771 return 0;
1772
1773 case WM_EXITSIZEMOVE:
1774 HandlePossibleSizeChange();
1775 return 0;
1776
1777 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001778 switch(wParam)
1779 {
1780 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001781 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001782 break;
1783 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001784 try
1785 {
1786 Test();
1787 }
1788 catch(const std::exception& ex)
1789 {
1790 printf("ERROR: %s\n", ex.what());
1791 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001792 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001793 case 'S':
1794 try
1795 {
1796 if(g_SparseBindingEnabled)
1797 {
1798 TestSparseBinding();
1799 }
1800 else
1801 {
1802 printf("Sparse binding not supported.\n");
1803 }
1804 }
1805 catch(const std::exception& ex)
1806 {
1807 printf("ERROR: %s\n", ex.what());
1808 }
1809 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001810 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001811 return 0;
1812
1813 default:
1814 break;
1815 }
1816
1817 return DefWindowProc(hWnd, msg, wParam, lParam);
1818}
1819
1820int main()
1821{
1822 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1823
1824 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1825 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1826 wndClassDesc.hbrBackground = NULL;
1827 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1828 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1829 wndClassDesc.hInstance = g_hAppInstance;
1830 wndClassDesc.lpfnWndProc = WndProc;
1831 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1832
1833 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1834 assert(hWndClass);
1835
1836 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1837 const DWORD exStyle = 0;
1838
1839 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1840 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1841
Adam Sawicki86ccd632017-07-04 14:57:53 +02001842 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001843 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1844 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1845 NULL, NULL, g_hAppInstance, NULL);
1846
1847 MSG msg;
1848 for(;;)
1849 {
1850 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1851 {
1852 if(msg.message == WM_QUIT)
1853 break;
1854 TranslateMessage(&msg);
1855 DispatchMessage(&msg);
1856 }
1857 if(g_hDevice != VK_NULL_HANDLE)
1858 DrawFrame();
1859 }
1860
Adam Sawicki8317ba92019-11-18 13:14:11 +01001861 TEST(g_CpuAllocCount.load() == 0);
1862
Adam Sawickie6e498f2017-06-16 17:21:31 +02001863 return 0;
1864}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001865
Adam Sawickif1a793c2018-03-13 15:42:22 +01001866#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001867
Adam Sawickif1a793c2018-03-13 15:42:22 +01001868#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001869
1870int main()
1871{
1872}
1873
Adam Sawickif1a793c2018-03-13 15:42:22 +01001874#endif // #ifdef _WIN32