blob: 460c5c3bf71983d288a9efdc3334fffb223a3d20 [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{
1135 printf("Validation layer: %d\n", g_EnableValidationLayer ? 1 : 0);
1136 printf("Sparse binding: %d\n", g_SparseBindingEnabled ? 1 : 0);
1137 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1138 {
1139 printf("VK_KHR_get_memory_requirements2: %d\n", VK_KHR_get_memory_requirements2_enabled ? 1 : 0);
1140 printf("VK_KHR_get_physical_device_properties2: %d\n", VK_KHR_get_physical_device_properties2_enabled ? 1 : 0);
1141 printf("VK_KHR_dedicated_allocation: %d\n", VK_KHR_dedicated_allocation_enabled ? 1 : 0);
1142 printf("VK_KHR_bind_memory2: %d\n", VK_KHR_bind_memory2_enabled ? 1 : 0);
1143 }
1144 printf("VK_EXT_memory_budget: %d\n", VK_EXT_memory_budget_enabled ? 1 : 0);
1145 printf("VK_AMD_device_coherent_memory: %d\n", VK_AMD_device_coherent_memory_enabled ? 1 : 0);
1146}
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 Sawickie6e498f2017-06-16 17:21:31 +02001197static void InitializeApplication()
1198{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001199 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1200 {
1201 g_Allocs = &g_CpuAllocationCallbacks;
1202 }
1203
Adam Sawickie6e498f2017-06-16 17:21:31 +02001204 uint32_t instanceLayerPropCount = 0;
1205 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1206 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1207 if(instanceLayerPropCount > 0)
1208 {
1209 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1210 }
1211
1212 if(g_EnableValidationLayer == true)
1213 {
1214 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1215 {
1216 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1217 g_EnableValidationLayer = false;
1218 }
1219 }
1220
Adam Sawicki353e3672019-11-02 14:12:05 +01001221 uint32_t availableInstanceExtensionCount = 0;
1222 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
1223 std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
1224 if(availableInstanceExtensionCount > 0)
1225 {
1226 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
1227 }
1228
1229 std::vector<const char*> enabledInstanceExtensions;
1230 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1231 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001232
1233 std::vector<const char*> instanceLayers;
1234 if(g_EnableValidationLayer == true)
1235 {
1236 instanceLayers.push_back(VALIDATION_LAYER_NAME);
Adam Sawicki353e3672019-11-02 14:12:05 +01001237 enabledInstanceExtensions.push_back("VK_EXT_debug_report");
1238 }
1239
1240 for(const auto& extensionProperties : availableInstanceExtensions)
1241 {
1242 if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
1243 {
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001244 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1245 {
1246 enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
1247 VK_KHR_get_physical_device_properties2_enabled = true;
1248 }
Adam Sawicki353e3672019-11-02 14:12:05 +01001249 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001250 }
1251
1252 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1253 appInfo.pApplicationName = APP_TITLE_A;
1254 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1255 appInfo.pEngineName = "Adam Sawicki Engine";
1256 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
Adam Sawicki50882502020-02-07 16:51:31 +01001257 appInfo.apiVersion = GetVulkanApiVersion();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001258
1259 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1260 instInfo.pApplicationInfo = &appInfo;
Adam Sawicki353e3672019-11-02 14:12:05 +01001261 instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
1262 instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
Adam Sawickie6e498f2017-06-16 17:21:31 +02001263 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1264 instInfo.ppEnabledLayerNames = instanceLayers.data();
1265
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001266 printf("Vulkan API version: ");
1267 switch(appInfo.apiVersion)
1268 {
1269 case VK_API_VERSION_1_0: printf("1.0\n"); break;
1270 case VK_API_VERSION_1_1: printf("1.1\n"); break;
1271 case VK_API_VERSION_1_2: printf("1.2\n"); break;
1272 default: assert(0);
1273 }
1274
Adam Sawicki1f84f622019-07-02 13:40:01 +02001275 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001276
1277 // Create VkSurfaceKHR.
1278 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1279 surfaceInfo.hinstance = g_hAppInstance;
1280 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001281 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001282 assert(result == VK_SUCCESS);
1283
1284 if(g_EnableValidationLayer == true)
1285 RegisterDebugCallbacks();
1286
1287 // Find physical device
1288
1289 uint32_t deviceCount = 0;
1290 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1291 assert(deviceCount > 0);
1292
1293 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1294 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1295
1296 g_hPhysicalDevice = physicalDevices[0];
1297
Adam Sawicki50882502020-02-07 16:51:31 +01001298 // Query for extensions
1299
1300 uint32_t physicalDeviceExtensionPropertyCount = 0;
1301 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &physicalDeviceExtensionPropertyCount, nullptr) );
1302 std::vector<VkExtensionProperties> physicalDeviceExtensionProperties{physicalDeviceExtensionPropertyCount};
1303 if(physicalDeviceExtensionPropertyCount)
1304 {
1305 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(
1306 g_hPhysicalDevice,
1307 nullptr,
1308 &physicalDeviceExtensionPropertyCount,
1309 physicalDeviceExtensionProperties.data()) );
1310 }
1311
1312 for(uint32_t i = 0; i < physicalDeviceExtensionPropertyCount; ++i)
1313 {
1314 if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001315 {
1316 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1317 {
1318 VK_KHR_get_memory_requirements2_enabled = true;
1319 }
1320 }
Adam Sawicki50882502020-02-07 16:51:31 +01001321 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001322 {
1323 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1324 {
1325 VK_KHR_dedicated_allocation_enabled = true;
1326 }
1327 }
Adam Sawicki50882502020-02-07 16:51:31 +01001328 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001329 {
1330 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1331 {
1332 VK_KHR_bind_memory2_enabled = true;
1333 }
1334 }
Adam Sawicki50882502020-02-07 16:51:31 +01001335 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
1336 VK_EXT_memory_budget_enabled = true;
1337 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) == 0)
1338 VK_AMD_device_coherent_memory_enabled = true;
1339 }
1340
Adam Sawickie6e498f2017-06-16 17:21:31 +02001341 // Query for features
1342
1343 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1344 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1345
Adam Sawicki50882502020-02-07 16:51:31 +01001346 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1347 VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };
1348 if(VK_AMD_device_coherent_memory_enabled)
1349 {
1350 physicalDeviceCoherentMemoryFeatures.pNext = physicalDeviceFeatures.pNext;
1351 physicalDeviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1352 }
1353 vkGetPhysicalDeviceFeatures2(g_hPhysicalDevice, &physicalDeviceFeatures);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001354
Adam Sawicki50882502020-02-07 16:51:31 +01001355 g_SparseBindingEnabled = physicalDeviceFeatures.features.sparseBinding != 0;
1356
1357 // The extension is supported as fake with no real support for this feature? Don't use it.
1358 if(VK_AMD_device_coherent_memory_enabled && !physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory)
1359 VK_AMD_device_coherent_memory_enabled = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001360
1361 // Find queue family index
1362
1363 uint32_t queueFamilyCount = 0;
1364 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1365 assert(queueFamilyCount > 0);
1366 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1367 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1368 for(uint32_t i = 0;
1369 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001370 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1371 g_PresentQueueFamilyIndex == UINT_MAX ||
1372 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001373 ++i)
1374 {
1375 if(queueFamilies[i].queueCount > 0)
1376 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001377 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001378 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001379 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001380 {
1381 g_GraphicsQueueFamilyIndex = i;
1382 }
1383
1384 VkBool32 surfaceSupported = 0;
1385 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1386 if((res >= 0) && (surfaceSupported == VK_TRUE))
1387 {
1388 g_PresentQueueFamilyIndex = i;
1389 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001390
1391 if(g_SparseBindingEnabled &&
1392 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1393 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1394 {
1395 g_SparseBindingQueueFamilyIndex = i;
1396 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001397 }
1398 }
1399 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1400
Adam Sawicki51fa9662018-10-03 13:44:29 +02001401 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1402
Adam Sawickie6e498f2017-06-16 17:21:31 +02001403 // Create logical device
1404
1405 const float queuePriority = 1.f;
1406
Adam Sawicki51fa9662018-10-03 13:44:29 +02001407 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1408 uint32_t queueCount = 1;
1409 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1410 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1411 queueCreateInfo[0].queueCount = 1;
1412 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1413
1414 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1415 {
1416
1417 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1418 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1419 queueCreateInfo[queueCount].queueCount = 1;
1420 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1421 ++queueCount;
1422 }
1423
1424 if(g_SparseBindingEnabled &&
1425 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1426 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1427 {
1428
1429 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1430 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1431 queueCreateInfo[queueCount].queueCount = 1;
1432 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1433 ++queueCount;
1434 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001435
Adam Sawickie6e498f2017-06-16 17:21:31 +02001436 std::vector<const char*> enabledDeviceExtensions;
1437 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki50882502020-02-07 16:51:31 +01001438 if(VK_KHR_get_memory_requirements2_enabled)
1439 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1440 if(VK_KHR_dedicated_allocation_enabled)
1441 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1442 if(VK_KHR_bind_memory2_enabled)
1443 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1444 if(VK_EXT_memory_budget_enabled)
1445 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
1446 if(VK_AMD_device_coherent_memory_enabled)
1447 enabledDeviceExtensions.push_back(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME);
1448
1449 VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1450 deviceFeatures.features.samplerAnisotropy = VK_TRUE;
1451 deviceFeatures.features.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
1452
1453 if(VK_AMD_device_coherent_memory_enabled)
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001454 {
Adam Sawicki50882502020-02-07 16:51:31 +01001455 physicalDeviceCoherentMemoryFeatures.pNext = deviceFeatures.pNext;
1456 deviceFeatures.pNext = &physicalDeviceCoherentMemoryFeatures;
1457 physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory = VK_TRUE;
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001458 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001459
1460 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
Adam Sawicki50882502020-02-07 16:51:31 +01001461 deviceCreateInfo.pNext = &deviceFeatures;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001462 deviceCreateInfo.enabledLayerCount = 0;
1463 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1464 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001465 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001466 deviceCreateInfo.queueCreateInfoCount = queueCount;
1467 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001468
Adam Sawicki1f84f622019-07-02 13:40:01 +02001469 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001470
1471 // Create memory allocator
1472
1473 VmaAllocatorCreateInfo allocatorInfo = {};
Adam Sawicki50882502020-02-07 16:51:31 +01001474 SetAllocatorCreateInfo(allocatorInfo);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001475 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1476
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001477 PrintEnabledFeatures();
1478
Adam Sawicki51fa9662018-10-03 13:44:29 +02001479 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001480
1481 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1482 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1483 assert(g_hGraphicsQueue);
1484 assert(g_hPresentQueue);
1485
Adam Sawicki51fa9662018-10-03 13:44:29 +02001486 if(g_SparseBindingEnabled)
1487 {
1488 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1489 assert(g_hSparseBindingQueue);
1490 }
1491
Adam Sawickie6e498f2017-06-16 17:21:31 +02001492 // Create command pool
1493
1494 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1495 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1496 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001497 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001498
1499 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1500 commandBufferInfo.commandPool = g_hCommandPool;
1501 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1502 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1503 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1504
1505 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1506 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1507 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1508 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001509 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001510 }
1511
Adam Sawicki1f84f622019-07-02 13:40:01 +02001512 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001513
Adam Sawickie6e498f2017-06-16 17:21:31 +02001514 commandBufferInfo.commandBufferCount = 1;
1515 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1516
1517 // Create texture sampler
1518
1519 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1520 samplerInfo.magFilter = VK_FILTER_LINEAR;
1521 samplerInfo.minFilter = VK_FILTER_LINEAR;
1522 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1523 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1524 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1525 samplerInfo.anisotropyEnable = VK_TRUE;
1526 samplerInfo.maxAnisotropy = 16;
1527 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1528 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1529 samplerInfo.compareEnable = VK_FALSE;
1530 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1531 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1532 samplerInfo.mipLodBias = 0.f;
1533 samplerInfo.minLod = 0.f;
1534 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001535 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001536
1537 CreateTexture(128, 128);
1538 CreateMesh();
1539
1540 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1541 samplerLayoutBinding.binding = 1;
1542 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1543 samplerLayoutBinding.descriptorCount = 1;
1544 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1545
1546 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1547 descriptorSetLayoutInfo.bindingCount = 1;
1548 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001549 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001550
1551 // Create descriptor pool
1552
1553 VkDescriptorPoolSize descriptorPoolSizes[2];
1554 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1555 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1556 descriptorPoolSizes[0].descriptorCount = 1;
1557 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1558 descriptorPoolSizes[1].descriptorCount = 1;
1559
1560 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1561 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1562 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1563 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001564 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001565
1566 // Create descriptor set layout
1567
1568 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1569 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1570 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1571 descriptorSetInfo.descriptorSetCount = 1;
1572 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1573 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1574
1575 VkDescriptorImageInfo descriptorImageInfo = {};
1576 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1577 descriptorImageInfo.imageView = g_hTextureImageView;
1578 descriptorImageInfo.sampler = g_hSampler;
1579
1580 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1581 writeDescriptorSet.dstSet = g_hDescriptorSet;
1582 writeDescriptorSet.dstBinding = 1;
1583 writeDescriptorSet.dstArrayElement = 0;
1584 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1585 writeDescriptorSet.descriptorCount = 1;
1586 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1587
1588 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1589
1590 CreateSwapchain();
1591}
1592
1593static void FinalizeApplication()
1594{
1595 vkDeviceWaitIdle(g_hDevice);
1596
1597 DestroySwapchain(true);
1598
1599 if(g_hDescriptorPool != VK_NULL_HANDLE)
1600 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001601 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001602 g_hDescriptorPool = VK_NULL_HANDLE;
1603 }
1604
1605 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1606 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001607 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001608 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1609 }
1610
1611 if(g_hTextureImageView != VK_NULL_HANDLE)
1612 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001613 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001614 g_hTextureImageView = VK_NULL_HANDLE;
1615 }
1616 if(g_hTextureImage != VK_NULL_HANDLE)
1617 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001618 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001619 g_hTextureImage = VK_NULL_HANDLE;
1620 }
1621
1622 if(g_hIndexBuffer != VK_NULL_HANDLE)
1623 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001624 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001625 g_hIndexBuffer = VK_NULL_HANDLE;
1626 }
1627 if(g_hVertexBuffer != VK_NULL_HANDLE)
1628 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001629 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001630 g_hVertexBuffer = VK_NULL_HANDLE;
1631 }
1632
1633 if(g_hSampler != VK_NULL_HANDLE)
1634 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001635 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001636 g_hSampler = VK_NULL_HANDLE;
1637 }
1638
Adam Sawicki51fa9662018-10-03 13:44:29 +02001639 if(g_ImmediateFence)
1640 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001641 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001642 g_ImmediateFence = VK_NULL_HANDLE;
1643 }
1644
Adam Sawickie6e498f2017-06-16 17:21:31 +02001645 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1646 {
1647 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1648 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001649 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001650 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1651 }
1652 }
1653 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1654 {
1655 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1656 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1657 }
1658 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1659 {
1660 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1661 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1662 }
1663
1664 if(g_hCommandPool != VK_NULL_HANDLE)
1665 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001666 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001667 g_hCommandPool = VK_NULL_HANDLE;
1668 }
1669
1670 if(g_hAllocator != VK_NULL_HANDLE)
1671 {
1672 vmaDestroyAllocator(g_hAllocator);
1673 g_hAllocator = nullptr;
1674 }
1675
1676 if(g_hDevice != VK_NULL_HANDLE)
1677 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001678 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001679 g_hDevice = nullptr;
1680 }
1681
1682 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1683 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001684 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001685 g_hCallback = VK_NULL_HANDLE;
1686 }
1687
1688 if(g_hSurface != VK_NULL_HANDLE)
1689 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001690 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001691 g_hSurface = VK_NULL_HANDLE;
1692 }
1693
1694 if(g_hVulkanInstance != VK_NULL_HANDLE)
1695 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001696 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001697 g_hVulkanInstance = VK_NULL_HANDLE;
1698 }
1699}
1700
1701static void PrintAllocatorStats()
1702{
1703#if VMA_STATS_STRING_ENABLED
1704 char* statsString = nullptr;
1705 vmaBuildStatsString(g_hAllocator, &statsString, true);
1706 printf("%s\n", statsString);
1707 vmaFreeStatsString(g_hAllocator, statsString);
1708#endif
1709}
1710
1711static void RecreateSwapChain()
1712{
1713 vkDeviceWaitIdle(g_hDevice);
1714 DestroySwapchain(false);
1715 CreateSwapchain();
1716}
1717
1718static void DrawFrame()
1719{
1720 // Begin main command buffer
1721 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1722 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1723 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1724
1725 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1726 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1727
1728 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1729 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1730 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1731
1732 // Acquire swapchain image
1733 uint32_t imageIndex = 0;
1734 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1735 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1736 {
1737 RecreateSwapChain();
1738 return;
1739 }
1740 else if(res < 0)
1741 {
1742 ERR_GUARD_VULKAN(res);
1743 }
1744
1745 // Record geometry pass
1746
1747 VkClearValue clearValues[2];
1748 ZeroMemory(clearValues, sizeof(clearValues));
1749 clearValues[0].color.float32[0] = 0.25f;
1750 clearValues[0].color.float32[1] = 0.25f;
1751 clearValues[0].color.float32[2] = 0.5f;
1752 clearValues[0].color.float32[3] = 1.0f;
1753 clearValues[1].depthStencil.depth = 1.0f;
1754
1755 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1756 renderPassBeginInfo.renderPass = g_hRenderPass;
1757 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1758 renderPassBeginInfo.renderArea.offset.x = 0;
1759 renderPassBeginInfo.renderArea.offset.y = 0;
1760 renderPassBeginInfo.renderArea.extent = g_Extent;
1761 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1762 renderPassBeginInfo.pClearValues = clearValues;
1763 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1764
1765 vkCmdBindPipeline(
1766 hCommandBuffer,
1767 VK_PIPELINE_BIND_POINT_GRAPHICS,
1768 g_hPipeline);
1769
Adam Sawicki82c3f332018-06-11 15:27:33 +02001770 mat4 view = mat4::LookAt(
1771 vec3(0.f, 0.f, 0.f),
1772 vec3(0.f, -2.f, 4.f),
1773 vec3(0.f, 1.f, 0.f));
1774 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001775 1.0471975511966f, // 60 degrees
1776 (float)g_Extent.width / (float)g_Extent.height,
1777 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001778 1000.f);
1779 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001780
1781 vkCmdBindDescriptorSets(
1782 hCommandBuffer,
1783 VK_PIPELINE_BIND_POINT_GRAPHICS,
1784 g_hPipelineLayout,
1785 0,
1786 1,
1787 &g_hDescriptorSet,
1788 0,
1789 nullptr);
1790
Adam Sawicki82c3f332018-06-11 15:27:33 +02001791 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1792 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001793
1794 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001795 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001796 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1797
1798 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1799 VkDeviceSize offsets[] = { 0 };
1800 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1801
1802 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1803
1804 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1805
1806 vkCmdEndRenderPass(hCommandBuffer);
1807
1808 vkEndCommandBuffer(hCommandBuffer);
1809
1810 // Submit command buffer
1811
1812 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1813 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1814 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1815 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1816 submitInfo.waitSemaphoreCount = 1;
1817 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1818 submitInfo.pWaitDstStageMask = submitWaitStages;
1819 submitInfo.commandBufferCount = 1;
1820 submitInfo.pCommandBuffers = &hCommandBuffer;
1821 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1822 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1823 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1824
1825 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1826
1827 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1828 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1829 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1830 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1831 presentInfo.swapchainCount = 1;
1832 presentInfo.pSwapchains = swapchains;
1833 presentInfo.pImageIndices = &imageIndex;
1834 presentInfo.pResults = nullptr;
1835 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1836 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1837 {
1838 RecreateSwapChain();
1839 }
1840 else
1841 ERR_GUARD_VULKAN(res);
1842}
1843
1844static void HandlePossibleSizeChange()
1845{
1846 RECT clientRect;
1847 GetClientRect(g_hWnd, &clientRect);
1848 LONG newSizeX = clientRect.right - clientRect.left;
1849 LONG newSizeY = clientRect.bottom - clientRect.top;
1850 if((newSizeX > 0) &&
1851 (newSizeY > 0) &&
1852 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1853 {
1854 g_SizeX = newSizeX;
1855 g_SizeY = newSizeY;
1856
1857 RecreateSwapChain();
1858 }
1859}
1860
1861static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1862{
1863 switch(msg)
1864 {
1865 case WM_CREATE:
1866 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1867 g_hWnd = hWnd;
1868 InitializeApplication();
1869 PrintAllocatorStats();
1870 return 0;
1871
1872 case WM_DESTROY:
1873 FinalizeApplication();
1874 PostQuitMessage(0);
1875 return 0;
1876
1877 // This prevents app from freezing when left Alt is pressed
1878 // (which normally enters modal menu loop).
1879 case WM_SYSKEYDOWN:
1880 case WM_SYSKEYUP:
1881 return 0;
1882
1883 case WM_SIZE:
1884 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1885 HandlePossibleSizeChange();
1886 return 0;
1887
1888 case WM_EXITSIZEMOVE:
1889 HandlePossibleSizeChange();
1890 return 0;
1891
1892 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001893 switch(wParam)
1894 {
1895 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001896 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001897 break;
1898 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001899 try
1900 {
1901 Test();
1902 }
1903 catch(const std::exception& ex)
1904 {
1905 printf("ERROR: %s\n", ex.what());
1906 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001907 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001908 case 'S':
1909 try
1910 {
1911 if(g_SparseBindingEnabled)
1912 {
1913 TestSparseBinding();
1914 }
1915 else
1916 {
1917 printf("Sparse binding not supported.\n");
1918 }
1919 }
1920 catch(const std::exception& ex)
1921 {
1922 printf("ERROR: %s\n", ex.what());
1923 }
1924 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001925 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001926 return 0;
1927
1928 default:
1929 break;
1930 }
1931
1932 return DefWindowProc(hWnd, msg, wParam, lParam);
1933}
1934
1935int main()
1936{
1937 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1938
1939 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1940 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1941 wndClassDesc.hbrBackground = NULL;
1942 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1943 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1944 wndClassDesc.hInstance = g_hAppInstance;
1945 wndClassDesc.lpfnWndProc = WndProc;
1946 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1947
1948 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1949 assert(hWndClass);
1950
1951 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1952 const DWORD exStyle = 0;
1953
1954 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1955 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1956
Adam Sawicki86ccd632017-07-04 14:57:53 +02001957 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001958 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1959 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1960 NULL, NULL, g_hAppInstance, NULL);
1961
1962 MSG msg;
1963 for(;;)
1964 {
1965 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1966 {
1967 if(msg.message == WM_QUIT)
1968 break;
1969 TranslateMessage(&msg);
1970 DispatchMessage(&msg);
1971 }
1972 if(g_hDevice != VK_NULL_HANDLE)
1973 DrawFrame();
1974 }
1975
Adam Sawicki8317ba92019-11-18 13:14:11 +01001976 TEST(g_CpuAllocCount.load() == 0);
1977
Adam Sawickie6e498f2017-06-16 17:21:31 +02001978 return 0;
1979}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001980
Adam Sawickif1a793c2018-03-13 15:42:22 +01001981#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001982
Adam Sawickif1a793c2018-03-13 15:42:22 +01001983#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001984
1985int main()
1986{
1987}
1988
Adam Sawickif1a793c2018-03-13 15:42:22 +01001989#endif // #ifdef _WIN32