blob: ccab048a195a93df2e3fcb2c7748fb298522ca1c [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawicki50882502020-02-07 16:51:31 +01002// Copyright (c) 2017-2020 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 Sawicki8ef0d202020-03-02 15:43:47 +010035static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.4.0";
36static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.4.0";
Adam Sawickie6e498f2017-06-16 17:21:31 +020037
38static const bool VSYNC = true;
39static const uint32_t COMMAND_BUFFER_COUNT = 2;
Adam Sawickia68c01c2018-03-13 16:40:45 +010040static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
Adam Sawicki8317ba92019-11-18 13:14:11 +010041static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = true;
Adam Sawickie6e498f2017-06-16 17:21:31 +020042
Adam Sawickib8333fb2018-03-13 16:15:53 +010043VkPhysicalDevice g_hPhysicalDevice;
44VkDevice g_hDevice;
45VmaAllocator g_hAllocator;
Adam Sawicki4ac8ff82019-11-18 14:47:33 +010046VkInstance g_hVulkanInstance;
Adam Sawickib8333fb2018-03-13 16:15:53 +010047bool g_MemoryAliasingWarningEnabled = true;
48
Adam Sawicki50882502020-02-07 16:51:31 +010049bool g_EnableValidationLayer = true;
50bool VK_KHR_get_memory_requirements2_enabled = false;
51bool VK_KHR_get_physical_device_properties2_enabled = false;
52bool VK_KHR_dedicated_allocation_enabled = false;
53bool VK_KHR_bind_memory2_enabled = false;
54bool VK_EXT_memory_budget_enabled = false;
55bool VK_AMD_device_coherent_memory_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020056bool g_SparseBindingEnabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010057
Adam Sawickie6e498f2017-06-16 17:21:31 +020058static HINSTANCE g_hAppInstance;
59static HWND g_hWnd;
60static LONG g_SizeX = 1280, g_SizeY = 720;
Adam Sawickie6e498f2017-06-16 17:21:31 +020061static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020062static VkQueue g_hPresentQueue;
63static VkSurfaceFormatKHR g_SurfaceFormat;
64static VkExtent2D g_Extent;
65static VkSwapchainKHR g_hSwapchain;
66static std::vector<VkImage> g_SwapchainImages;
67static std::vector<VkImageView> g_SwapchainImageViews;
68static std::vector<VkFramebuffer> g_Framebuffers;
69static VkCommandPool g_hCommandPool;
70static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
71static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020072VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020073static uint32_t g_NextCommandBufferIndex;
74static VkSemaphore g_hImageAvailableSemaphore;
75static VkSemaphore g_hRenderFinishedSemaphore;
76static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
77static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020078static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020079static VkDescriptorSetLayout g_hDescriptorSetLayout;
80static VkDescriptorPool g_hDescriptorPool;
81static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
82static VkSampler g_hSampler;
83static VkFormat g_DepthFormat;
84static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +020085static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +020086static VkImageView g_hDepthImageView;
87
88static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
89static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
90static std::vector<VkPresentModeKHR> g_PresentModes;
91
92static PFN_vkCreateDebugReportCallbackEXT g_pvkCreateDebugReportCallbackEXT;
93static PFN_vkDebugReportMessageEXT g_pvkDebugReportMessageEXT;
94static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
95static VkDebugReportCallbackEXT g_hCallback;
96
Adam Sawickie6e498f2017-06-16 17:21:31 +020097static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +020098VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +010099VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200100
101static VkPipelineLayout g_hPipelineLayout;
102static VkRenderPass g_hRenderPass;
103static VkPipeline g_hPipeline;
104
105static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200106static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200107static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200108static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200109static uint32_t g_VertexCount;
110static uint32_t g_IndexCount;
111
112static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200113static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200114static VkImageView g_hTextureImageView;
115
Adam Sawicki8317ba92019-11-18 13:14:11 +0100116static std::atomic_uint32_t g_CpuAllocCount;
117
Adam Sawickia68c01c2018-03-13 16:40:45 +0100118static void* CustomCpuAllocation(
119 void* pUserData, size_t size, size_t alignment,
120 VkSystemAllocationScope allocationScope)
121{
122 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100123 void* const result = _aligned_malloc(size, alignment);
124 if(result)
125 {
126 ++g_CpuAllocCount;
127 }
128 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100129}
130
131static void* CustomCpuReallocation(
132 void* pUserData, void* pOriginal, size_t size, size_t alignment,
133 VkSystemAllocationScope allocationScope)
134{
135 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100136 void* const result = _aligned_realloc(pOriginal, size, alignment);
137 if(pOriginal && !result)
138 {
139 --g_CpuAllocCount;
140 }
141 else if(!pOriginal && result)
142 {
143 ++g_CpuAllocCount;
144 }
145 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100146}
147
148static void CustomCpuFree(void* pUserData, void* pMemory)
149{
150 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100151 if(pMemory)
152 {
153 const uint32_t oldAllocCount = g_CpuAllocCount.fetch_sub(1);
154 TEST(oldAllocCount > 0);
155 _aligned_free(pMemory);
156 }
Adam Sawickia68c01c2018-03-13 16:40:45 +0100157}
158
Adam Sawicki1f84f622019-07-02 13:40:01 +0200159static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
160 CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA, // pUserData
161 &CustomCpuAllocation, // pfnAllocation
162 &CustomCpuReallocation, // pfnReallocation
163 &CustomCpuFree // pfnFree
164};
165
166const VkAllocationCallbacks* g_Allocs;
167
Adam Sawicki978fcf52018-12-05 14:38:48 +0100168void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200169{
170 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
171 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
172 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
173}
174
Adam Sawicki978fcf52018-12-05 14:38:48 +0100175void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200176{
177 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
178
179 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
180 submitInfo.commandBufferCount = 1;
181 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
182
183 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
184 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
185}
186
Adam Sawickida6c1942018-12-05 17:34:34 +0100187void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200188{
189 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
190 if(file.is_open() == false)
191 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
192 assert(file.is_open());
193 size_t fileSize = (size_t)file.tellg();
194 if(fileSize > 0)
195 {
196 out.resize(fileSize);
197 file.seekg(0);
198 file.read(out.data(), fileSize);
199 file.close();
200 }
201 else
202 out.clear();
203}
204
205VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback(
206 VkDebugReportFlagsEXT flags,
207 VkDebugReportObjectTypeEXT objectType,
208 uint64_t object,
209 size_t location,
210 int32_t messageCode,
211 const char* pLayerPrefix,
212 const char* pMessage,
213 void* pUserData)
214{
Adam Sawickib8333fb2018-03-13 16:15:53 +0100215 // "Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug."
216 if(!g_MemoryAliasingWarningEnabled && flags == VK_DEBUG_REPORT_WARNING_BIT_EXT &&
217 (strstr(pMessage, " is aliased with non-linear ") || strstr(pMessage, " is aliased with linear ")))
218 {
219 return VK_FALSE;
220 }
221
222 // Ignoring because when VK_KHR_dedicated_allocation extension is enabled,
223 // vkGetBufferMemoryRequirements2KHR function is used instead, while Validation
224 // Layer seems to be unaware of it.
225 if (strstr(pMessage, "but vkGetBufferMemoryRequirements() has not been called on that buffer") != nullptr)
226 {
227 return VK_FALSE;
228 }
229 if (strstr(pMessage, "but vkGetImageMemoryRequirements() has not been called on that image") != nullptr)
230 {
231 return VK_FALSE;
232 }
Adam Sawicki94e82062018-08-20 11:12:51 +0200233
234 /*
235 "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."
236 Ignoring because we map entire VkDeviceMemory blocks, where different types of
237 images and buffers may end up together, especially on GPUs with unified memory
238 like Intel.
239 */
240 if(strstr(pMessage, "Mapping an image with layout") != nullptr &&
241 strstr(pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr)
242 {
243 return VK_FALSE;
244 }
Adam Sawickib8333fb2018-03-13 16:15:53 +0100245
246 switch(flags)
247 {
248 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
249 SetConsoleColor(CONSOLE_COLOR::WARNING);
250 break;
251 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
252 SetConsoleColor(CONSOLE_COLOR::ERROR_);
253 break;
254 default:
255 SetConsoleColor(CONSOLE_COLOR::INFO);
256 }
257
Adam Sawickie6e498f2017-06-16 17:21:31 +0200258 printf("%s \xBA %s\n", pLayerPrefix, pMessage);
259
Adam Sawickib8333fb2018-03-13 16:15:53 +0100260 SetConsoleColor(CONSOLE_COLOR::NORMAL);
261
262 if(flags == VK_DEBUG_REPORT_WARNING_BIT_EXT ||
263 flags == VK_DEBUG_REPORT_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200264 {
265 OutputDebugStringA(pMessage);
266 OutputDebugStringA("\n");
267 }
268
269 return VK_FALSE;
270}
271
272static VkSurfaceFormatKHR ChooseSurfaceFormat()
273{
274 assert(!g_SurfaceFormats.empty());
275
276 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
277 {
278 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
279 return result;
280 }
281
282 for(const auto& format : g_SurfaceFormats)
283 {
284 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
285 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
286 {
287 return format;
288 }
289 }
290
291 return g_SurfaceFormats[0];
292}
293
294VkPresentModeKHR ChooseSwapPresentMode()
295{
296 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
297
298 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
299 g_PresentModes.end())
300 {
301 return preferredMode;
302 }
303
304 return VK_PRESENT_MODE_FIFO_KHR;
305}
306
307static VkExtent2D ChooseSwapExtent()
308{
309 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
310 return g_SurfaceCapabilities.currentExtent;
311
312 VkExtent2D result = {
313 std::max(g_SurfaceCapabilities.minImageExtent.width,
314 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
315 std::max(g_SurfaceCapabilities.minImageExtent.height,
316 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
317 return result;
318}
319
320struct Vertex
321{
322 float pos[3];
323 float color[3];
324 float texCoord[2];
325};
326
327static void CreateMesh()
328{
329 assert(g_hAllocator);
330
331 static Vertex vertices[] = {
332 // -X
333 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
334 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
335 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
336 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
337 // +X
338 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
339 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
340 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
341 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
342 // -Z
343 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
344 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
345 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
346 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
347 // +Z
348 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
349 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
350 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
351 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
352 // -Y
353 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
354 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
355 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
356 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
357 // +Y
358 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
359 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
360 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
361 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
362 };
363 static uint16_t indices[] = {
364 0, 1, 2, 3, USHRT_MAX,
365 4, 5, 6, 7, USHRT_MAX,
366 8, 9, 10, 11, USHRT_MAX,
367 12, 13, 14, 15, USHRT_MAX,
368 16, 17, 18, 19, USHRT_MAX,
369 20, 21, 22, 23, USHRT_MAX,
370 };
371
372 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
373 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
374 g_IndexCount = (uint32_t)_countof(indices);
375
376 // Create vertex buffer
377
378 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
379 vbInfo.size = vertexBufferSize;
380 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
381 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200382
Adam Sawicki976f9202017-09-12 20:45:14 +0200383 VmaAllocationCreateInfo vbAllocCreateInfo = {};
384 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100385 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200386
Adam Sawicki819860e2017-07-04 14:30:38 +0200387 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
388 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
389 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200390 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200391
392 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200393
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200394 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
395
Adam Sawickie6e498f2017-06-16 17:21:31 +0200396 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200397 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
398 vbAllocCreateInfo.flags = 0;
399 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200400
401 // Create index buffer
402
403 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
404 ibInfo.size = indexBufferSize;
405 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
406 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200407
Adam Sawicki976f9202017-09-12 20:45:14 +0200408 VmaAllocationCreateInfo ibAllocCreateInfo = {};
409 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100410 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200411
Adam Sawickie6e498f2017-06-16 17:21:31 +0200412 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200413 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
414 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200415 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200416
Adam Sawicki819860e2017-07-04 14:30:38 +0200417 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200418
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200419 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
420
Adam Sawickie6e498f2017-06-16 17:21:31 +0200421 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200422 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
423 ibAllocCreateInfo.flags = 0;
424 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200425
426 // Copy buffers
427
428 BeginSingleTimeCommands();
429
430 VkBufferCopy vbCopyRegion = {};
431 vbCopyRegion.srcOffset = 0;
432 vbCopyRegion.dstOffset = 0;
433 vbCopyRegion.size = vbInfo.size;
434 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
435
436 VkBufferCopy ibCopyRegion = {};
437 ibCopyRegion.srcOffset = 0;
438 ibCopyRegion.dstOffset = 0;
439 ibCopyRegion.size = ibInfo.size;
440 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
441
442 EndSingleTimeCommands();
443
Adam Sawicki819860e2017-07-04 14:30:38 +0200444 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
445 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200446}
447
Adam Sawickie6e498f2017-06-16 17:21:31 +0200448static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
449{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100450 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200451
452 const VkDeviceSize imageSize = sizeX * sizeY * 4;
453
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100454 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
455 stagingBufInfo.size = imageSize;
456 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
457
458 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
459 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
460 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200461
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100462 VkBuffer stagingBuf = VK_NULL_HANDLE;
463 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
464 VmaAllocationInfo stagingBufAllocInfo = {};
465 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200466
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100467 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
468 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200469 for(uint32_t y = 0; y < sizeY; ++y)
470 {
471 uint32_t* pPixelData = (uint32_t*)pRowData;
472 for(uint32_t x = 0; x < sizeY; ++x)
473 {
474 *pPixelData =
475 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
476 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
477 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
478 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
479 ++pPixelData;
480 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100481 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200482 }
483
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200484 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
485
Adam Sawicki10844a82017-08-16 17:32:09 +0200486 // Create g_hTextureImage in GPU memory.
487
Adam Sawickie6e498f2017-06-16 17:21:31 +0200488 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
489 imageInfo.imageType = VK_IMAGE_TYPE_2D;
490 imageInfo.extent.width = sizeX;
491 imageInfo.extent.height = sizeY;
492 imageInfo.extent.depth = 1;
493 imageInfo.mipLevels = 1;
494 imageInfo.arrayLayers = 1;
495 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
496 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
497 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
498 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
499 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
500 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
501 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200502
Adam Sawicki976f9202017-09-12 20:45:14 +0200503 VmaAllocationCreateInfo imageAllocCreateInfo = {};
504 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200505
Adam Sawicki976f9202017-09-12 20:45:14 +0200506 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200507
Adam Sawicki10844a82017-08-16 17:32:09 +0200508 // Transition image layouts, copy image.
509
510 BeginSingleTimeCommands();
511
512 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200513 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
514 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200515 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
516 imgMemBarrier.subresourceRange.baseMipLevel = 0;
517 imgMemBarrier.subresourceRange.levelCount = 1;
518 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
519 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200520 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
521 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
522 imgMemBarrier.image = g_hTextureImage;
523 imgMemBarrier.srcAccessMask = 0;
524 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
525
526 vkCmdPipelineBarrier(
527 g_hTemporaryCommandBuffer,
528 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
529 VK_PIPELINE_STAGE_TRANSFER_BIT,
530 0,
531 0, nullptr,
532 0, nullptr,
533 1, &imgMemBarrier);
534
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100535 VkBufferImageCopy region = {};
536 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
537 region.imageSubresource.layerCount = 1;
538 region.imageExtent.width = sizeX;
539 region.imageExtent.height = sizeY;
540 region.imageExtent.depth = 1;
541
542 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200543
544 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
545 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
546 imgMemBarrier.image = g_hTextureImage;
547 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
548 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
549
550 vkCmdPipelineBarrier(
551 g_hTemporaryCommandBuffer,
552 VK_PIPELINE_STAGE_TRANSFER_BIT,
553 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
554 0,
555 0, nullptr,
556 0, nullptr,
557 1, &imgMemBarrier);
558
559 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200560
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100561 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200562
563 // Create ImageView
564
565 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
566 textureImageViewInfo.image = g_hTextureImage;
567 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
568 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
569 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
570 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
571 textureImageViewInfo.subresourceRange.levelCount = 1;
572 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
573 textureImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200574 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200575}
576
577struct UniformBufferObject
578{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200579 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200580};
581
582static void RegisterDebugCallbacks()
583{
584 g_pvkCreateDebugReportCallbackEXT =
585 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
586 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
587 g_pvkDebugReportMessageEXT =
588 reinterpret_cast<PFN_vkDebugReportMessageEXT>
589 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
590 g_pvkDestroyDebugReportCallbackEXT =
591 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
592 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
593 assert(g_pvkCreateDebugReportCallbackEXT);
594 assert(g_pvkDebugReportMessageEXT);
595 assert(g_pvkDestroyDebugReportCallbackEXT);
596
597 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
598 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
599 callbackCreateInfo.pNext = nullptr;
600 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
601 VK_DEBUG_REPORT_ERROR_BIT_EXT |
602 VK_DEBUG_REPORT_WARNING_BIT_EXT |
603 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
604 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
605 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
606 callbackCreateInfo.pUserData = nullptr;
607
Adam Sawicki1f84f622019-07-02 13:40:01 +0200608 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, g_Allocs, &g_hCallback) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200609}
610
611static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
612{
613 const VkLayerProperties* propsEnd = pProps + propCount;
614 return std::find_if(
615 pProps,
616 propsEnd,
617 [pLayerName](const VkLayerProperties& prop) -> bool {
618 return strcmp(pLayerName, prop.layerName) == 0;
619 }) != propsEnd;
620}
621
622static VkFormat FindSupportedFormat(
623 const std::vector<VkFormat>& candidates,
624 VkImageTiling tiling,
625 VkFormatFeatureFlags features)
626{
627 for (VkFormat format : candidates)
628 {
629 VkFormatProperties props;
630 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
631
632 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
633 ((props.linearTilingFeatures & features) == features))
634 {
635 return format;
636 }
637 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
638 ((props.optimalTilingFeatures & features) == features))
639 {
640 return format;
641 }
642 }
643 return VK_FORMAT_UNDEFINED;
644}
645
646static VkFormat FindDepthFormat()
647{
648 std::vector<VkFormat> formats;
649 formats.push_back(VK_FORMAT_D32_SFLOAT);
650 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
651 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
652
653 return FindSupportedFormat(
654 formats,
655 VK_IMAGE_TILING_OPTIMAL,
656 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
657}
658
659static void CreateSwapchain()
660{
661 // Query surface formats.
662
663 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
664
665 uint32_t formatCount = 0;
666 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
667 g_SurfaceFormats.resize(formatCount);
668 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
669
670 uint32_t presentModeCount = 0;
671 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
672 g_PresentModes.resize(presentModeCount);
673 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
674
675 // Create swap chain
676
677 g_SurfaceFormat = ChooseSurfaceFormat();
678 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
679 g_Extent = ChooseSwapExtent();
680
681 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
682 if((g_SurfaceCapabilities.maxImageCount > 0) &&
683 (imageCount > g_SurfaceCapabilities.maxImageCount))
684 {
685 imageCount = g_SurfaceCapabilities.maxImageCount;
686 }
687
688 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
689 swapChainInfo.surface = g_hSurface;
690 swapChainInfo.minImageCount = imageCount;
691 swapChainInfo.imageFormat = g_SurfaceFormat.format;
692 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
693 swapChainInfo.imageExtent = g_Extent;
694 swapChainInfo.imageArrayLayers = 1;
695 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
696 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
697 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
698 swapChainInfo.presentMode = presentMode;
699 swapChainInfo.clipped = VK_TRUE;
700 swapChainInfo.oldSwapchain = g_hSwapchain;
701
702 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
703 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
704 {
705 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
706 swapChainInfo.queueFamilyIndexCount = 2;
707 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
708 }
709 else
710 {
711 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
712 }
713
714 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200715 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, g_Allocs, &hNewSwapchain) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200716 if(g_hSwapchain != VK_NULL_HANDLE)
Adam Sawicki1f84f622019-07-02 13:40:01 +0200717 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200718 g_hSwapchain = hNewSwapchain;
719
720 // Retrieve swapchain images.
721
722 uint32_t swapchainImageCount = 0;
723 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
724 g_SwapchainImages.resize(swapchainImageCount);
725 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
726
727 // Create swapchain image views.
728
729 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +0200730 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200731 g_SwapchainImageViews.clear();
732
733 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
734 g_SwapchainImageViews.resize(swapchainImageCount);
735 for(uint32_t i = 0; i < swapchainImageCount; ++i)
736 {
737 swapchainImageViewInfo.image = g_SwapchainImages[i];
738 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
739 swapchainImageViewInfo.format = g_SurfaceFormat.format;
740 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
741 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
742 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
743 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
744 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
745 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
746 swapchainImageViewInfo.subresourceRange.levelCount = 1;
747 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
748 swapchainImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200749 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200750 }
751
752 // Create depth buffer
753
754 g_DepthFormat = FindDepthFormat();
755 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
756
757 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
758 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
759 depthImageInfo.extent.width = g_Extent.width;
760 depthImageInfo.extent.height = g_Extent.height;
761 depthImageInfo.extent.depth = 1;
762 depthImageInfo.mipLevels = 1;
763 depthImageInfo.arrayLayers = 1;
764 depthImageInfo.format = g_DepthFormat;
765 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
766 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
767 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
768 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
769 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
770 depthImageInfo.flags = 0;
771
Adam Sawicki976f9202017-09-12 20:45:14 +0200772 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
773 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200774
Adam Sawicki976f9202017-09-12 20:45:14 +0200775 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200776
777 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
778 depthImageViewInfo.image = g_hDepthImage;
779 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
780 depthImageViewInfo.format = g_DepthFormat;
781 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
782 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
783 depthImageViewInfo.subresourceRange.levelCount = 1;
784 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
785 depthImageViewInfo.subresourceRange.layerCount = 1;
786
Adam Sawicki1f84f622019-07-02 13:40:01 +0200787 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200788
Adam Sawickie6e498f2017-06-16 17:21:31 +0200789 // Create pipeline layout
790 {
791 if(g_hPipelineLayout != VK_NULL_HANDLE)
792 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200793 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200794 g_hPipelineLayout = VK_NULL_HANDLE;
795 }
796
797 VkPushConstantRange pushConstantRanges[1];
798 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
799 pushConstantRanges[0].offset = 0;
800 pushConstantRanges[0].size = sizeof(UniformBufferObject);
801 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
802
803 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
804 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
805 pipelineLayoutInfo.setLayoutCount = 1;
806 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
807 pipelineLayoutInfo.pushConstantRangeCount = 1;
808 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200809 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200810 }
811
812 // Create render pass
813 {
814 if(g_hRenderPass != VK_NULL_HANDLE)
815 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200816 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200817 g_hRenderPass = VK_NULL_HANDLE;
818 }
819
820 VkAttachmentDescription attachments[2];
821 ZeroMemory(attachments, sizeof(attachments));
822
823 attachments[0].format = g_SurfaceFormat.format;
824 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
825 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
826 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
827 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
828 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100829 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200830 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
831
832 attachments[1].format = g_DepthFormat;
833 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
834 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
835 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
836 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
837 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100838 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200839 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
840
841 VkAttachmentReference colorAttachmentRef = {};
842 colorAttachmentRef.attachment = 0;
843 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
844
845 VkAttachmentReference depthStencilAttachmentRef = {};
846 depthStencilAttachmentRef.attachment = 1;
847 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
848
849 VkSubpassDescription subpassDesc = {};
850 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
851 subpassDesc.colorAttachmentCount = 1;
852 subpassDesc.pColorAttachments = &colorAttachmentRef;
853 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
854
Adam Sawickie6e498f2017-06-16 17:21:31 +0200855 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
856 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
857 renderPassInfo.pAttachments = attachments;
858 renderPassInfo.subpassCount = 1;
859 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200860 renderPassInfo.dependencyCount = 0;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200861 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200862 }
863
864 // Create pipeline
865 {
866 std::vector<char> vertShaderCode;
867 LoadShader(vertShaderCode, "Shader.vert.spv");
868 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
869 shaderModuleInfo.codeSize = vertShaderCode.size();
870 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
871 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200872 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200873
874 std::vector<char> hFragShaderCode;
875 LoadShader(hFragShaderCode, "Shader.frag.spv");
876 shaderModuleInfo.codeSize = hFragShaderCode.size();
877 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
878 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200879 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200880
881 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
882 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
883 vertPipelineShaderStageInfo.module = hVertShaderModule;
884 vertPipelineShaderStageInfo.pName = "main";
885
886 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
887 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
888 fragPipelineShaderStageInfo.module = fragShaderModule;
889 fragPipelineShaderStageInfo.pName = "main";
890
891 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
892 vertPipelineShaderStageInfo,
893 fragPipelineShaderStageInfo
894 };
895
896 VkVertexInputBindingDescription bindingDescription = {};
897 bindingDescription.binding = 0;
898 bindingDescription.stride = sizeof(Vertex);
899 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
900
901 VkVertexInputAttributeDescription attributeDescriptions[3];
902 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
903
904 attributeDescriptions[0].binding = 0;
905 attributeDescriptions[0].location = 0;
906 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
907 attributeDescriptions[0].offset = offsetof(Vertex, pos);
908
909 attributeDescriptions[1].binding = 0;
910 attributeDescriptions[1].location = 1;
911 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
912 attributeDescriptions[1].offset = offsetof(Vertex, color);
913
914 attributeDescriptions[2].binding = 0;
915 attributeDescriptions[2].location = 2;
916 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
917 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
918
919 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
920 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
921 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
922 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
923 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
924
925 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
926 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
927 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
928
929 VkViewport viewport = {};
930 viewport.x = 0.f;
931 viewport.y = 0.f;
932 viewport.width = (float)g_Extent.width;
933 viewport.height = (float)g_Extent.height;
934 viewport.minDepth = 0.f;
935 viewport.maxDepth = 1.f;
936
937 VkRect2D scissor = {};
938 scissor.offset.x = 0;
939 scissor.offset.y = 0;
940 scissor.extent = g_Extent;
941
942 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
943 pipelineViewportStateInfo.viewportCount = 1;
944 pipelineViewportStateInfo.pViewports = &viewport;
945 pipelineViewportStateInfo.scissorCount = 1;
946 pipelineViewportStateInfo.pScissors = &scissor;
947
948 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
949 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
950 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
951 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
952 pipelineRasterizationStateInfo.lineWidth = 1.f;
953 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
954 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
955 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
956 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
957 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
958 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
959
960 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
961 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
962 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
963 pipelineMultisampleStateInfo.minSampleShading = 1.f;
964 pipelineMultisampleStateInfo.pSampleMask = nullptr;
965 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
966 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
967
968 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
969 pipelineColorBlendAttachmentState.colorWriteMask =
970 VK_COLOR_COMPONENT_R_BIT |
971 VK_COLOR_COMPONENT_G_BIT |
972 VK_COLOR_COMPONENT_B_BIT |
973 VK_COLOR_COMPONENT_A_BIT;
974 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
975 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
976 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
977 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
978 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
979 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
980 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
981
982 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
983 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
984 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
985 pipelineColorBlendStateInfo.attachmentCount = 1;
986 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
987
988 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
989 depthStencilStateInfo.depthTestEnable = VK_TRUE;
990 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
991 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
992 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
993 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
994
995 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
996 pipelineInfo.stageCount = 2;
997 pipelineInfo.pStages = pipelineShaderStageInfos;
998 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
999 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
1000 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
1001 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
1002 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
1003 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
1004 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
1005 pipelineInfo.pDynamicState = nullptr;
1006 pipelineInfo.layout = g_hPipelineLayout;
1007 pipelineInfo.renderPass = g_hRenderPass;
1008 pipelineInfo.subpass = 0;
1009 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
1010 pipelineInfo.basePipelineIndex = -1;
1011 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
1012 g_hDevice,
1013 VK_NULL_HANDLE,
1014 1,
Adam Sawicki1f84f622019-07-02 13:40:01 +02001015 &pipelineInfo,
1016 g_Allocs,
Adam Sawickie6e498f2017-06-16 17:21:31 +02001017 &g_hPipeline) );
1018
Adam Sawicki1f84f622019-07-02 13:40:01 +02001019 vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
1020 vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001021 }
1022
1023 // Create frambuffers
1024
1025 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001026 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001027 g_Framebuffers.clear();
1028
1029 g_Framebuffers.resize(g_SwapchainImageViews.size());
1030 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1031 {
1032 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1033
1034 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1035 framebufferInfo.renderPass = g_hRenderPass;
1036 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1037 framebufferInfo.pAttachments = attachments;
1038 framebufferInfo.width = g_Extent.width;
1039 framebufferInfo.height = g_Extent.height;
1040 framebufferInfo.layers = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001041 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001042 }
1043
1044 // Create semaphores
1045
1046 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1047 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001048 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001049 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1050 }
1051 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1052 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001053 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001054 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1055 }
1056
1057 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
Adam Sawicki1f84f622019-07-02 13:40:01 +02001058 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
1059 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001060}
1061
1062static void DestroySwapchain(bool destroyActualSwapchain)
1063{
1064 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1065 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001066 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001067 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1068 }
1069 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1070 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001071 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001072 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1073 }
1074
1075 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001076 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001077 g_Framebuffers.clear();
1078
1079 if(g_hDepthImageView != VK_NULL_HANDLE)
1080 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001081 vkDestroyImageView(g_hDevice, g_hDepthImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001082 g_hDepthImageView = VK_NULL_HANDLE;
1083 }
1084 if(g_hDepthImage != VK_NULL_HANDLE)
1085 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001086 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001087 g_hDepthImage = VK_NULL_HANDLE;
1088 }
1089
1090 if(g_hPipeline != VK_NULL_HANDLE)
1091 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001092 vkDestroyPipeline(g_hDevice, g_hPipeline, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001093 g_hPipeline = VK_NULL_HANDLE;
1094 }
1095
1096 if(g_hRenderPass != VK_NULL_HANDLE)
1097 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001098 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001099 g_hRenderPass = VK_NULL_HANDLE;
1100 }
1101
1102 if(g_hPipelineLayout != VK_NULL_HANDLE)
1103 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001104 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001105 g_hPipelineLayout = VK_NULL_HANDLE;
1106 }
1107
1108 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001109 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001110 g_SwapchainImageViews.clear();
1111
1112 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1113 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001114 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001115 g_hSwapchain = VK_NULL_HANDLE;
1116 }
1117}
1118
Adam Sawicki50882502020-02-07 16:51:31 +01001119static constexpr uint32_t GetVulkanApiVersion()
1120{
Adam Sawicki8ef0d202020-03-02 15:43:47 +01001121#if VMA_VULKAN_VERSION == 1002000
1122 return VK_API_VERSION_1_2;
1123#elif VMA_VULKAN_VERSION == 1001000
1124 return VK_API_VERSION_1_1;
1125#elif VMA_VULKAN_VERSION == 1000000
1126 return VK_API_VERSION_1_0;
1127#else
1128 #error Invalid VMA_VULKAN_VERSION.
1129 return UINT32_MAX;
1130#endif
Adam Sawicki50882502020-02-07 16:51:31 +01001131}
1132
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001133static void PrintEnabledFeatures()
1134{
Adam Sawickie8a85442020-03-06 14:48:30 +01001135 wprintf(L"Validation layer: %d\n", g_EnableValidationLayer ? 1 : 0);
1136 wprintf(L"Sparse binding: %d\n", g_SparseBindingEnabled ? 1 : 0);
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001137 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1138 {
Adam Sawickie8a85442020-03-06 14:48:30 +01001139 wprintf(L"VK_KHR_get_memory_requirements2: %d\n", VK_KHR_get_memory_requirements2_enabled ? 1 : 0);
1140 wprintf(L"VK_KHR_get_physical_device_properties2: %d\n", VK_KHR_get_physical_device_properties2_enabled ? 1 : 0);
1141 wprintf(L"VK_KHR_dedicated_allocation: %d\n", VK_KHR_dedicated_allocation_enabled ? 1 : 0);
1142 wprintf(L"VK_KHR_bind_memory2: %d\n", VK_KHR_bind_memory2_enabled ? 1 : 0);
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001143 }
Adam Sawickie8a85442020-03-06 14:48:30 +01001144 wprintf(L"VK_EXT_memory_budget: %d\n", VK_EXT_memory_budget_enabled ? 1 : 0);
1145 wprintf(L"VK_AMD_device_coherent_memory: %d\n", VK_AMD_device_coherent_memory_enabled ? 1 : 0);
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001146}
1147
Adam Sawicki50882502020-02-07 16:51:31 +01001148void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
1149{
1150 outInfo = {};
1151
1152 outInfo.physicalDevice = g_hPhysicalDevice;
1153 outInfo.device = g_hDevice;
1154 outInfo.instance = g_hVulkanInstance;
1155 outInfo.vulkanApiVersion = GetVulkanApiVersion();
1156
1157 if(VK_KHR_dedicated_allocation_enabled)
1158 {
1159 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1160 }
1161 if(VK_KHR_bind_memory2_enabled)
1162 {
1163 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
1164 }
1165#if !defined(VMA_MEMORY_BUDGET) || VMA_MEMORY_BUDGET == 1
Adam Sawicki6a93b8a2020-03-09 16:58:18 +01001166 if(VK_EXT_memory_budget_enabled && (
1167 GetVulkanApiVersion() >= VK_API_VERSION_1_1 || VK_KHR_get_physical_device_properties2_enabled))
Adam Sawicki50882502020-02-07 16:51:31 +01001168 {
1169 outInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
1170 }
1171#endif
1172 if(VK_AMD_device_coherent_memory_enabled)
1173 {
1174 outInfo.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT;
1175 }
1176
1177 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1178 {
1179 outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
1180 }
1181
1182 // Uncomment to enable recording to CSV file.
1183 /*
1184 static VmaRecordSettings recordSettings = {};
1185 recordSettings.pFilePath = "VulkanSample.csv";
1186 outInfo.pRecordSettings = &recordSettings;
1187 */
1188
1189 // Uncomment to enable HeapSizeLimit.
1190 /*
1191 static std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapSizeLimit;
1192 std::fill(heapSizeLimit.begin(), heapSizeLimit.end(), VK_WHOLE_SIZE);
1193 heapSizeLimit[0] = 512ull * 1024 * 1024;
1194 outInfo.pHeapSizeLimit = heapSizeLimit.data();
1195 */
1196}
1197
Adam Sawickie8a85442020-03-06 14:48:30 +01001198static void PrintPhysicalDeviceProperties(const VkPhysicalDeviceProperties& properties)
1199{
1200 wprintf(L"Physical device:\n");
1201 wprintf(L" Driver version: 0x%X\n", properties.driverVersion);
1202 wprintf(L" Vendor ID: 0x%X\n", properties.vendorID);
1203 wprintf(L" Device ID: 0x%X\n", properties.deviceID);
1204 wprintf(L" Device type: %u\n", properties.deviceType);
1205 wprintf(L" Device name: %hs\n", properties.deviceName);
1206}
1207
Adam Sawickie6e498f2017-06-16 17:21:31 +02001208static void InitializeApplication()
1209{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001210 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1211 {
1212 g_Allocs = &g_CpuAllocationCallbacks;
1213 }
1214
Adam Sawickie6e498f2017-06-16 17:21:31 +02001215 uint32_t instanceLayerPropCount = 0;
1216 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1217 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1218 if(instanceLayerPropCount > 0)
1219 {
1220 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1221 }
1222
1223 if(g_EnableValidationLayer == true)
1224 {
1225 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1226 {
Adam Sawickie8a85442020-03-06 14:48:30 +01001227 wprintf(L"Layer \"%hs\" not supported.", VALIDATION_LAYER_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001228 g_EnableValidationLayer = false;
1229 }
1230 }
1231
Adam Sawicki353e3672019-11-02 14:12:05 +01001232 uint32_t availableInstanceExtensionCount = 0;
1233 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
1234 std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
1235 if(availableInstanceExtensionCount > 0)
1236 {
1237 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
1238 }
1239
1240 std::vector<const char*> enabledInstanceExtensions;
1241 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1242 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001243
1244 std::vector<const char*> instanceLayers;
1245 if(g_EnableValidationLayer == true)
1246 {
1247 instanceLayers.push_back(VALIDATION_LAYER_NAME);
Adam Sawicki353e3672019-11-02 14:12:05 +01001248 enabledInstanceExtensions.push_back("VK_EXT_debug_report");
1249 }
1250
1251 for(const auto& extensionProperties : availableInstanceExtensions)
1252 {
1253 if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
1254 {
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001255 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1256 {
1257 enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1258 VK_KHR_get_physical_device_properties2_enabled = true;
1259 }
Adam Sawicki353e3672019-11-02 14:12:05 +01001260 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001261 }
1262
1263 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1264 appInfo.pApplicationName = APP_TITLE_A;
1265 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1266 appInfo.pEngineName = "Adam Sawicki Engine";
1267 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
Adam Sawicki50882502020-02-07 16:51:31 +01001268 appInfo.apiVersion = GetVulkanApiVersion();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001269
1270 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1271 instInfo.pApplicationInfo = &appInfo;
Adam Sawicki353e3672019-11-02 14:12:05 +01001272 instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
1273 instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001274 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1275 instInfo.ppEnabledLayerNames = instanceLayers.data();
1276
Adam Sawickie8a85442020-03-06 14:48:30 +01001277 wprintf(L"Vulkan API version: ");
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001278 switch(appInfo.apiVersion)
1279 {
Adam Sawickie8a85442020-03-06 14:48:30 +01001280 case VK_API_VERSION_1_0: wprintf(L"1.0\n"); break;
1281 case VK_API_VERSION_1_1: wprintf(L"1.1\n"); break;
1282 case VK_API_VERSION_1_2: wprintf(L"1.2\n"); break;
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001283 default: assert(0);
1284 }
1285
Adam Sawicki1f84f622019-07-02 13:40:01 +02001286 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001287
1288 // Create VkSurfaceKHR.
1289 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1290 surfaceInfo.hinstance = g_hAppInstance;
1291 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001292 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001293 assert(result == VK_SUCCESS);
1294
1295 if(g_EnableValidationLayer == true)
1296 RegisterDebugCallbacks();
1297
1298 // Find physical device
1299
1300 uint32_t deviceCount = 0;
1301 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1302 assert(deviceCount > 0);
1303
1304 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1305 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1306
1307 g_hPhysicalDevice = physicalDevices[0];
1308
Adam Sawicki50882502020-02-07 16:51:31 +01001309 // Query for extensions
1310
1311 uint32_t physicalDeviceExtensionPropertyCount = 0;
1312 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &physicalDeviceExtensionPropertyCount, nullptr) );
1313 std::vector<VkExtensionProperties> physicalDeviceExtensionProperties{physicalDeviceExtensionPropertyCount};
1314 if(physicalDeviceExtensionPropertyCount)
1315 {
1316 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(
1317 g_hPhysicalDevice,
1318 nullptr,
1319 &physicalDeviceExtensionPropertyCount,
1320 physicalDeviceExtensionProperties.data()) );
1321 }
1322
1323 for(uint32_t i = 0; i < physicalDeviceExtensionPropertyCount; ++i)
1324 {
1325 if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001326 {
1327 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1328 {
1329 VK_KHR_get_memory_requirements2_enabled = true;
1330 }
1331 }
Adam Sawicki50882502020-02-07 16:51:31 +01001332 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001333 {
1334 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1335 {
1336 VK_KHR_dedicated_allocation_enabled = true;
1337 }
1338 }
Adam Sawicki50882502020-02-07 16:51:31 +01001339 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001340 {
1341 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1342 {
1343 VK_KHR_bind_memory2_enabled = true;
1344 }
1345 }
Adam Sawicki50882502020-02-07 16:51:31 +01001346 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
1347 VK_EXT_memory_budget_enabled = true;
1348 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) == 0)
1349 VK_AMD_device_coherent_memory_enabled = true;
1350 }
1351
Adam Sawickie6e498f2017-06-16 17:21:31 +02001352 // Query for features
1353
1354 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1355 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1356
Adam Sawickie8a85442020-03-06 14:48:30 +01001357 PrintPhysicalDeviceProperties(physicalDeviceProperties);
1358
Adam Sawicki50882502020-02-07 16:51:31 +01001359 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1360 VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };
1361 if(VK_AMD_device_coherent_memory_enabled)
1362 {
1363 physicalDeviceCoherentMemoryFeatures.pNext = physicalDeviceFeatures.pNext;
1364 physicalDeviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1365 }
1366 vkGetPhysicalDeviceFeatures2(g_hPhysicalDevice, &physicalDeviceFeatures);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001367
Adam Sawicki50882502020-02-07 16:51:31 +01001368 g_SparseBindingEnabled = physicalDeviceFeatures.features.sparseBinding != 0;
1369
1370 // The extension is supported as fake with no real support for this feature? Don't use it.
1371 if(VK_AMD_device_coherent_memory_enabled && !physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory)
1372 VK_AMD_device_coherent_memory_enabled = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001373
1374 // Find queue family index
1375
1376 uint32_t queueFamilyCount = 0;
1377 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1378 assert(queueFamilyCount > 0);
1379 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1380 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1381 for(uint32_t i = 0;
1382 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001383 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1384 g_PresentQueueFamilyIndex == UINT_MAX ||
1385 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001386 ++i)
1387 {
1388 if(queueFamilies[i].queueCount > 0)
1389 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001390 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001391 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001392 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001393 {
1394 g_GraphicsQueueFamilyIndex = i;
1395 }
1396
1397 VkBool32 surfaceSupported = 0;
1398 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1399 if((res >= 0) && (surfaceSupported == VK_TRUE))
1400 {
1401 g_PresentQueueFamilyIndex = i;
1402 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001403
1404 if(g_SparseBindingEnabled &&
1405 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1406 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1407 {
1408 g_SparseBindingQueueFamilyIndex = i;
1409 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001410 }
1411 }
1412 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1413
Adam Sawicki51fa9662018-10-03 13:44:29 +02001414 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1415
Adam Sawickie6e498f2017-06-16 17:21:31 +02001416 // Create logical device
1417
1418 const float queuePriority = 1.f;
1419
Adam Sawicki51fa9662018-10-03 13:44:29 +02001420 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1421 uint32_t queueCount = 1;
1422 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1423 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1424 queueCreateInfo[0].queueCount = 1;
1425 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1426
1427 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1428 {
1429
1430 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1431 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1432 queueCreateInfo[queueCount].queueCount = 1;
1433 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1434 ++queueCount;
1435 }
1436
1437 if(g_SparseBindingEnabled &&
1438 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1439 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1440 {
1441
1442 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1443 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1444 queueCreateInfo[queueCount].queueCount = 1;
1445 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1446 ++queueCount;
1447 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001448
Adam Sawickie6e498f2017-06-16 17:21:31 +02001449 std::vector<const char*> enabledDeviceExtensions;
1450 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki50882502020-02-07 16:51:31 +01001451 if(VK_KHR_get_memory_requirements2_enabled)
1452 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1453 if(VK_KHR_dedicated_allocation_enabled)
1454 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1455 if(VK_KHR_bind_memory2_enabled)
1456 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1457 if(VK_EXT_memory_budget_enabled)
1458 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
1459 if(VK_AMD_device_coherent_memory_enabled)
1460 enabledDeviceExtensions.push_back(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME);
1461
1462 VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1463 deviceFeatures.features.samplerAnisotropy = VK_TRUE;
1464 deviceFeatures.features.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
1465
1466 if(VK_AMD_device_coherent_memory_enabled)
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001467 {
Adam Sawicki50882502020-02-07 16:51:31 +01001468 physicalDeviceCoherentMemoryFeatures.pNext = deviceFeatures.pNext;
1469 deviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1470 physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory = VK_TRUE;
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001471 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001472
1473 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
Adam Sawicki50882502020-02-07 16:51:31 +01001474 deviceCreateInfo.pNext = &deviceFeatures;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001475 deviceCreateInfo.enabledLayerCount = 0;
1476 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1477 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001478 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001479 deviceCreateInfo.queueCreateInfoCount = queueCount;
1480 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001481
Adam Sawicki1f84f622019-07-02 13:40:01 +02001482 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001483
1484 // Create memory allocator
1485
1486 VmaAllocatorCreateInfo allocatorInfo = {};
Adam Sawicki50882502020-02-07 16:51:31 +01001487 SetAllocatorCreateInfo(allocatorInfo);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001488 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1489
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001490 PrintEnabledFeatures();
1491
Adam Sawicki51fa9662018-10-03 13:44:29 +02001492 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001493
1494 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1495 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1496 assert(g_hGraphicsQueue);
1497 assert(g_hPresentQueue);
1498
Adam Sawicki51fa9662018-10-03 13:44:29 +02001499 if(g_SparseBindingEnabled)
1500 {
1501 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1502 assert(g_hSparseBindingQueue);
1503 }
1504
Adam Sawickie6e498f2017-06-16 17:21:31 +02001505 // Create command pool
1506
1507 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1508 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1509 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001510 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001511
1512 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1513 commandBufferInfo.commandPool = g_hCommandPool;
1514 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1515 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1516 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1517
1518 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1519 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1520 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1521 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001522 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001523 }
1524
Adam Sawicki1f84f622019-07-02 13:40:01 +02001525 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001526
Adam Sawickie6e498f2017-06-16 17:21:31 +02001527 commandBufferInfo.commandBufferCount = 1;
1528 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1529
1530 // Create texture sampler
1531
1532 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1533 samplerInfo.magFilter = VK_FILTER_LINEAR;
1534 samplerInfo.minFilter = VK_FILTER_LINEAR;
1535 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1536 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1537 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1538 samplerInfo.anisotropyEnable = VK_TRUE;
1539 samplerInfo.maxAnisotropy = 16;
1540 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1541 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1542 samplerInfo.compareEnable = VK_FALSE;
1543 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1544 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1545 samplerInfo.mipLodBias = 0.f;
1546 samplerInfo.minLod = 0.f;
1547 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001548 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001549
1550 CreateTexture(128, 128);
1551 CreateMesh();
1552
1553 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1554 samplerLayoutBinding.binding = 1;
1555 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1556 samplerLayoutBinding.descriptorCount = 1;
1557 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1558
1559 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1560 descriptorSetLayoutInfo.bindingCount = 1;
1561 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001562 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001563
1564 // Create descriptor pool
1565
1566 VkDescriptorPoolSize descriptorPoolSizes[2];
1567 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1568 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1569 descriptorPoolSizes[0].descriptorCount = 1;
1570 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1571 descriptorPoolSizes[1].descriptorCount = 1;
1572
1573 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1574 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1575 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1576 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001577 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001578
1579 // Create descriptor set layout
1580
1581 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1582 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1583 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1584 descriptorSetInfo.descriptorSetCount = 1;
1585 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1586 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1587
1588 VkDescriptorImageInfo descriptorImageInfo = {};
1589 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1590 descriptorImageInfo.imageView = g_hTextureImageView;
1591 descriptorImageInfo.sampler = g_hSampler;
1592
1593 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1594 writeDescriptorSet.dstSet = g_hDescriptorSet;
1595 writeDescriptorSet.dstBinding = 1;
1596 writeDescriptorSet.dstArrayElement = 0;
1597 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1598 writeDescriptorSet.descriptorCount = 1;
1599 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1600
1601 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1602
1603 CreateSwapchain();
1604}
1605
1606static void FinalizeApplication()
1607{
1608 vkDeviceWaitIdle(g_hDevice);
1609
1610 DestroySwapchain(true);
1611
1612 if(g_hDescriptorPool != VK_NULL_HANDLE)
1613 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001614 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001615 g_hDescriptorPool = VK_NULL_HANDLE;
1616 }
1617
1618 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1619 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001620 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001621 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1622 }
1623
1624 if(g_hTextureImageView != VK_NULL_HANDLE)
1625 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001626 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001627 g_hTextureImageView = VK_NULL_HANDLE;
1628 }
1629 if(g_hTextureImage != VK_NULL_HANDLE)
1630 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001631 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001632 g_hTextureImage = VK_NULL_HANDLE;
1633 }
1634
1635 if(g_hIndexBuffer != VK_NULL_HANDLE)
1636 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001637 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001638 g_hIndexBuffer = VK_NULL_HANDLE;
1639 }
1640 if(g_hVertexBuffer != VK_NULL_HANDLE)
1641 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001642 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001643 g_hVertexBuffer = VK_NULL_HANDLE;
1644 }
1645
1646 if(g_hSampler != VK_NULL_HANDLE)
1647 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001648 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001649 g_hSampler = VK_NULL_HANDLE;
1650 }
1651
Adam Sawicki51fa9662018-10-03 13:44:29 +02001652 if(g_ImmediateFence)
1653 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001654 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001655 g_ImmediateFence = VK_NULL_HANDLE;
1656 }
1657
Adam Sawickie6e498f2017-06-16 17:21:31 +02001658 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1659 {
1660 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1661 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001662 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001663 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1664 }
1665 }
1666 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1667 {
1668 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1669 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1670 }
1671 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1672 {
1673 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1674 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1675 }
1676
1677 if(g_hCommandPool != VK_NULL_HANDLE)
1678 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001679 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001680 g_hCommandPool = VK_NULL_HANDLE;
1681 }
1682
1683 if(g_hAllocator != VK_NULL_HANDLE)
1684 {
1685 vmaDestroyAllocator(g_hAllocator);
1686 g_hAllocator = nullptr;
1687 }
1688
1689 if(g_hDevice != VK_NULL_HANDLE)
1690 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001691 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001692 g_hDevice = nullptr;
1693 }
1694
1695 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1696 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001697 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001698 g_hCallback = VK_NULL_HANDLE;
1699 }
1700
1701 if(g_hSurface != VK_NULL_HANDLE)
1702 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001703 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001704 g_hSurface = VK_NULL_HANDLE;
1705 }
1706
1707 if(g_hVulkanInstance != VK_NULL_HANDLE)
1708 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001709 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001710 g_hVulkanInstance = VK_NULL_HANDLE;
1711 }
1712}
1713
1714static void PrintAllocatorStats()
1715{
1716#if VMA_STATS_STRING_ENABLED
1717 char* statsString = nullptr;
1718 vmaBuildStatsString(g_hAllocator, &statsString, true);
1719 printf("%s\n", statsString);
1720 vmaFreeStatsString(g_hAllocator, statsString);
1721#endif
1722}
1723
1724static void RecreateSwapChain()
1725{
1726 vkDeviceWaitIdle(g_hDevice);
1727 DestroySwapchain(false);
1728 CreateSwapchain();
1729}
1730
1731static void DrawFrame()
1732{
1733 // Begin main command buffer
1734 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1735 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1736 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1737
1738 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1739 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1740
1741 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1742 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1743 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1744
1745 // Acquire swapchain image
1746 uint32_t imageIndex = 0;
1747 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1748 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1749 {
1750 RecreateSwapChain();
1751 return;
1752 }
1753 else if(res < 0)
1754 {
1755 ERR_GUARD_VULKAN(res);
1756 }
1757
1758 // Record geometry pass
1759
1760 VkClearValue clearValues[2];
1761 ZeroMemory(clearValues, sizeof(clearValues));
1762 clearValues[0].color.float32[0] = 0.25f;
1763 clearValues[0].color.float32[1] = 0.25f;
1764 clearValues[0].color.float32[2] = 0.5f;
1765 clearValues[0].color.float32[3] = 1.0f;
1766 clearValues[1].depthStencil.depth = 1.0f;
1767
1768 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1769 renderPassBeginInfo.renderPass = g_hRenderPass;
1770 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1771 renderPassBeginInfo.renderArea.offset.x = 0;
1772 renderPassBeginInfo.renderArea.offset.y = 0;
1773 renderPassBeginInfo.renderArea.extent = g_Extent;
1774 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1775 renderPassBeginInfo.pClearValues = clearValues;
1776 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1777
1778 vkCmdBindPipeline(
1779 hCommandBuffer,
1780 VK_PIPELINE_BIND_POINT_GRAPHICS,
1781 g_hPipeline);
1782
Adam Sawicki82c3f332018-06-11 15:27:33 +02001783 mat4 view = mat4::LookAt(
1784 vec3(0.f, 0.f, 0.f),
1785 vec3(0.f, -2.f, 4.f),
1786 vec3(0.f, 1.f, 0.f));
1787 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001788 1.0471975511966f, // 60 degrees
1789 (float)g_Extent.width / (float)g_Extent.height,
1790 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001791 1000.f);
1792 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001793
1794 vkCmdBindDescriptorSets(
1795 hCommandBuffer,
1796 VK_PIPELINE_BIND_POINT_GRAPHICS,
1797 g_hPipelineLayout,
1798 0,
1799 1,
1800 &g_hDescriptorSet,
1801 0,
1802 nullptr);
1803
Adam Sawicki82c3f332018-06-11 15:27:33 +02001804 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1805 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001806
1807 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001808 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001809 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1810
1811 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1812 VkDeviceSize offsets[] = { 0 };
1813 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1814
1815 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1816
1817 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1818
1819 vkCmdEndRenderPass(hCommandBuffer);
1820
1821 vkEndCommandBuffer(hCommandBuffer);
1822
1823 // Submit command buffer
1824
1825 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1826 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1827 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1828 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1829 submitInfo.waitSemaphoreCount = 1;
1830 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1831 submitInfo.pWaitDstStageMask = submitWaitStages;
1832 submitInfo.commandBufferCount = 1;
1833 submitInfo.pCommandBuffers = &hCommandBuffer;
1834 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1835 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1836 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1837
1838 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1839
1840 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1841 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1842 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1843 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1844 presentInfo.swapchainCount = 1;
1845 presentInfo.pSwapchains = swapchains;
1846 presentInfo.pImageIndices = &imageIndex;
1847 presentInfo.pResults = nullptr;
1848 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1849 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1850 {
1851 RecreateSwapChain();
1852 }
1853 else
1854 ERR_GUARD_VULKAN(res);
1855}
1856
1857static void HandlePossibleSizeChange()
1858{
1859 RECT clientRect;
1860 GetClientRect(g_hWnd, &clientRect);
1861 LONG newSizeX = clientRect.right - clientRect.left;
1862 LONG newSizeY = clientRect.bottom - clientRect.top;
1863 if((newSizeX > 0) &&
1864 (newSizeY > 0) &&
1865 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1866 {
1867 g_SizeX = newSizeX;
1868 g_SizeY = newSizeY;
1869
1870 RecreateSwapChain();
1871 }
1872}
1873
1874static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1875{
1876 switch(msg)
1877 {
1878 case WM_CREATE:
1879 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1880 g_hWnd = hWnd;
1881 InitializeApplication();
1882 PrintAllocatorStats();
1883 return 0;
1884
1885 case WM_DESTROY:
1886 FinalizeApplication();
1887 PostQuitMessage(0);
1888 return 0;
1889
1890 // This prevents app from freezing when left Alt is pressed
1891 // (which normally enters modal menu loop).
1892 case WM_SYSKEYDOWN:
1893 case WM_SYSKEYUP:
1894 return 0;
1895
1896 case WM_SIZE:
1897 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1898 HandlePossibleSizeChange();
1899 return 0;
1900
1901 case WM_EXITSIZEMOVE:
1902 HandlePossibleSizeChange();
1903 return 0;
1904
1905 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001906 switch(wParam)
1907 {
1908 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001909 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001910 break;
1911 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001912 try
1913 {
1914 Test();
1915 }
1916 catch(const std::exception& ex)
1917 {
1918 printf("ERROR: %s\n", ex.what());
1919 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001920 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001921 case 'S':
1922 try
1923 {
1924 if(g_SparseBindingEnabled)
1925 {
1926 TestSparseBinding();
1927 }
1928 else
1929 {
1930 printf("Sparse binding not supported.\n");
1931 }
1932 }
1933 catch(const std::exception& ex)
1934 {
1935 printf("ERROR: %s\n", ex.what());
1936 }
1937 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001938 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001939 return 0;
1940
1941 default:
1942 break;
1943 }
1944
1945 return DefWindowProc(hWnd, msg, wParam, lParam);
1946}
1947
1948int main()
1949{
1950 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1951
1952 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1953 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1954 wndClassDesc.hbrBackground = NULL;
1955 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1956 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1957 wndClassDesc.hInstance = g_hAppInstance;
1958 wndClassDesc.lpfnWndProc = WndProc;
1959 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1960
1961 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1962 assert(hWndClass);
1963
1964 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1965 const DWORD exStyle = 0;
1966
1967 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1968 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1969
Adam Sawicki86ccd632017-07-04 14:57:53 +02001970 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001971 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1972 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1973 NULL, NULL, g_hAppInstance, NULL);
1974
1975 MSG msg;
1976 for(;;)
1977 {
1978 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1979 {
1980 if(msg.message == WM_QUIT)
1981 break;
1982 TranslateMessage(&msg);
1983 DispatchMessage(&msg);
1984 }
1985 if(g_hDevice != VK_NULL_HANDLE)
1986 DrawFrame();
1987 }
1988
Adam Sawicki8317ba92019-11-18 13:14:11 +01001989 TEST(g_CpuAllocCount.load() == 0);
1990
Adam Sawickie6e498f2017-06-16 17:21:31 +02001991 return 0;
1992}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001993
Adam Sawickif1a793c2018-03-13 15:42:22 +01001994#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001995
Adam Sawickif1a793c2018-03-13 15:42:22 +01001996#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001997
1998int main()
1999{
2000}
2001
Adam Sawickif1a793c2018-03-13 15:42:22 +01002002#endif // #ifdef _WIN32