blob: 75b0a91ff751843e853dce40b3d96ef0d5f9565e [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawickiae5c4662019-01-02 10:23:35 +01002// Copyright (c) 2017-2019 Advanced Micro Devices, Inc. All rights reserved.
Adam Sawickie6e498f2017-06-16 17:21:31 +02003//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21//
22
Adam Sawickif1a793c2018-03-13 15:42:22 +010023#ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +020024
Adam Sawicki51fa9662018-10-03 13:44:29 +020025#include "SparseBindingTest.h"
Adam Sawickif1a793c2018-03-13 15:42:22 +010026#include "Tests.h"
27#include "VmaUsage.h"
28#include "Common.h"
Adam Sawickie6e498f2017-06-16 17:21:31 +020029
30static const char* const SHADER_PATH1 = "./";
31static const char* const SHADER_PATH2 = "../bin/";
32static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
33static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_LUNARG_standard_validation";
Adam Sawicki6c8b7a22019-03-05 13:40:29 +010034static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.3.0-development";
35static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.3.0-development";
Adam Sawickie6e498f2017-06-16 17:21:31 +020036
37static const bool VSYNC = true;
38static const uint32_t COMMAND_BUFFER_COUNT = 2;
Adam Sawickia68c01c2018-03-13 16:40:45 +010039static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
40static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +020041
Adam Sawickib8333fb2018-03-13 16:15:53 +010042VkPhysicalDevice g_hPhysicalDevice;
43VkDevice g_hDevice;
44VmaAllocator g_hAllocator;
45bool g_MemoryAliasingWarningEnabled = true;
46
Adam Sawickia68c01c2018-03-13 16:40:45 +010047static bool g_EnableValidationLayer = true;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010048static bool VK_KHR_get_memory_requirements2_enabled = false;
49static bool VK_KHR_dedicated_allocation_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020050bool g_SparseBindingEnabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010051
Adam Sawickie6e498f2017-06-16 17:21:31 +020052static HINSTANCE g_hAppInstance;
53static HWND g_hWnd;
54static LONG g_SizeX = 1280, g_SizeY = 720;
55static VkInstance g_hVulkanInstance;
56static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020057static VkQueue g_hPresentQueue;
58static VkSurfaceFormatKHR g_SurfaceFormat;
59static VkExtent2D g_Extent;
60static VkSwapchainKHR g_hSwapchain;
61static std::vector<VkImage> g_SwapchainImages;
62static std::vector<VkImageView> g_SwapchainImageViews;
63static std::vector<VkFramebuffer> g_Framebuffers;
64static VkCommandPool g_hCommandPool;
65static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
66static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020067VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020068static uint32_t g_NextCommandBufferIndex;
69static VkSemaphore g_hImageAvailableSemaphore;
70static VkSemaphore g_hRenderFinishedSemaphore;
71static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
72static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020073static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020074static VkDescriptorSetLayout g_hDescriptorSetLayout;
75static VkDescriptorPool g_hDescriptorPool;
76static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
77static VkSampler g_hSampler;
78static VkFormat g_DepthFormat;
79static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +020080static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +020081static VkImageView g_hDepthImageView;
82
83static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
84static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
85static std::vector<VkPresentModeKHR> g_PresentModes;
86
87static PFN_vkCreateDebugReportCallbackEXT g_pvkCreateDebugReportCallbackEXT;
88static PFN_vkDebugReportMessageEXT g_pvkDebugReportMessageEXT;
89static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
90static VkDebugReportCallbackEXT g_hCallback;
91
Adam Sawickie6e498f2017-06-16 17:21:31 +020092static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +020093VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +010094VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +020095
96static VkPipelineLayout g_hPipelineLayout;
97static VkRenderPass g_hRenderPass;
98static VkPipeline g_hPipeline;
99
100static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200101static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200102static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200103static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200104static uint32_t g_VertexCount;
105static uint32_t g_IndexCount;
106
107static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200108static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200109static VkImageView g_hTextureImageView;
110
Adam Sawickia68c01c2018-03-13 16:40:45 +0100111static void* CustomCpuAllocation(
112 void* pUserData, size_t size, size_t alignment,
113 VkSystemAllocationScope allocationScope)
114{
115 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
116 return _aligned_malloc(size, alignment);
117}
118
119static void* CustomCpuReallocation(
120 void* pUserData, void* pOriginal, size_t size, size_t alignment,
121 VkSystemAllocationScope allocationScope)
122{
123 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
124 return _aligned_realloc(pOriginal, size, alignment);
125}
126
127static void CustomCpuFree(void* pUserData, void* pMemory)
128{
129 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
130 _aligned_free(pMemory);
131}
132
Adam Sawicki1f84f622019-07-02 13:40:01 +0200133static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
134 CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA, // pUserData
135 &CustomCpuAllocation, // pfnAllocation
136 &CustomCpuReallocation, // pfnReallocation
137 &CustomCpuFree // pfnFree
138};
139
140const VkAllocationCallbacks* g_Allocs;
141
Adam Sawicki978fcf52018-12-05 14:38:48 +0100142void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200143{
144 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
145 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
146 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
147}
148
Adam Sawicki978fcf52018-12-05 14:38:48 +0100149void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200150{
151 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
152
153 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
154 submitInfo.commandBufferCount = 1;
155 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
156
157 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
158 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
159}
160
Adam Sawickida6c1942018-12-05 17:34:34 +0100161void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200162{
163 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
164 if(file.is_open() == false)
165 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
166 assert(file.is_open());
167 size_t fileSize = (size_t)file.tellg();
168 if(fileSize > 0)
169 {
170 out.resize(fileSize);
171 file.seekg(0);
172 file.read(out.data(), fileSize);
173 file.close();
174 }
175 else
176 out.clear();
177}
178
179VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback(
180 VkDebugReportFlagsEXT flags,
181 VkDebugReportObjectTypeEXT objectType,
182 uint64_t object,
183 size_t location,
184 int32_t messageCode,
185 const char* pLayerPrefix,
186 const char* pMessage,
187 void* pUserData)
188{
Adam Sawickib8333fb2018-03-13 16:15:53 +0100189 // "Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug."
190 if(!g_MemoryAliasingWarningEnabled && flags == VK_DEBUG_REPORT_WARNING_BIT_EXT &&
191 (strstr(pMessage, " is aliased with non-linear ") || strstr(pMessage, " is aliased with linear ")))
192 {
193 return VK_FALSE;
194 }
195
196 // Ignoring because when VK_KHR_dedicated_allocation extension is enabled,
197 // vkGetBufferMemoryRequirements2KHR function is used instead, while Validation
198 // Layer seems to be unaware of it.
199 if (strstr(pMessage, "but vkGetBufferMemoryRequirements() has not been called on that buffer") != nullptr)
200 {
201 return VK_FALSE;
202 }
203 if (strstr(pMessage, "but vkGetImageMemoryRequirements() has not been called on that image") != nullptr)
204 {
205 return VK_FALSE;
206 }
Adam Sawicki94e82062018-08-20 11:12:51 +0200207
208 /*
209 "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."
210 Ignoring because we map entire VkDeviceMemory blocks, where different types of
211 images and buffers may end up together, especially on GPUs with unified memory
212 like Intel.
213 */
214 if(strstr(pMessage, "Mapping an image with layout") != nullptr &&
215 strstr(pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr)
216 {
217 return VK_FALSE;
218 }
Adam Sawickib8333fb2018-03-13 16:15:53 +0100219
220 switch(flags)
221 {
222 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
223 SetConsoleColor(CONSOLE_COLOR::WARNING);
224 break;
225 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
226 SetConsoleColor(CONSOLE_COLOR::ERROR_);
227 break;
228 default:
229 SetConsoleColor(CONSOLE_COLOR::INFO);
230 }
231
Adam Sawickie6e498f2017-06-16 17:21:31 +0200232 printf("%s \xBA %s\n", pLayerPrefix, pMessage);
233
Adam Sawickib8333fb2018-03-13 16:15:53 +0100234 SetConsoleColor(CONSOLE_COLOR::NORMAL);
235
236 if(flags == VK_DEBUG_REPORT_WARNING_BIT_EXT ||
237 flags == VK_DEBUG_REPORT_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200238 {
239 OutputDebugStringA(pMessage);
240 OutputDebugStringA("\n");
241 }
242
243 return VK_FALSE;
244}
245
246static VkSurfaceFormatKHR ChooseSurfaceFormat()
247{
248 assert(!g_SurfaceFormats.empty());
249
250 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
251 {
252 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
253 return result;
254 }
255
256 for(const auto& format : g_SurfaceFormats)
257 {
258 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
259 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
260 {
261 return format;
262 }
263 }
264
265 return g_SurfaceFormats[0];
266}
267
268VkPresentModeKHR ChooseSwapPresentMode()
269{
270 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
271
272 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
273 g_PresentModes.end())
274 {
275 return preferredMode;
276 }
277
278 return VK_PRESENT_MODE_FIFO_KHR;
279}
280
281static VkExtent2D ChooseSwapExtent()
282{
283 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
284 return g_SurfaceCapabilities.currentExtent;
285
286 VkExtent2D result = {
287 std::max(g_SurfaceCapabilities.minImageExtent.width,
288 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
289 std::max(g_SurfaceCapabilities.minImageExtent.height,
290 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
291 return result;
292}
293
294struct Vertex
295{
296 float pos[3];
297 float color[3];
298 float texCoord[2];
299};
300
301static void CreateMesh()
302{
303 assert(g_hAllocator);
304
305 static Vertex vertices[] = {
306 // -X
307 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
308 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
309 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
310 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
311 // +X
312 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
313 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
314 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
315 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
316 // -Z
317 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
318 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
319 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
320 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
321 // +Z
322 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
323 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
324 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
325 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
326 // -Y
327 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
328 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
329 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
330 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
331 // +Y
332 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
333 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
334 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
335 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
336 };
337 static uint16_t indices[] = {
338 0, 1, 2, 3, USHRT_MAX,
339 4, 5, 6, 7, USHRT_MAX,
340 8, 9, 10, 11, USHRT_MAX,
341 12, 13, 14, 15, USHRT_MAX,
342 16, 17, 18, 19, USHRT_MAX,
343 20, 21, 22, 23, USHRT_MAX,
344 };
345
346 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
347 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
348 g_IndexCount = (uint32_t)_countof(indices);
349
350 // Create vertex buffer
351
352 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
353 vbInfo.size = vertexBufferSize;
354 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
355 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200356
Adam Sawicki976f9202017-09-12 20:45:14 +0200357 VmaAllocationCreateInfo vbAllocCreateInfo = {};
358 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100359 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200360
Adam Sawicki819860e2017-07-04 14:30:38 +0200361 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
362 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
363 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200364 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200365
366 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200367
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200368 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
369
Adam Sawickie6e498f2017-06-16 17:21:31 +0200370 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200371 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
372 vbAllocCreateInfo.flags = 0;
373 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200374
375 // Create index buffer
376
377 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
378 ibInfo.size = indexBufferSize;
379 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
380 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200381
Adam Sawicki976f9202017-09-12 20:45:14 +0200382 VmaAllocationCreateInfo ibAllocCreateInfo = {};
383 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100384 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200385
Adam Sawickie6e498f2017-06-16 17:21:31 +0200386 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200387 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
388 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200389 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200390
Adam Sawicki819860e2017-07-04 14:30:38 +0200391 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200392
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200393 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
394
Adam Sawickie6e498f2017-06-16 17:21:31 +0200395 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200396 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
397 ibAllocCreateInfo.flags = 0;
398 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200399
400 // Copy buffers
401
402 BeginSingleTimeCommands();
403
404 VkBufferCopy vbCopyRegion = {};
405 vbCopyRegion.srcOffset = 0;
406 vbCopyRegion.dstOffset = 0;
407 vbCopyRegion.size = vbInfo.size;
408 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
409
410 VkBufferCopy ibCopyRegion = {};
411 ibCopyRegion.srcOffset = 0;
412 ibCopyRegion.dstOffset = 0;
413 ibCopyRegion.size = ibInfo.size;
414 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
415
416 EndSingleTimeCommands();
417
Adam Sawicki819860e2017-07-04 14:30:38 +0200418 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
419 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200420}
421
Adam Sawickie6e498f2017-06-16 17:21:31 +0200422static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
423{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100424 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200425
426 const VkDeviceSize imageSize = sizeX * sizeY * 4;
427
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100428 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
429 stagingBufInfo.size = imageSize;
430 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
431
432 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
433 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
434 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200435
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100436 VkBuffer stagingBuf = VK_NULL_HANDLE;
437 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
438 VmaAllocationInfo stagingBufAllocInfo = {};
439 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200440
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100441 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
442 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200443 for(uint32_t y = 0; y < sizeY; ++y)
444 {
445 uint32_t* pPixelData = (uint32_t*)pRowData;
446 for(uint32_t x = 0; x < sizeY; ++x)
447 {
448 *pPixelData =
449 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
450 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
451 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
452 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
453 ++pPixelData;
454 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100455 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200456 }
457
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200458 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
459
Adam Sawicki10844a82017-08-16 17:32:09 +0200460 // Create g_hTextureImage in GPU memory.
461
Adam Sawickie6e498f2017-06-16 17:21:31 +0200462 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
463 imageInfo.imageType = VK_IMAGE_TYPE_2D;
464 imageInfo.extent.width = sizeX;
465 imageInfo.extent.height = sizeY;
466 imageInfo.extent.depth = 1;
467 imageInfo.mipLevels = 1;
468 imageInfo.arrayLayers = 1;
469 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
470 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
471 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
472 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
473 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
474 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
475 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200476
Adam Sawicki976f9202017-09-12 20:45:14 +0200477 VmaAllocationCreateInfo imageAllocCreateInfo = {};
478 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200479
Adam Sawicki976f9202017-09-12 20:45:14 +0200480 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200481
Adam Sawicki10844a82017-08-16 17:32:09 +0200482 // Transition image layouts, copy image.
483
484 BeginSingleTimeCommands();
485
486 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200487 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
488 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200489 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
490 imgMemBarrier.subresourceRange.baseMipLevel = 0;
491 imgMemBarrier.subresourceRange.levelCount = 1;
492 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
493 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200494 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
495 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
496 imgMemBarrier.image = g_hTextureImage;
497 imgMemBarrier.srcAccessMask = 0;
498 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
499
500 vkCmdPipelineBarrier(
501 g_hTemporaryCommandBuffer,
502 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
503 VK_PIPELINE_STAGE_TRANSFER_BIT,
504 0,
505 0, nullptr,
506 0, nullptr,
507 1, &imgMemBarrier);
508
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100509 VkBufferImageCopy region = {};
510 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
511 region.imageSubresource.layerCount = 1;
512 region.imageExtent.width = sizeX;
513 region.imageExtent.height = sizeY;
514 region.imageExtent.depth = 1;
515
516 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200517
518 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
519 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
520 imgMemBarrier.image = g_hTextureImage;
521 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
522 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
523
524 vkCmdPipelineBarrier(
525 g_hTemporaryCommandBuffer,
526 VK_PIPELINE_STAGE_TRANSFER_BIT,
527 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
528 0,
529 0, nullptr,
530 0, nullptr,
531 1, &imgMemBarrier);
532
533 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200534
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100535 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200536
537 // Create ImageView
538
539 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
540 textureImageViewInfo.image = g_hTextureImage;
541 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
542 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
543 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
544 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
545 textureImageViewInfo.subresourceRange.levelCount = 1;
546 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
547 textureImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200548 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200549}
550
551struct UniformBufferObject
552{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200553 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200554};
555
556static void RegisterDebugCallbacks()
557{
558 g_pvkCreateDebugReportCallbackEXT =
559 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
560 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
561 g_pvkDebugReportMessageEXT =
562 reinterpret_cast<PFN_vkDebugReportMessageEXT>
563 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
564 g_pvkDestroyDebugReportCallbackEXT =
565 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
566 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
567 assert(g_pvkCreateDebugReportCallbackEXT);
568 assert(g_pvkDebugReportMessageEXT);
569 assert(g_pvkDestroyDebugReportCallbackEXT);
570
571 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
572 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
573 callbackCreateInfo.pNext = nullptr;
574 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
575 VK_DEBUG_REPORT_ERROR_BIT_EXT |
576 VK_DEBUG_REPORT_WARNING_BIT_EXT |
577 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
578 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
579 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
580 callbackCreateInfo.pUserData = nullptr;
581
Adam Sawicki1f84f622019-07-02 13:40:01 +0200582 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, g_Allocs, &g_hCallback) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200583}
584
585static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
586{
587 const VkLayerProperties* propsEnd = pProps + propCount;
588 return std::find_if(
589 pProps,
590 propsEnd,
591 [pLayerName](const VkLayerProperties& prop) -> bool {
592 return strcmp(pLayerName, prop.layerName) == 0;
593 }) != propsEnd;
594}
595
596static VkFormat FindSupportedFormat(
597 const std::vector<VkFormat>& candidates,
598 VkImageTiling tiling,
599 VkFormatFeatureFlags features)
600{
601 for (VkFormat format : candidates)
602 {
603 VkFormatProperties props;
604 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
605
606 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
607 ((props.linearTilingFeatures & features) == features))
608 {
609 return format;
610 }
611 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
612 ((props.optimalTilingFeatures & features) == features))
613 {
614 return format;
615 }
616 }
617 return VK_FORMAT_UNDEFINED;
618}
619
620static VkFormat FindDepthFormat()
621{
622 std::vector<VkFormat> formats;
623 formats.push_back(VK_FORMAT_D32_SFLOAT);
624 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
625 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
626
627 return FindSupportedFormat(
628 formats,
629 VK_IMAGE_TILING_OPTIMAL,
630 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
631}
632
633static void CreateSwapchain()
634{
635 // Query surface formats.
636
637 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
638
639 uint32_t formatCount = 0;
640 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
641 g_SurfaceFormats.resize(formatCount);
642 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
643
644 uint32_t presentModeCount = 0;
645 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
646 g_PresentModes.resize(presentModeCount);
647 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
648
649 // Create swap chain
650
651 g_SurfaceFormat = ChooseSurfaceFormat();
652 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
653 g_Extent = ChooseSwapExtent();
654
655 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
656 if((g_SurfaceCapabilities.maxImageCount > 0) &&
657 (imageCount > g_SurfaceCapabilities.maxImageCount))
658 {
659 imageCount = g_SurfaceCapabilities.maxImageCount;
660 }
661
662 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
663 swapChainInfo.surface = g_hSurface;
664 swapChainInfo.minImageCount = imageCount;
665 swapChainInfo.imageFormat = g_SurfaceFormat.format;
666 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
667 swapChainInfo.imageExtent = g_Extent;
668 swapChainInfo.imageArrayLayers = 1;
669 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
670 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
671 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
672 swapChainInfo.presentMode = presentMode;
673 swapChainInfo.clipped = VK_TRUE;
674 swapChainInfo.oldSwapchain = g_hSwapchain;
675
676 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
677 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
678 {
679 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
680 swapChainInfo.queueFamilyIndexCount = 2;
681 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
682 }
683 else
684 {
685 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
686 }
687
688 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200689 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, g_Allocs, &hNewSwapchain) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200690 if(g_hSwapchain != VK_NULL_HANDLE)
Adam Sawicki1f84f622019-07-02 13:40:01 +0200691 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200692 g_hSwapchain = hNewSwapchain;
693
694 // Retrieve swapchain images.
695
696 uint32_t swapchainImageCount = 0;
697 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
698 g_SwapchainImages.resize(swapchainImageCount);
699 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
700
701 // Create swapchain image views.
702
703 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +0200704 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200705 g_SwapchainImageViews.clear();
706
707 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
708 g_SwapchainImageViews.resize(swapchainImageCount);
709 for(uint32_t i = 0; i < swapchainImageCount; ++i)
710 {
711 swapchainImageViewInfo.image = g_SwapchainImages[i];
712 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
713 swapchainImageViewInfo.format = g_SurfaceFormat.format;
714 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
715 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
716 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
717 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
718 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
719 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
720 swapchainImageViewInfo.subresourceRange.levelCount = 1;
721 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
722 swapchainImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200723 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200724 }
725
726 // Create depth buffer
727
728 g_DepthFormat = FindDepthFormat();
729 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
730
731 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
732 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
733 depthImageInfo.extent.width = g_Extent.width;
734 depthImageInfo.extent.height = g_Extent.height;
735 depthImageInfo.extent.depth = 1;
736 depthImageInfo.mipLevels = 1;
737 depthImageInfo.arrayLayers = 1;
738 depthImageInfo.format = g_DepthFormat;
739 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
740 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
741 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
742 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
743 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
744 depthImageInfo.flags = 0;
745
Adam Sawicki976f9202017-09-12 20:45:14 +0200746 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
747 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200748
Adam Sawicki976f9202017-09-12 20:45:14 +0200749 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200750
751 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
752 depthImageViewInfo.image = g_hDepthImage;
753 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
754 depthImageViewInfo.format = g_DepthFormat;
755 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
756 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
757 depthImageViewInfo.subresourceRange.levelCount = 1;
758 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
759 depthImageViewInfo.subresourceRange.layerCount = 1;
760
Adam Sawicki1f84f622019-07-02 13:40:01 +0200761 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200762
Adam Sawickie6e498f2017-06-16 17:21:31 +0200763 // Create pipeline layout
764 {
765 if(g_hPipelineLayout != VK_NULL_HANDLE)
766 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200767 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200768 g_hPipelineLayout = VK_NULL_HANDLE;
769 }
770
771 VkPushConstantRange pushConstantRanges[1];
772 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
773 pushConstantRanges[0].offset = 0;
774 pushConstantRanges[0].size = sizeof(UniformBufferObject);
775 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
776
777 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
778 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
779 pipelineLayoutInfo.setLayoutCount = 1;
780 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
781 pipelineLayoutInfo.pushConstantRangeCount = 1;
782 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200783 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200784 }
785
786 // Create render pass
787 {
788 if(g_hRenderPass != VK_NULL_HANDLE)
789 {
Adam Sawicki1f84f622019-07-02 13:40:01 +0200790 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200791 g_hRenderPass = VK_NULL_HANDLE;
792 }
793
794 VkAttachmentDescription attachments[2];
795 ZeroMemory(attachments, sizeof(attachments));
796
797 attachments[0].format = g_SurfaceFormat.format;
798 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
799 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
800 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
801 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
802 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100803 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200804 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
805
806 attachments[1].format = g_DepthFormat;
807 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
808 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
809 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
810 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
811 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100812 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200813 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
814
815 VkAttachmentReference colorAttachmentRef = {};
816 colorAttachmentRef.attachment = 0;
817 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
818
819 VkAttachmentReference depthStencilAttachmentRef = {};
820 depthStencilAttachmentRef.attachment = 1;
821 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
822
823 VkSubpassDescription subpassDesc = {};
824 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
825 subpassDesc.colorAttachmentCount = 1;
826 subpassDesc.pColorAttachments = &colorAttachmentRef;
827 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
828
Adam Sawickie6e498f2017-06-16 17:21:31 +0200829 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
830 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
831 renderPassInfo.pAttachments = attachments;
832 renderPassInfo.subpassCount = 1;
833 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200834 renderPassInfo.dependencyCount = 0;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200835 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200836 }
837
838 // Create pipeline
839 {
840 std::vector<char> vertShaderCode;
841 LoadShader(vertShaderCode, "Shader.vert.spv");
842 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
843 shaderModuleInfo.codeSize = vertShaderCode.size();
844 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
845 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200846 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200847
848 std::vector<char> hFragShaderCode;
849 LoadShader(hFragShaderCode, "Shader.frag.spv");
850 shaderModuleInfo.codeSize = hFragShaderCode.size();
851 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
852 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200853 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200854
855 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
856 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
857 vertPipelineShaderStageInfo.module = hVertShaderModule;
858 vertPipelineShaderStageInfo.pName = "main";
859
860 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
861 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
862 fragPipelineShaderStageInfo.module = fragShaderModule;
863 fragPipelineShaderStageInfo.pName = "main";
864
865 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
866 vertPipelineShaderStageInfo,
867 fragPipelineShaderStageInfo
868 };
869
870 VkVertexInputBindingDescription bindingDescription = {};
871 bindingDescription.binding = 0;
872 bindingDescription.stride = sizeof(Vertex);
873 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
874
875 VkVertexInputAttributeDescription attributeDescriptions[3];
876 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
877
878 attributeDescriptions[0].binding = 0;
879 attributeDescriptions[0].location = 0;
880 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
881 attributeDescriptions[0].offset = offsetof(Vertex, pos);
882
883 attributeDescriptions[1].binding = 0;
884 attributeDescriptions[1].location = 1;
885 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
886 attributeDescriptions[1].offset = offsetof(Vertex, color);
887
888 attributeDescriptions[2].binding = 0;
889 attributeDescriptions[2].location = 2;
890 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
891 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
892
893 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
894 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
895 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
896 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
897 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
898
899 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
900 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
901 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
902
903 VkViewport viewport = {};
904 viewport.x = 0.f;
905 viewport.y = 0.f;
906 viewport.width = (float)g_Extent.width;
907 viewport.height = (float)g_Extent.height;
908 viewport.minDepth = 0.f;
909 viewport.maxDepth = 1.f;
910
911 VkRect2D scissor = {};
912 scissor.offset.x = 0;
913 scissor.offset.y = 0;
914 scissor.extent = g_Extent;
915
916 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
917 pipelineViewportStateInfo.viewportCount = 1;
918 pipelineViewportStateInfo.pViewports = &viewport;
919 pipelineViewportStateInfo.scissorCount = 1;
920 pipelineViewportStateInfo.pScissors = &scissor;
921
922 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
923 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
924 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
925 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
926 pipelineRasterizationStateInfo.lineWidth = 1.f;
927 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
928 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
929 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
930 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
931 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
932 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
933
934 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
935 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
936 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
937 pipelineMultisampleStateInfo.minSampleShading = 1.f;
938 pipelineMultisampleStateInfo.pSampleMask = nullptr;
939 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
940 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
941
942 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
943 pipelineColorBlendAttachmentState.colorWriteMask =
944 VK_COLOR_COMPONENT_R_BIT |
945 VK_COLOR_COMPONENT_G_BIT |
946 VK_COLOR_COMPONENT_B_BIT |
947 VK_COLOR_COMPONENT_A_BIT;
948 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
949 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
950 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
951 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
952 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
953 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
954 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
955
956 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
957 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
958 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
959 pipelineColorBlendStateInfo.attachmentCount = 1;
960 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
961
962 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
963 depthStencilStateInfo.depthTestEnable = VK_TRUE;
964 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
965 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
966 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
967 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
968
969 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
970 pipelineInfo.stageCount = 2;
971 pipelineInfo.pStages = pipelineShaderStageInfos;
972 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
973 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
974 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
975 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
976 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
977 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
978 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
979 pipelineInfo.pDynamicState = nullptr;
980 pipelineInfo.layout = g_hPipelineLayout;
981 pipelineInfo.renderPass = g_hRenderPass;
982 pipelineInfo.subpass = 0;
983 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
984 pipelineInfo.basePipelineIndex = -1;
985 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
986 g_hDevice,
987 VK_NULL_HANDLE,
988 1,
Adam Sawicki1f84f622019-07-02 13:40:01 +0200989 &pipelineInfo,
990 g_Allocs,
Adam Sawickie6e498f2017-06-16 17:21:31 +0200991 &g_hPipeline) );
992
Adam Sawicki1f84f622019-07-02 13:40:01 +0200993 vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
994 vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200995 }
996
997 // Create frambuffers
998
999 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001000 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001001 g_Framebuffers.clear();
1002
1003 g_Framebuffers.resize(g_SwapchainImageViews.size());
1004 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1005 {
1006 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1007
1008 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1009 framebufferInfo.renderPass = g_hRenderPass;
1010 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1011 framebufferInfo.pAttachments = attachments;
1012 framebufferInfo.width = g_Extent.width;
1013 framebufferInfo.height = g_Extent.height;
1014 framebufferInfo.layers = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001015 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001016 }
1017
1018 // Create semaphores
1019
1020 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1021 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001022 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001023 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1024 }
1025 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1026 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001027 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001028 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1029 }
1030
1031 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
Adam Sawicki1f84f622019-07-02 13:40:01 +02001032 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
1033 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001034}
1035
1036static void DestroySwapchain(bool destroyActualSwapchain)
1037{
1038 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1039 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001040 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001041 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1042 }
1043 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1044 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001045 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001046 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1047 }
1048
1049 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001050 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001051 g_Framebuffers.clear();
1052
1053 if(g_hDepthImageView != VK_NULL_HANDLE)
1054 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001055 vkDestroyImageView(g_hDevice, g_hDepthImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001056 g_hDepthImageView = VK_NULL_HANDLE;
1057 }
1058 if(g_hDepthImage != VK_NULL_HANDLE)
1059 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001060 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001061 g_hDepthImage = VK_NULL_HANDLE;
1062 }
1063
1064 if(g_hPipeline != VK_NULL_HANDLE)
1065 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001066 vkDestroyPipeline(g_hDevice, g_hPipeline, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001067 g_hPipeline = VK_NULL_HANDLE;
1068 }
1069
1070 if(g_hRenderPass != VK_NULL_HANDLE)
1071 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001072 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001073 g_hRenderPass = VK_NULL_HANDLE;
1074 }
1075
1076 if(g_hPipelineLayout != VK_NULL_HANDLE)
1077 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001078 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001079 g_hPipelineLayout = VK_NULL_HANDLE;
1080 }
1081
1082 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001083 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001084 g_SwapchainImageViews.clear();
1085
1086 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1087 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001088 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001089 g_hSwapchain = VK_NULL_HANDLE;
1090 }
1091}
1092
1093static void InitializeApplication()
1094{
Adam Sawicki1f84f622019-07-02 13:40:01 +02001095 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1096 {
1097 g_Allocs = &g_CpuAllocationCallbacks;
1098 }
1099
Adam Sawickie6e498f2017-06-16 17:21:31 +02001100 uint32_t instanceLayerPropCount = 0;
1101 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1102 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1103 if(instanceLayerPropCount > 0)
1104 {
1105 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1106 }
1107
1108 if(g_EnableValidationLayer == true)
1109 {
1110 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1111 {
1112 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1113 g_EnableValidationLayer = false;
1114 }
1115 }
1116
1117 std::vector<const char*> instanceExtensions;
1118 instanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1119 instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
1120
1121 std::vector<const char*> instanceLayers;
1122 if(g_EnableValidationLayer == true)
1123 {
1124 instanceLayers.push_back(VALIDATION_LAYER_NAME);
1125 instanceExtensions.push_back("VK_EXT_debug_report");
1126 }
1127
1128 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1129 appInfo.pApplicationName = APP_TITLE_A;
1130 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1131 appInfo.pEngineName = "Adam Sawicki Engine";
1132 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
1133 appInfo.apiVersion = VK_API_VERSION_1_0;
1134
1135 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1136 instInfo.pApplicationInfo = &appInfo;
1137 instInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
1138 instInfo.ppEnabledExtensionNames = instanceExtensions.data();
1139 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1140 instInfo.ppEnabledLayerNames = instanceLayers.data();
1141
Adam Sawicki1f84f622019-07-02 13:40:01 +02001142 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001143
1144 // Create VkSurfaceKHR.
1145 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1146 surfaceInfo.hinstance = g_hAppInstance;
1147 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001148 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001149 assert(result == VK_SUCCESS);
1150
1151 if(g_EnableValidationLayer == true)
1152 RegisterDebugCallbacks();
1153
1154 // Find physical device
1155
1156 uint32_t deviceCount = 0;
1157 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1158 assert(deviceCount > 0);
1159
1160 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1161 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1162
1163 g_hPhysicalDevice = physicalDevices[0];
1164
1165 // Query for features
1166
1167 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1168 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1169
Adam Sawicki51fa9662018-10-03 13:44:29 +02001170 VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
1171 vkGetPhysicalDeviceFeatures(g_hPhysicalDevice, &physicalDeviceFeatures);
1172
1173 g_SparseBindingEnabled = physicalDeviceFeatures.sparseBinding != 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001174
1175 // Find queue family index
1176
1177 uint32_t queueFamilyCount = 0;
1178 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1179 assert(queueFamilyCount > 0);
1180 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1181 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1182 for(uint32_t i = 0;
1183 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001184 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1185 g_PresentQueueFamilyIndex == UINT_MAX ||
1186 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001187 ++i)
1188 {
1189 if(queueFamilies[i].queueCount > 0)
1190 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001191 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001192 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001193 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001194 {
1195 g_GraphicsQueueFamilyIndex = i;
1196 }
1197
1198 VkBool32 surfaceSupported = 0;
1199 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1200 if((res >= 0) && (surfaceSupported == VK_TRUE))
1201 {
1202 g_PresentQueueFamilyIndex = i;
1203 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001204
1205 if(g_SparseBindingEnabled &&
1206 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1207 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1208 {
1209 g_SparseBindingQueueFamilyIndex = i;
1210 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001211 }
1212 }
1213 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1214
Adam Sawicki51fa9662018-10-03 13:44:29 +02001215 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1216
Adam Sawickie6e498f2017-06-16 17:21:31 +02001217 // Create logical device
1218
1219 const float queuePriority = 1.f;
1220
Adam Sawicki51fa9662018-10-03 13:44:29 +02001221 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1222 uint32_t queueCount = 1;
1223 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1224 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1225 queueCreateInfo[0].queueCount = 1;
1226 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1227
1228 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1229 {
1230
1231 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1232 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1233 queueCreateInfo[queueCount].queueCount = 1;
1234 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1235 ++queueCount;
1236 }
1237
1238 if(g_SparseBindingEnabled &&
1239 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1240 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1241 {
1242
1243 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1244 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1245 queueCreateInfo[queueCount].queueCount = 1;
1246 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1247 ++queueCount;
1248 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001249
1250 VkPhysicalDeviceFeatures deviceFeatures = {};
Adam Sawicki51fa9662018-10-03 13:44:29 +02001251 //deviceFeatures.fillModeNonSolid = VK_TRUE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001252 deviceFeatures.samplerAnisotropy = VK_TRUE;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001253 deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001254
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001255 // Determine list of device extensions to enable.
Adam Sawickie6e498f2017-06-16 17:21:31 +02001256 std::vector<const char*> enabledDeviceExtensions;
1257 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001258 {
1259 uint32_t propertyCount = 0;
1260 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, nullptr) );
1261
1262 if(propertyCount)
1263 {
1264 std::vector<VkExtensionProperties> properties{propertyCount};
1265 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, properties.data()) );
1266
1267 for(uint32_t i = 0; i < propertyCount; ++i)
1268 {
1269 if(strcmp(properties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1270 {
1271 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1272 VK_KHR_get_memory_requirements2_enabled = true;
1273 }
1274 else if(strcmp(properties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1275 {
1276 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1277 VK_KHR_dedicated_allocation_enabled = true;
1278 }
1279 }
1280 }
1281 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001282
1283 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1284 deviceCreateInfo.enabledLayerCount = 0;
1285 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1286 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001287 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001288 deviceCreateInfo.queueCreateInfoCount = queueCount;
1289 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001290 deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
1291
Adam Sawicki1f84f622019-07-02 13:40:01 +02001292 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001293
1294 // Create memory allocator
1295
1296 VmaAllocatorCreateInfo allocatorInfo = {};
1297 allocatorInfo.physicalDevice = g_hPhysicalDevice;
1298 allocatorInfo.device = g_hDevice;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001299
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001300 if(VK_KHR_dedicated_allocation_enabled)
1301 {
Adam Sawickif48896d2019-04-16 12:55:35 +02001302 /*
1303 Comment out this line to make the app working with RenderDoc.
Adam Sawicki4fb254e2019-04-23 11:29:57 +02001304
1305 Currently there is a problem with compatibility of this app with RenderDoc due
1306 to a known bug in Vulkan validation layers:
Adam Sawickif48896d2019-04-16 12:55:35 +02001307
Adam Sawicki4fb254e2019-04-23 11:29:57 +02001308 https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/579
1309
1310 It occurs because this app uses Vulkan 1.0 and VK_KHR_dedicated_allocation
1311 extension instead of equivalent functionality embedded into Vulkan 1.1.
Adam Sawickif48896d2019-04-16 12:55:35 +02001312 */
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001313 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1314 }
Adam Sawickia68c01c2018-03-13 16:40:45 +01001315
Adam Sawickia68c01c2018-03-13 16:40:45 +01001316 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1317 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001318 allocatorInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001319 }
1320
Adam Sawickib0c36362018-11-13 16:17:38 +01001321 // Uncomment to enable recording to CSV file.
1322 /*
1323 {
1324 VmaRecordSettings recordSettings = {};
1325 recordSettings.pFilePath = "VulkanSample.csv";
1326 allocatorInfo.pRecordSettings = &recordSettings;
1327 }
1328 */
1329
Adam Sawickie6e498f2017-06-16 17:21:31 +02001330 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1331
Adam Sawicki51fa9662018-10-03 13:44:29 +02001332 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001333
1334 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1335 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1336 assert(g_hGraphicsQueue);
1337 assert(g_hPresentQueue);
1338
Adam Sawicki51fa9662018-10-03 13:44:29 +02001339 if(g_SparseBindingEnabled)
1340 {
1341 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1342 assert(g_hSparseBindingQueue);
1343 }
1344
Adam Sawickie6e498f2017-06-16 17:21:31 +02001345 // Create command pool
1346
1347 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1348 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1349 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001350 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001351
1352 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1353 commandBufferInfo.commandPool = g_hCommandPool;
1354 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1355 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1356 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1357
1358 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1359 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1360 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1361 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001362 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001363 }
1364
Adam Sawicki1f84f622019-07-02 13:40:01 +02001365 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02001366
Adam Sawickie6e498f2017-06-16 17:21:31 +02001367 commandBufferInfo.commandBufferCount = 1;
1368 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1369
1370 // Create texture sampler
1371
1372 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1373 samplerInfo.magFilter = VK_FILTER_LINEAR;
1374 samplerInfo.minFilter = VK_FILTER_LINEAR;
1375 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1376 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1377 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1378 samplerInfo.anisotropyEnable = VK_TRUE;
1379 samplerInfo.maxAnisotropy = 16;
1380 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1381 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1382 samplerInfo.compareEnable = VK_FALSE;
1383 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1384 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1385 samplerInfo.mipLodBias = 0.f;
1386 samplerInfo.minLod = 0.f;
1387 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001388 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001389
1390 CreateTexture(128, 128);
1391 CreateMesh();
1392
1393 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1394 samplerLayoutBinding.binding = 1;
1395 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1396 samplerLayoutBinding.descriptorCount = 1;
1397 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1398
1399 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1400 descriptorSetLayoutInfo.bindingCount = 1;
1401 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001402 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001403
1404 // Create descriptor pool
1405
1406 VkDescriptorPoolSize descriptorPoolSizes[2];
1407 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1408 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1409 descriptorPoolSizes[0].descriptorCount = 1;
1410 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1411 descriptorPoolSizes[1].descriptorCount = 1;
1412
1413 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1414 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1415 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1416 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001417 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001418
1419 // Create descriptor set layout
1420
1421 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1422 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1423 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1424 descriptorSetInfo.descriptorSetCount = 1;
1425 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1426 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1427
1428 VkDescriptorImageInfo descriptorImageInfo = {};
1429 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1430 descriptorImageInfo.imageView = g_hTextureImageView;
1431 descriptorImageInfo.sampler = g_hSampler;
1432
1433 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1434 writeDescriptorSet.dstSet = g_hDescriptorSet;
1435 writeDescriptorSet.dstBinding = 1;
1436 writeDescriptorSet.dstArrayElement = 0;
1437 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1438 writeDescriptorSet.descriptorCount = 1;
1439 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1440
1441 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1442
1443 CreateSwapchain();
1444}
1445
1446static void FinalizeApplication()
1447{
1448 vkDeviceWaitIdle(g_hDevice);
1449
1450 DestroySwapchain(true);
1451
1452 if(g_hDescriptorPool != VK_NULL_HANDLE)
1453 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001454 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001455 g_hDescriptorPool = VK_NULL_HANDLE;
1456 }
1457
1458 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1459 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001460 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001461 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1462 }
1463
1464 if(g_hTextureImageView != VK_NULL_HANDLE)
1465 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001466 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001467 g_hTextureImageView = VK_NULL_HANDLE;
1468 }
1469 if(g_hTextureImage != VK_NULL_HANDLE)
1470 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001471 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001472 g_hTextureImage = VK_NULL_HANDLE;
1473 }
1474
1475 if(g_hIndexBuffer != VK_NULL_HANDLE)
1476 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001477 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001478 g_hIndexBuffer = VK_NULL_HANDLE;
1479 }
1480 if(g_hVertexBuffer != VK_NULL_HANDLE)
1481 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001482 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001483 g_hVertexBuffer = VK_NULL_HANDLE;
1484 }
1485
1486 if(g_hSampler != VK_NULL_HANDLE)
1487 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001488 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001489 g_hSampler = VK_NULL_HANDLE;
1490 }
1491
Adam Sawicki51fa9662018-10-03 13:44:29 +02001492 if(g_ImmediateFence)
1493 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001494 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001495 g_ImmediateFence = VK_NULL_HANDLE;
1496 }
1497
Adam Sawickie6e498f2017-06-16 17:21:31 +02001498 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1499 {
1500 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1501 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001502 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001503 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1504 }
1505 }
1506 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1507 {
1508 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1509 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1510 }
1511 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1512 {
1513 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1514 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1515 }
1516
1517 if(g_hCommandPool != VK_NULL_HANDLE)
1518 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001519 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001520 g_hCommandPool = VK_NULL_HANDLE;
1521 }
1522
1523 if(g_hAllocator != VK_NULL_HANDLE)
1524 {
1525 vmaDestroyAllocator(g_hAllocator);
1526 g_hAllocator = nullptr;
1527 }
1528
1529 if(g_hDevice != VK_NULL_HANDLE)
1530 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001531 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001532 g_hDevice = nullptr;
1533 }
1534
1535 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1536 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001537 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001538 g_hCallback = VK_NULL_HANDLE;
1539 }
1540
1541 if(g_hSurface != VK_NULL_HANDLE)
1542 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001543 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001544 g_hSurface = VK_NULL_HANDLE;
1545 }
1546
1547 if(g_hVulkanInstance != VK_NULL_HANDLE)
1548 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001549 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001550 g_hVulkanInstance = VK_NULL_HANDLE;
1551 }
1552}
1553
1554static void PrintAllocatorStats()
1555{
1556#if VMA_STATS_STRING_ENABLED
1557 char* statsString = nullptr;
1558 vmaBuildStatsString(g_hAllocator, &statsString, true);
1559 printf("%s\n", statsString);
1560 vmaFreeStatsString(g_hAllocator, statsString);
1561#endif
1562}
1563
1564static void RecreateSwapChain()
1565{
1566 vkDeviceWaitIdle(g_hDevice);
1567 DestroySwapchain(false);
1568 CreateSwapchain();
1569}
1570
1571static void DrawFrame()
1572{
1573 // Begin main command buffer
1574 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1575 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1576 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1577
1578 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1579 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1580
1581 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1582 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1583 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1584
1585 // Acquire swapchain image
1586 uint32_t imageIndex = 0;
1587 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1588 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1589 {
1590 RecreateSwapChain();
1591 return;
1592 }
1593 else if(res < 0)
1594 {
1595 ERR_GUARD_VULKAN(res);
1596 }
1597
1598 // Record geometry pass
1599
1600 VkClearValue clearValues[2];
1601 ZeroMemory(clearValues, sizeof(clearValues));
1602 clearValues[0].color.float32[0] = 0.25f;
1603 clearValues[0].color.float32[1] = 0.25f;
1604 clearValues[0].color.float32[2] = 0.5f;
1605 clearValues[0].color.float32[3] = 1.0f;
1606 clearValues[1].depthStencil.depth = 1.0f;
1607
1608 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1609 renderPassBeginInfo.renderPass = g_hRenderPass;
1610 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1611 renderPassBeginInfo.renderArea.offset.x = 0;
1612 renderPassBeginInfo.renderArea.offset.y = 0;
1613 renderPassBeginInfo.renderArea.extent = g_Extent;
1614 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1615 renderPassBeginInfo.pClearValues = clearValues;
1616 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1617
1618 vkCmdBindPipeline(
1619 hCommandBuffer,
1620 VK_PIPELINE_BIND_POINT_GRAPHICS,
1621 g_hPipeline);
1622
Adam Sawicki82c3f332018-06-11 15:27:33 +02001623 mat4 view = mat4::LookAt(
1624 vec3(0.f, 0.f, 0.f),
1625 vec3(0.f, -2.f, 4.f),
1626 vec3(0.f, 1.f, 0.f));
1627 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001628 1.0471975511966f, // 60 degrees
1629 (float)g_Extent.width / (float)g_Extent.height,
1630 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001631 1000.f);
1632 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001633
1634 vkCmdBindDescriptorSets(
1635 hCommandBuffer,
1636 VK_PIPELINE_BIND_POINT_GRAPHICS,
1637 g_hPipelineLayout,
1638 0,
1639 1,
1640 &g_hDescriptorSet,
1641 0,
1642 nullptr);
1643
Adam Sawicki82c3f332018-06-11 15:27:33 +02001644 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1645 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001646
1647 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001648 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001649 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1650
1651 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1652 VkDeviceSize offsets[] = { 0 };
1653 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1654
1655 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1656
1657 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1658
1659 vkCmdEndRenderPass(hCommandBuffer);
1660
1661 vkEndCommandBuffer(hCommandBuffer);
1662
1663 // Submit command buffer
1664
1665 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1666 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1667 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1668 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1669 submitInfo.waitSemaphoreCount = 1;
1670 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1671 submitInfo.pWaitDstStageMask = submitWaitStages;
1672 submitInfo.commandBufferCount = 1;
1673 submitInfo.pCommandBuffers = &hCommandBuffer;
1674 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1675 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1676 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1677
1678 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1679
1680 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1681 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1682 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1683 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1684 presentInfo.swapchainCount = 1;
1685 presentInfo.pSwapchains = swapchains;
1686 presentInfo.pImageIndices = &imageIndex;
1687 presentInfo.pResults = nullptr;
1688 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1689 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1690 {
1691 RecreateSwapChain();
1692 }
1693 else
1694 ERR_GUARD_VULKAN(res);
1695}
1696
1697static void HandlePossibleSizeChange()
1698{
1699 RECT clientRect;
1700 GetClientRect(g_hWnd, &clientRect);
1701 LONG newSizeX = clientRect.right - clientRect.left;
1702 LONG newSizeY = clientRect.bottom - clientRect.top;
1703 if((newSizeX > 0) &&
1704 (newSizeY > 0) &&
1705 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1706 {
1707 g_SizeX = newSizeX;
1708 g_SizeY = newSizeY;
1709
1710 RecreateSwapChain();
1711 }
1712}
1713
1714static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1715{
1716 switch(msg)
1717 {
1718 case WM_CREATE:
1719 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1720 g_hWnd = hWnd;
1721 InitializeApplication();
1722 PrintAllocatorStats();
1723 return 0;
1724
1725 case WM_DESTROY:
1726 FinalizeApplication();
1727 PostQuitMessage(0);
1728 return 0;
1729
1730 // This prevents app from freezing when left Alt is pressed
1731 // (which normally enters modal menu loop).
1732 case WM_SYSKEYDOWN:
1733 case WM_SYSKEYUP:
1734 return 0;
1735
1736 case WM_SIZE:
1737 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1738 HandlePossibleSizeChange();
1739 return 0;
1740
1741 case WM_EXITSIZEMOVE:
1742 HandlePossibleSizeChange();
1743 return 0;
1744
1745 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001746 switch(wParam)
1747 {
1748 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001749 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001750 break;
1751 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001752 try
1753 {
1754 Test();
1755 }
1756 catch(const std::exception& ex)
1757 {
1758 printf("ERROR: %s\n", ex.what());
1759 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001760 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001761 case 'S':
1762 try
1763 {
1764 if(g_SparseBindingEnabled)
1765 {
1766 TestSparseBinding();
1767 }
1768 else
1769 {
1770 printf("Sparse binding not supported.\n");
1771 }
1772 }
1773 catch(const std::exception& ex)
1774 {
1775 printf("ERROR: %s\n", ex.what());
1776 }
1777 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001778 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001779 return 0;
1780
1781 default:
1782 break;
1783 }
1784
1785 return DefWindowProc(hWnd, msg, wParam, lParam);
1786}
1787
1788int main()
1789{
1790 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1791
1792 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1793 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1794 wndClassDesc.hbrBackground = NULL;
1795 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1796 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1797 wndClassDesc.hInstance = g_hAppInstance;
1798 wndClassDesc.lpfnWndProc = WndProc;
1799 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1800
1801 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1802 assert(hWndClass);
1803
1804 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1805 const DWORD exStyle = 0;
1806
1807 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1808 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1809
Adam Sawicki86ccd632017-07-04 14:57:53 +02001810 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001811 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1812 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1813 NULL, NULL, g_hAppInstance, NULL);
1814
1815 MSG msg;
1816 for(;;)
1817 {
1818 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1819 {
1820 if(msg.message == WM_QUIT)
1821 break;
1822 TranslateMessage(&msg);
1823 DispatchMessage(&msg);
1824 }
1825 if(g_hDevice != VK_NULL_HANDLE)
1826 DrawFrame();
1827 }
1828
1829 return 0;
1830}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001831
Adam Sawickif1a793c2018-03-13 15:42:22 +01001832#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001833
Adam Sawickif1a793c2018-03-13 15:42:22 +01001834#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001835
1836int main()
1837{
1838}
1839
Adam Sawickif1a793c2018-03-13 15:42:22 +01001840#endif // #ifdef _WIN32