blob: 39961ecd61ed25b8c05851e4df02a75215e9c63f [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
1166 if(VK_EXT_memory_budget_enabled && VK_KHR_get_physical_device_properties2_enabled)
1167 {
1168 outInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
1169 }
1170#endif
1171 if(VK_AMD_device_coherent_memory_enabled)
1172 {
1173 outInfo.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT;
1174 }
1175
1176 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1177 {
1178 outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
1179 }
1180
1181 // Uncomment to enable recording to CSV file.
1182 /*
1183 static VmaRecordSettings recordSettings = {};
1184 recordSettings.pFilePath = "VulkanSample.csv";
1185 outInfo.pRecordSettings = &recordSettings;
1186 */
1187
1188 // Uncomment to enable HeapSizeLimit.
1189 /*
1190 static std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapSizeLimit;
1191 std::fill(heapSizeLimit.begin(), heapSizeLimit.end(), VK_WHOLE_SIZE);
1192 heapSizeLimit[0] = 512ull * 1024 * 1024;
1193 outInfo.pHeapSizeLimit = heapSizeLimit.data();
1194 */
1195}
1196
Adam Sawickie8a85442020-03-06 14:48:30 +01001197static void PrintPhysicalDeviceProperties(const VkPhysicalDeviceProperties& properties)
1198{
1199 wprintf(L"Physical device:\n");
1200 wprintf(L" Driver version: 0x%X\n", properties.driverVersion);
1201 wprintf(L" Vendor ID: 0x%X\n", properties.vendorID);
1202 wprintf(L" Device ID: 0x%X\n", properties.deviceID);
1203 wprintf(L" Device type: %u\n", properties.deviceType);
1204 wprintf(L" Device name: %hs\n", properties.deviceName);
1205}
1206
Adam Sawickie6e498f2017-06-16 17:21:31 +02001207static void InitializeApplication()
1208{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001209 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1210 {
1211 g_Allocs = &g_CpuAllocationCallbacks;
1212 }
1213
Adam Sawickie6e498f2017-06-16 17:21:31 +02001214 uint32_t instanceLayerPropCount = 0;
1215 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1216 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1217 if(instanceLayerPropCount > 0)
1218 {
1219 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1220 }
1221
1222 if(g_EnableValidationLayer == true)
1223 {
1224 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1225 {
Adam Sawickie8a85442020-03-06 14:48:30 +01001226 wprintf(L"Layer \"%hs\" not supported.", VALIDATION_LAYER_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001227 g_EnableValidationLayer = false;
1228 }
1229 }
1230
Adam Sawicki353e3672019-11-02 14:12:05 +01001231 uint32_t availableInstanceExtensionCount = 0;
1232 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
1233 std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
1234 if(availableInstanceExtensionCount > 0)
1235 {
1236 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
1237 }
1238
1239 std::vector<const char*> enabledInstanceExtensions;
1240 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1241 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001242
1243 std::vector<const char*> instanceLayers;
1244 if(g_EnableValidationLayer == true)
1245 {
1246 instanceLayers.push_back(VALIDATION_LAYER_NAME);
Adam Sawicki353e3672019-11-02 14:12:05 +01001247 enabledInstanceExtensions.push_back("VK_EXT_debug_report");
1248 }
1249
1250 for(const auto& extensionProperties : availableInstanceExtensions)
1251 {
1252 if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
1253 {
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001254 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1255 {
1256 enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1257 VK_KHR_get_physical_device_properties2_enabled = true;
1258 }
Adam Sawicki353e3672019-11-02 14:12:05 +01001259 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001260 }
1261
1262 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1263 appInfo.pApplicationName = APP_TITLE_A;
1264 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1265 appInfo.pEngineName = "Adam Sawicki Engine";
1266 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
Adam Sawicki50882502020-02-07 16:51:31 +01001267 appInfo.apiVersion = GetVulkanApiVersion();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001268
1269 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1270 instInfo.pApplicationInfo = &appInfo;
Adam Sawicki353e3672019-11-02 14:12:05 +01001271 instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
1272 instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001273 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1274 instInfo.ppEnabledLayerNames = instanceLayers.data();
1275
Adam Sawickie8a85442020-03-06 14:48:30 +01001276 wprintf(L"Vulkan API version: ");
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001277 switch(appInfo.apiVersion)
1278 {
Adam Sawickie8a85442020-03-06 14:48:30 +01001279 case VK_API_VERSION_1_0: wprintf(L"1.0\n"); break;
1280 case VK_API_VERSION_1_1: wprintf(L"1.1\n"); break;
1281 case VK_API_VERSION_1_2: wprintf(L"1.2\n"); break;
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001282 default: assert(0);
1283 }
1284
Adam Sawicki1f84f622019-07-02 13:40:01 +02001285 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001286
1287 // Create VkSurfaceKHR.
1288 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1289 surfaceInfo.hinstance = g_hAppInstance;
1290 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001291 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001292 assert(result == VK_SUCCESS);
1293
1294 if(g_EnableValidationLayer == true)
1295 RegisterDebugCallbacks();
1296
1297 // Find physical device
1298
1299 uint32_t deviceCount = 0;
1300 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1301 assert(deviceCount > 0);
1302
1303 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1304 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1305
1306 g_hPhysicalDevice = physicalDevices[0];
1307
Adam Sawicki50882502020-02-07 16:51:31 +01001308 // Query for extensions
1309
1310 uint32_t physicalDeviceExtensionPropertyCount = 0;
1311 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &physicalDeviceExtensionPropertyCount, nullptr) );
1312 std::vector<VkExtensionProperties> physicalDeviceExtensionProperties{physicalDeviceExtensionPropertyCount};
1313 if(physicalDeviceExtensionPropertyCount)
1314 {
1315 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(
1316 g_hPhysicalDevice,
1317 nullptr,
1318 &physicalDeviceExtensionPropertyCount,
1319 physicalDeviceExtensionProperties.data()) );
1320 }
1321
1322 for(uint32_t i = 0; i < physicalDeviceExtensionPropertyCount; ++i)
1323 {
1324 if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001325 {
1326 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1327 {
1328 VK_KHR_get_memory_requirements2_enabled = true;
1329 }
1330 }
Adam Sawicki50882502020-02-07 16:51:31 +01001331 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001332 {
1333 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1334 {
1335 VK_KHR_dedicated_allocation_enabled = true;
1336 }
1337 }
Adam Sawicki50882502020-02-07 16:51:31 +01001338 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001339 {
1340 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1341 {
1342 VK_KHR_bind_memory2_enabled = true;
1343 }
1344 }
Adam Sawicki50882502020-02-07 16:51:31 +01001345 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
1346 VK_EXT_memory_budget_enabled = true;
1347 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) == 0)
1348 VK_AMD_device_coherent_memory_enabled = true;
1349 }
1350
Adam Sawickie6e498f2017-06-16 17:21:31 +02001351 // Query for features
1352
1353 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1354 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1355
Adam Sawickie8a85442020-03-06 14:48:30 +01001356 PrintPhysicalDeviceProperties(physicalDeviceProperties);
1357
Adam Sawicki50882502020-02-07 16:51:31 +01001358 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1359 VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };
1360 if(VK_AMD_device_coherent_memory_enabled)
1361 {
1362 physicalDeviceCoherentMemoryFeatures.pNext = physicalDeviceFeatures.pNext;
1363 physicalDeviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1364 }
1365 vkGetPhysicalDeviceFeatures2(g_hPhysicalDevice, &physicalDeviceFeatures);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001366
Adam Sawicki50882502020-02-07 16:51:31 +01001367 g_SparseBindingEnabled = physicalDeviceFeatures.features.sparseBinding != 0;
1368
1369 // The extension is supported as fake with no real support for this feature? Don't use it.
1370 if(VK_AMD_device_coherent_memory_enabled && !physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory)
1371 VK_AMD_device_coherent_memory_enabled = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001372
1373 // Find queue family index
1374
1375 uint32_t queueFamilyCount = 0;
1376 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1377 assert(queueFamilyCount > 0);
1378 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1379 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1380 for(uint32_t i = 0;
1381 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001382 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1383 g_PresentQueueFamilyIndex == UINT_MAX ||
1384 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001385 ++i)
1386 {
1387 if(queueFamilies[i].queueCount > 0)
1388 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001389 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001390 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001391 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001392 {
1393 g_GraphicsQueueFamilyIndex = i;
1394 }
1395
1396 VkBool32 surfaceSupported = 0;
1397 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1398 if((res >= 0) && (surfaceSupported == VK_TRUE))
1399 {
1400 g_PresentQueueFamilyIndex = i;
1401 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001402
1403 if(g_SparseBindingEnabled &&
1404 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1405 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1406 {
1407 g_SparseBindingQueueFamilyIndex = i;
1408 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001409 }
1410 }
1411 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1412
Adam Sawicki51fa9662018-10-03 13:44:29 +02001413 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1414
Adam Sawickie6e498f2017-06-16 17:21:31 +02001415 // Create logical device
1416
1417 const float queuePriority = 1.f;
1418
Adam Sawicki51fa9662018-10-03 13:44:29 +02001419 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1420 uint32_t queueCount = 1;
1421 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1422 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1423 queueCreateInfo[0].queueCount = 1;
1424 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1425
1426 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1427 {
1428
1429 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1430 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1431 queueCreateInfo[queueCount].queueCount = 1;
1432 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1433 ++queueCount;
1434 }
1435
1436 if(g_SparseBindingEnabled &&
1437 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1438 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1439 {
1440
1441 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1442 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1443 queueCreateInfo[queueCount].queueCount = 1;
1444 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1445 ++queueCount;
1446 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001447
Adam Sawickie6e498f2017-06-16 17:21:31 +02001448 std::vector<const char*> enabledDeviceExtensions;
1449 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki50882502020-02-07 16:51:31 +01001450 if(VK_KHR_get_memory_requirements2_enabled)
1451 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1452 if(VK_KHR_dedicated_allocation_enabled)
1453 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1454 if(VK_KHR_bind_memory2_enabled)
1455 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1456 if(VK_EXT_memory_budget_enabled)
1457 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
1458 if(VK_AMD_device_coherent_memory_enabled)
1459 enabledDeviceExtensions.push_back(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME);
1460
1461 VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1462 deviceFeatures.features.samplerAnisotropy = VK_TRUE;
1463 deviceFeatures.features.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
1464
1465 if(VK_AMD_device_coherent_memory_enabled)
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001466 {
Adam Sawicki50882502020-02-07 16:51:31 +01001467 physicalDeviceCoherentMemoryFeatures.pNext = deviceFeatures.pNext;
1468 deviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1469 physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory = VK_TRUE;
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001470 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001471
1472 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
Adam Sawicki50882502020-02-07 16:51:31 +01001473 deviceCreateInfo.pNext = &deviceFeatures;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001474 deviceCreateInfo.enabledLayerCount = 0;
1475 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1476 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001477 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001478 deviceCreateInfo.queueCreateInfoCount = queueCount;
1479 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001480
Adam Sawicki1f84f622019-07-02 13:40:01 +02001481 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001482
1483 // Create memory allocator
1484
1485 VmaAllocatorCreateInfo allocatorInfo = {};
Adam Sawicki50882502020-02-07 16:51:31 +01001486 SetAllocatorCreateInfo(allocatorInfo);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001487 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1488
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001489 PrintEnabledFeatures();
1490
Adam Sawicki51fa9662018-10-03 13:44:29 +02001491 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001492
1493 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1494 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1495 assert(g_hGraphicsQueue);
1496 assert(g_hPresentQueue);
1497
Adam Sawicki51fa9662018-10-03 13:44:29 +02001498 if(g_SparseBindingEnabled)
1499 {
1500 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1501 assert(g_hSparseBindingQueue);
1502 }
1503
Adam Sawickie6e498f2017-06-16 17:21:31 +02001504 // Create command pool
1505
1506 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1507 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1508 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001509 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001510
1511 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1512 commandBufferInfo.commandPool = g_hCommandPool;
1513 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1514 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1515 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1516
1517 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1518 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1519 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1520 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001521 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001522 }
1523
Adam Sawicki1f84f622019-07-02 13:40:01 +02001524 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001525
Adam Sawickie6e498f2017-06-16 17:21:31 +02001526 commandBufferInfo.commandBufferCount = 1;
1527 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1528
1529 // Create texture sampler
1530
1531 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1532 samplerInfo.magFilter = VK_FILTER_LINEAR;
1533 samplerInfo.minFilter = VK_FILTER_LINEAR;
1534 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1535 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1536 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1537 samplerInfo.anisotropyEnable = VK_TRUE;
1538 samplerInfo.maxAnisotropy = 16;
1539 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1540 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1541 samplerInfo.compareEnable = VK_FALSE;
1542 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1543 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1544 samplerInfo.mipLodBias = 0.f;
1545 samplerInfo.minLod = 0.f;
1546 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001547 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001548
1549 CreateTexture(128, 128);
1550 CreateMesh();
1551
1552 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1553 samplerLayoutBinding.binding = 1;
1554 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1555 samplerLayoutBinding.descriptorCount = 1;
1556 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1557
1558 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1559 descriptorSetLayoutInfo.bindingCount = 1;
1560 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001561 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001562
1563 // Create descriptor pool
1564
1565 VkDescriptorPoolSize descriptorPoolSizes[2];
1566 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1567 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1568 descriptorPoolSizes[0].descriptorCount = 1;
1569 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1570 descriptorPoolSizes[1].descriptorCount = 1;
1571
1572 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1573 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1574 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1575 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001576 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001577
1578 // Create descriptor set layout
1579
1580 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1581 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1582 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1583 descriptorSetInfo.descriptorSetCount = 1;
1584 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1585 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1586
1587 VkDescriptorImageInfo descriptorImageInfo = {};
1588 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1589 descriptorImageInfo.imageView = g_hTextureImageView;
1590 descriptorImageInfo.sampler = g_hSampler;
1591
1592 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1593 writeDescriptorSet.dstSet = g_hDescriptorSet;
1594 writeDescriptorSet.dstBinding = 1;
1595 writeDescriptorSet.dstArrayElement = 0;
1596 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1597 writeDescriptorSet.descriptorCount = 1;
1598 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1599
1600 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1601
1602 CreateSwapchain();
1603}
1604
1605static void FinalizeApplication()
1606{
1607 vkDeviceWaitIdle(g_hDevice);
1608
1609 DestroySwapchain(true);
1610
1611 if(g_hDescriptorPool != VK_NULL_HANDLE)
1612 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001613 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001614 g_hDescriptorPool = VK_NULL_HANDLE;
1615 }
1616
1617 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1618 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001619 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001620 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1621 }
1622
1623 if(g_hTextureImageView != VK_NULL_HANDLE)
1624 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001625 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001626 g_hTextureImageView = VK_NULL_HANDLE;
1627 }
1628 if(g_hTextureImage != VK_NULL_HANDLE)
1629 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001630 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001631 g_hTextureImage = VK_NULL_HANDLE;
1632 }
1633
1634 if(g_hIndexBuffer != VK_NULL_HANDLE)
1635 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001636 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001637 g_hIndexBuffer = VK_NULL_HANDLE;
1638 }
1639 if(g_hVertexBuffer != VK_NULL_HANDLE)
1640 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001641 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001642 g_hVertexBuffer = VK_NULL_HANDLE;
1643 }
1644
1645 if(g_hSampler != VK_NULL_HANDLE)
1646 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001647 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001648 g_hSampler = VK_NULL_HANDLE;
1649 }
1650
Adam Sawicki51fa9662018-10-03 13:44:29 +02001651 if(g_ImmediateFence)
1652 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001653 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001654 g_ImmediateFence = VK_NULL_HANDLE;
1655 }
1656
Adam Sawickie6e498f2017-06-16 17:21:31 +02001657 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1658 {
1659 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1660 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001661 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001662 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1663 }
1664 }
1665 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1666 {
1667 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1668 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1669 }
1670 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1671 {
1672 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1673 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1674 }
1675
1676 if(g_hCommandPool != VK_NULL_HANDLE)
1677 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001678 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001679 g_hCommandPool = VK_NULL_HANDLE;
1680 }
1681
1682 if(g_hAllocator != VK_NULL_HANDLE)
1683 {
1684 vmaDestroyAllocator(g_hAllocator);
1685 g_hAllocator = nullptr;
1686 }
1687
1688 if(g_hDevice != VK_NULL_HANDLE)
1689 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001690 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001691 g_hDevice = nullptr;
1692 }
1693
1694 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1695 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001696 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001697 g_hCallback = VK_NULL_HANDLE;
1698 }
1699
1700 if(g_hSurface != VK_NULL_HANDLE)
1701 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001702 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001703 g_hSurface = VK_NULL_HANDLE;
1704 }
1705
1706 if(g_hVulkanInstance != VK_NULL_HANDLE)
1707 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001708 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001709 g_hVulkanInstance = VK_NULL_HANDLE;
1710 }
1711}
1712
1713static void PrintAllocatorStats()
1714{
1715#if VMA_STATS_STRING_ENABLED
1716 char* statsString = nullptr;
1717 vmaBuildStatsString(g_hAllocator, &statsString, true);
1718 printf("%s\n", statsString);
1719 vmaFreeStatsString(g_hAllocator, statsString);
1720#endif
1721}
1722
1723static void RecreateSwapChain()
1724{
1725 vkDeviceWaitIdle(g_hDevice);
1726 DestroySwapchain(false);
1727 CreateSwapchain();
1728}
1729
1730static void DrawFrame()
1731{
1732 // Begin main command buffer
1733 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1734 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1735 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1736
1737 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1738 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1739
1740 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1741 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1742 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1743
1744 // Acquire swapchain image
1745 uint32_t imageIndex = 0;
1746 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1747 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1748 {
1749 RecreateSwapChain();
1750 return;
1751 }
1752 else if(res < 0)
1753 {
1754 ERR_GUARD_VULKAN(res);
1755 }
1756
1757 // Record geometry pass
1758
1759 VkClearValue clearValues[2];
1760 ZeroMemory(clearValues, sizeof(clearValues));
1761 clearValues[0].color.float32[0] = 0.25f;
1762 clearValues[0].color.float32[1] = 0.25f;
1763 clearValues[0].color.float32[2] = 0.5f;
1764 clearValues[0].color.float32[3] = 1.0f;
1765 clearValues[1].depthStencil.depth = 1.0f;
1766
1767 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1768 renderPassBeginInfo.renderPass = g_hRenderPass;
1769 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1770 renderPassBeginInfo.renderArea.offset.x = 0;
1771 renderPassBeginInfo.renderArea.offset.y = 0;
1772 renderPassBeginInfo.renderArea.extent = g_Extent;
1773 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1774 renderPassBeginInfo.pClearValues = clearValues;
1775 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1776
1777 vkCmdBindPipeline(
1778 hCommandBuffer,
1779 VK_PIPELINE_BIND_POINT_GRAPHICS,
1780 g_hPipeline);
1781
Adam Sawicki82c3f332018-06-11 15:27:33 +02001782 mat4 view = mat4::LookAt(
1783 vec3(0.f, 0.f, 0.f),
1784 vec3(0.f, -2.f, 4.f),
1785 vec3(0.f, 1.f, 0.f));
1786 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001787 1.0471975511966f, // 60 degrees
1788 (float)g_Extent.width / (float)g_Extent.height,
1789 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001790 1000.f);
1791 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001792
1793 vkCmdBindDescriptorSets(
1794 hCommandBuffer,
1795 VK_PIPELINE_BIND_POINT_GRAPHICS,
1796 g_hPipelineLayout,
1797 0,
1798 1,
1799 &g_hDescriptorSet,
1800 0,
1801 nullptr);
1802
Adam Sawicki82c3f332018-06-11 15:27:33 +02001803 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1804 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001805
1806 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001807 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001808 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1809
1810 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1811 VkDeviceSize offsets[] = { 0 };
1812 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1813
1814 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1815
1816 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1817
1818 vkCmdEndRenderPass(hCommandBuffer);
1819
1820 vkEndCommandBuffer(hCommandBuffer);
1821
1822 // Submit command buffer
1823
1824 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1825 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1826 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1827 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1828 submitInfo.waitSemaphoreCount = 1;
1829 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1830 submitInfo.pWaitDstStageMask = submitWaitStages;
1831 submitInfo.commandBufferCount = 1;
1832 submitInfo.pCommandBuffers = &hCommandBuffer;
1833 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1834 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1835 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1836
1837 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1838
1839 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1840 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1841 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1842 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1843 presentInfo.swapchainCount = 1;
1844 presentInfo.pSwapchains = swapchains;
1845 presentInfo.pImageIndices = &imageIndex;
1846 presentInfo.pResults = nullptr;
1847 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1848 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1849 {
1850 RecreateSwapChain();
1851 }
1852 else
1853 ERR_GUARD_VULKAN(res);
1854}
1855
1856static void HandlePossibleSizeChange()
1857{
1858 RECT clientRect;
1859 GetClientRect(g_hWnd, &clientRect);
1860 LONG newSizeX = clientRect.right - clientRect.left;
1861 LONG newSizeY = clientRect.bottom - clientRect.top;
1862 if((newSizeX > 0) &&
1863 (newSizeY > 0) &&
1864 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1865 {
1866 g_SizeX = newSizeX;
1867 g_SizeY = newSizeY;
1868
1869 RecreateSwapChain();
1870 }
1871}
1872
1873static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1874{
1875 switch(msg)
1876 {
1877 case WM_CREATE:
1878 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1879 g_hWnd = hWnd;
1880 InitializeApplication();
1881 PrintAllocatorStats();
1882 return 0;
1883
1884 case WM_DESTROY:
1885 FinalizeApplication();
1886 PostQuitMessage(0);
1887 return 0;
1888
1889 // This prevents app from freezing when left Alt is pressed
1890 // (which normally enters modal menu loop).
1891 case WM_SYSKEYDOWN:
1892 case WM_SYSKEYUP:
1893 return 0;
1894
1895 case WM_SIZE:
1896 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1897 HandlePossibleSizeChange();
1898 return 0;
1899
1900 case WM_EXITSIZEMOVE:
1901 HandlePossibleSizeChange();
1902 return 0;
1903
1904 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001905 switch(wParam)
1906 {
1907 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001908 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001909 break;
1910 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001911 try
1912 {
1913 Test();
1914 }
1915 catch(const std::exception& ex)
1916 {
1917 printf("ERROR: %s\n", ex.what());
1918 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001919 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001920 case 'S':
1921 try
1922 {
1923 if(g_SparseBindingEnabled)
1924 {
1925 TestSparseBinding();
1926 }
1927 else
1928 {
1929 printf("Sparse binding not supported.\n");
1930 }
1931 }
1932 catch(const std::exception& ex)
1933 {
1934 printf("ERROR: %s\n", ex.what());
1935 }
1936 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001937 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001938 return 0;
1939
1940 default:
1941 break;
1942 }
1943
1944 return DefWindowProc(hWnd, msg, wParam, lParam);
1945}
1946
1947int main()
1948{
1949 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1950
1951 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1952 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1953 wndClassDesc.hbrBackground = NULL;
1954 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1955 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1956 wndClassDesc.hInstance = g_hAppInstance;
1957 wndClassDesc.lpfnWndProc = WndProc;
1958 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1959
1960 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1961 assert(hWndClass);
1962
1963 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1964 const DWORD exStyle = 0;
1965
1966 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1967 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1968
Adam Sawicki86ccd632017-07-04 14:57:53 +02001969 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001970 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1971 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1972 NULL, NULL, g_hAppInstance, NULL);
1973
1974 MSG msg;
1975 for(;;)
1976 {
1977 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1978 {
1979 if(msg.message == WM_QUIT)
1980 break;
1981 TranslateMessage(&msg);
1982 DispatchMessage(&msg);
1983 }
1984 if(g_hDevice != VK_NULL_HANDLE)
1985 DrawFrame();
1986 }
1987
Adam Sawicki8317ba92019-11-18 13:14:11 +01001988 TEST(g_CpuAllocCount.load() == 0);
1989
Adam Sawickie6e498f2017-06-16 17:21:31 +02001990 return 0;
1991}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001992
Adam Sawickif1a793c2018-03-13 15:42:22 +01001993#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001994
Adam Sawickif1a793c2018-03-13 15:42:22 +01001995#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001996
1997int main()
1998{
1999}
2000
Adam Sawickif1a793c2018-03-13 15:42:22 +01002001#endif // #ifdef _WIN32