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