blob: ed79925d60d78cae0fe4c0d075c644b138a65b3c [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawicki4426bfb2018-01-22 18:18:24 +01002// Copyright (c) 2017-2018 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 Sawickif1a793c2018-03-13 15:42:22 +010034static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.0";
35static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.0";
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 Sawicki978fcf52018-12-05 14:38:48 +0100133void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200134{
135 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
136 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
137 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
138}
139
Adam Sawicki978fcf52018-12-05 14:38:48 +0100140void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200141{
142 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
143
144 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
145 submitInfo.commandBufferCount = 1;
146 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
147
148 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
149 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
150}
151
Adam Sawickida6c1942018-12-05 17:34:34 +0100152void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200153{
154 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
155 if(file.is_open() == false)
156 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
157 assert(file.is_open());
158 size_t fileSize = (size_t)file.tellg();
159 if(fileSize > 0)
160 {
161 out.resize(fileSize);
162 file.seekg(0);
163 file.read(out.data(), fileSize);
164 file.close();
165 }
166 else
167 out.clear();
168}
169
170VKAPI_ATTR VkBool32 VKAPI_CALL MyDebugReportCallback(
171 VkDebugReportFlagsEXT flags,
172 VkDebugReportObjectTypeEXT objectType,
173 uint64_t object,
174 size_t location,
175 int32_t messageCode,
176 const char* pLayerPrefix,
177 const char* pMessage,
178 void* pUserData)
179{
Adam Sawickib8333fb2018-03-13 16:15:53 +0100180 // "Non-linear image 0xebc91 is aliased with linear buffer 0xeb8e4 which may indicate a bug."
181 if(!g_MemoryAliasingWarningEnabled && flags == VK_DEBUG_REPORT_WARNING_BIT_EXT &&
182 (strstr(pMessage, " is aliased with non-linear ") || strstr(pMessage, " is aliased with linear ")))
183 {
184 return VK_FALSE;
185 }
186
187 // Ignoring because when VK_KHR_dedicated_allocation extension is enabled,
188 // vkGetBufferMemoryRequirements2KHR function is used instead, while Validation
189 // Layer seems to be unaware of it.
190 if (strstr(pMessage, "but vkGetBufferMemoryRequirements() has not been called on that buffer") != nullptr)
191 {
192 return VK_FALSE;
193 }
194 if (strstr(pMessage, "but vkGetImageMemoryRequirements() has not been called on that image") != nullptr)
195 {
196 return VK_FALSE;
197 }
Adam Sawicki94e82062018-08-20 11:12:51 +0200198
199 /*
200 "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."
201 Ignoring because we map entire VkDeviceMemory blocks, where different types of
202 images and buffers may end up together, especially on GPUs with unified memory
203 like Intel.
204 */
205 if(strstr(pMessage, "Mapping an image with layout") != nullptr &&
206 strstr(pMessage, "can result in undefined behavior if this memory is used by the device") != nullptr)
207 {
208 return VK_FALSE;
209 }
Adam Sawickib8333fb2018-03-13 16:15:53 +0100210
211 switch(flags)
212 {
213 case VK_DEBUG_REPORT_WARNING_BIT_EXT:
214 SetConsoleColor(CONSOLE_COLOR::WARNING);
215 break;
216 case VK_DEBUG_REPORT_ERROR_BIT_EXT:
217 SetConsoleColor(CONSOLE_COLOR::ERROR_);
218 break;
219 default:
220 SetConsoleColor(CONSOLE_COLOR::INFO);
221 }
222
Adam Sawickie6e498f2017-06-16 17:21:31 +0200223 printf("%s \xBA %s\n", pLayerPrefix, pMessage);
224
Adam Sawickib8333fb2018-03-13 16:15:53 +0100225 SetConsoleColor(CONSOLE_COLOR::NORMAL);
226
227 if(flags == VK_DEBUG_REPORT_WARNING_BIT_EXT ||
228 flags == VK_DEBUG_REPORT_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200229 {
230 OutputDebugStringA(pMessage);
231 OutputDebugStringA("\n");
232 }
233
234 return VK_FALSE;
235}
236
237static VkSurfaceFormatKHR ChooseSurfaceFormat()
238{
239 assert(!g_SurfaceFormats.empty());
240
241 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
242 {
243 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
244 return result;
245 }
246
247 for(const auto& format : g_SurfaceFormats)
248 {
249 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
250 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
251 {
252 return format;
253 }
254 }
255
256 return g_SurfaceFormats[0];
257}
258
259VkPresentModeKHR ChooseSwapPresentMode()
260{
261 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
262
263 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
264 g_PresentModes.end())
265 {
266 return preferredMode;
267 }
268
269 return VK_PRESENT_MODE_FIFO_KHR;
270}
271
272static VkExtent2D ChooseSwapExtent()
273{
274 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
275 return g_SurfaceCapabilities.currentExtent;
276
277 VkExtent2D result = {
278 std::max(g_SurfaceCapabilities.minImageExtent.width,
279 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
280 std::max(g_SurfaceCapabilities.minImageExtent.height,
281 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
282 return result;
283}
284
285struct Vertex
286{
287 float pos[3];
288 float color[3];
289 float texCoord[2];
290};
291
292static void CreateMesh()
293{
294 assert(g_hAllocator);
295
296 static Vertex vertices[] = {
297 // -X
298 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
299 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
300 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
301 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
302 // +X
303 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
304 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
305 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
306 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
307 // -Z
308 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
309 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
310 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
311 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
312 // +Z
313 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
314 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
315 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
316 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
317 // -Y
318 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
319 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
320 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
321 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
322 // +Y
323 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
324 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
325 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
326 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
327 };
328 static uint16_t indices[] = {
329 0, 1, 2, 3, USHRT_MAX,
330 4, 5, 6, 7, USHRT_MAX,
331 8, 9, 10, 11, USHRT_MAX,
332 12, 13, 14, 15, USHRT_MAX,
333 16, 17, 18, 19, USHRT_MAX,
334 20, 21, 22, 23, USHRT_MAX,
335 };
336
337 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
338 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
339 g_IndexCount = (uint32_t)_countof(indices);
340
341 // Create vertex buffer
342
343 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
344 vbInfo.size = vertexBufferSize;
345 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
346 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200347
Adam Sawicki976f9202017-09-12 20:45:14 +0200348 VmaAllocationCreateInfo vbAllocCreateInfo = {};
349 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100350 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200351
Adam Sawicki819860e2017-07-04 14:30:38 +0200352 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
353 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
354 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200355 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200356
357 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200358
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200359 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
360
Adam Sawickie6e498f2017-06-16 17:21:31 +0200361 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200362 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
363 vbAllocCreateInfo.flags = 0;
364 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200365
366 // Create index buffer
367
368 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
369 ibInfo.size = indexBufferSize;
370 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
371 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200372
Adam Sawicki976f9202017-09-12 20:45:14 +0200373 VmaAllocationCreateInfo ibAllocCreateInfo = {};
374 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100375 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200376
Adam Sawickie6e498f2017-06-16 17:21:31 +0200377 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200378 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
379 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200380 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200381
Adam Sawicki819860e2017-07-04 14:30:38 +0200382 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200383
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200384 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
385
Adam Sawickie6e498f2017-06-16 17:21:31 +0200386 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200387 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
388 ibAllocCreateInfo.flags = 0;
389 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200390
391 // Copy buffers
392
393 BeginSingleTimeCommands();
394
395 VkBufferCopy vbCopyRegion = {};
396 vbCopyRegion.srcOffset = 0;
397 vbCopyRegion.dstOffset = 0;
398 vbCopyRegion.size = vbInfo.size;
399 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
400
401 VkBufferCopy ibCopyRegion = {};
402 ibCopyRegion.srcOffset = 0;
403 ibCopyRegion.dstOffset = 0;
404 ibCopyRegion.size = ibInfo.size;
405 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
406
407 EndSingleTimeCommands();
408
Adam Sawicki819860e2017-07-04 14:30:38 +0200409 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
410 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200411}
412
Adam Sawickie6e498f2017-06-16 17:21:31 +0200413static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
414{
415 // Create Image
416
417 const VkDeviceSize imageSize = sizeX * sizeY * 4;
418
419 VkImageCreateInfo stagingImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
420 stagingImageInfo.imageType = VK_IMAGE_TYPE_2D;
421 stagingImageInfo.extent.width = sizeX;
422 stagingImageInfo.extent.height = sizeY;
423 stagingImageInfo.extent.depth = 1;
424 stagingImageInfo.mipLevels = 1;
425 stagingImageInfo.arrayLayers = 1;
426 stagingImageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
427 stagingImageInfo.tiling = VK_IMAGE_TILING_LINEAR;
428 stagingImageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
429 stagingImageInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
430 stagingImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
431 stagingImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
432 stagingImageInfo.flags = 0;
Adam Sawicki819860e2017-07-04 14:30:38 +0200433
Adam Sawicki976f9202017-09-12 20:45:14 +0200434 VmaAllocationCreateInfo stagingImageAllocCreateInfo = {};
435 stagingImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100436 stagingImageAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200437
Adam Sawickie6e498f2017-06-16 17:21:31 +0200438 VkImage stagingImage = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200439 VmaAllocation stagingImageAlloc = VK_NULL_HANDLE;
440 VmaAllocationInfo stagingImageAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200441 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &stagingImageInfo, &stagingImageAllocCreateInfo, &stagingImage, &stagingImageAlloc, &stagingImageAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200442
443 VkImageSubresource imageSubresource = {};
444 imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
445 imageSubresource.mipLevel = 0;
446 imageSubresource.arrayLayer = 0;
447
448 VkSubresourceLayout imageLayout = {};
449 vkGetImageSubresourceLayout(g_hDevice, stagingImage, &imageSubresource, &imageLayout);
450
Adam Sawicki819860e2017-07-04 14:30:38 +0200451 char* const pMipLevelData = (char*)stagingImageAllocInfo.pMappedData + imageLayout.offset;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200452 uint8_t* pRowData = (uint8_t*)pMipLevelData;
453 for(uint32_t y = 0; y < sizeY; ++y)
454 {
455 uint32_t* pPixelData = (uint32_t*)pRowData;
456 for(uint32_t x = 0; x < sizeY; ++x)
457 {
458 *pPixelData =
459 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
460 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
461 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
462 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
463 ++pPixelData;
464 }
465 pRowData += imageLayout.rowPitch;
466 }
467
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200468 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
469
Adam Sawicki10844a82017-08-16 17:32:09 +0200470 // Create g_hTextureImage in GPU memory.
471
Adam Sawickie6e498f2017-06-16 17:21:31 +0200472 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
473 imageInfo.imageType = VK_IMAGE_TYPE_2D;
474 imageInfo.extent.width = sizeX;
475 imageInfo.extent.height = sizeY;
476 imageInfo.extent.depth = 1;
477 imageInfo.mipLevels = 1;
478 imageInfo.arrayLayers = 1;
479 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
480 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
481 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
482 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
483 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
484 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
485 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200486
Adam Sawicki976f9202017-09-12 20:45:14 +0200487 VmaAllocationCreateInfo imageAllocCreateInfo = {};
488 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200489
Adam Sawicki976f9202017-09-12 20:45:14 +0200490 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200491
Adam Sawicki10844a82017-08-16 17:32:09 +0200492 // Transition image layouts, copy image.
493
494 BeginSingleTimeCommands();
495
496 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
497 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
498 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
499 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
500 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
501 imgMemBarrier.image = stagingImage;
502 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
503 imgMemBarrier.subresourceRange.baseMipLevel = 0;
504 imgMemBarrier.subresourceRange.levelCount = 1;
505 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
506 imgMemBarrier.subresourceRange.layerCount = 1;
507 imgMemBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
508 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
509
510 vkCmdPipelineBarrier(
511 g_hTemporaryCommandBuffer,
512 VK_PIPELINE_STAGE_HOST_BIT,
513 VK_PIPELINE_STAGE_TRANSFER_BIT,
514 0,
515 0, nullptr,
516 0, nullptr,
517 1, &imgMemBarrier);
518
519 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
520 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
521 imgMemBarrier.image = g_hTextureImage;
522 imgMemBarrier.srcAccessMask = 0;
523 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
524
525 vkCmdPipelineBarrier(
526 g_hTemporaryCommandBuffer,
527 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
528 VK_PIPELINE_STAGE_TRANSFER_BIT,
529 0,
530 0, nullptr,
531 0, nullptr,
532 1, &imgMemBarrier);
533
534 VkImageCopy imageCopy = {};
535 imageCopy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
536 imageCopy.srcSubresource.baseArrayLayer = 0;
537 imageCopy.srcSubresource.mipLevel = 0;
538 imageCopy.srcSubresource.layerCount = 1;
539 imageCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
540 imageCopy.dstSubresource.baseArrayLayer = 0;
541 imageCopy.dstSubresource.mipLevel = 0;
542 imageCopy.dstSubresource.layerCount = 1;
543 imageCopy.srcOffset.x = 0;
544 imageCopy.srcOffset.y = 0;
545 imageCopy.srcOffset.z = 0;
546 imageCopy.dstOffset.x = 0;
547 imageCopy.dstOffset.y = 0;
548 imageCopy.dstOffset.z = 0;
549 imageCopy.extent.width = sizeX;
550 imageCopy.extent.height = sizeY;
551 imageCopy.extent.depth = 1;
552 vkCmdCopyImage(
553 g_hTemporaryCommandBuffer,
554 stagingImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
555 g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
556 1, &imageCopy);
557
558 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
559 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
560 imgMemBarrier.image = g_hTextureImage;
561 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
562 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
563
564 vkCmdPipelineBarrier(
565 g_hTemporaryCommandBuffer,
566 VK_PIPELINE_STAGE_TRANSFER_BIT,
567 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
568 0,
569 0, nullptr,
570 0, nullptr,
571 1, &imgMemBarrier);
572
573 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200574
Adam Sawicki819860e2017-07-04 14:30:38 +0200575 vmaDestroyImage(g_hAllocator, stagingImage, stagingImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200576
577 // Create ImageView
578
579 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
580 textureImageViewInfo.image = g_hTextureImage;
581 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
582 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
583 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
584 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
585 textureImageViewInfo.subresourceRange.levelCount = 1;
586 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
587 textureImageViewInfo.subresourceRange.layerCount = 1;
588 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, nullptr, &g_hTextureImageView) );
589}
590
591struct UniformBufferObject
592{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200593 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200594};
595
596static void RegisterDebugCallbacks()
597{
598 g_pvkCreateDebugReportCallbackEXT =
599 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
600 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
601 g_pvkDebugReportMessageEXT =
602 reinterpret_cast<PFN_vkDebugReportMessageEXT>
603 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
604 g_pvkDestroyDebugReportCallbackEXT =
605 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
606 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
607 assert(g_pvkCreateDebugReportCallbackEXT);
608 assert(g_pvkDebugReportMessageEXT);
609 assert(g_pvkDestroyDebugReportCallbackEXT);
610
611 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
612 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
613 callbackCreateInfo.pNext = nullptr;
614 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
615 VK_DEBUG_REPORT_ERROR_BIT_EXT |
616 VK_DEBUG_REPORT_WARNING_BIT_EXT |
617 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
618 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
619 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
620 callbackCreateInfo.pUserData = nullptr;
621
622 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, nullptr, &g_hCallback) );
623}
624
625static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
626{
627 const VkLayerProperties* propsEnd = pProps + propCount;
628 return std::find_if(
629 pProps,
630 propsEnd,
631 [pLayerName](const VkLayerProperties& prop) -> bool {
632 return strcmp(pLayerName, prop.layerName) == 0;
633 }) != propsEnd;
634}
635
636static VkFormat FindSupportedFormat(
637 const std::vector<VkFormat>& candidates,
638 VkImageTiling tiling,
639 VkFormatFeatureFlags features)
640{
641 for (VkFormat format : candidates)
642 {
643 VkFormatProperties props;
644 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
645
646 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
647 ((props.linearTilingFeatures & features) == features))
648 {
649 return format;
650 }
651 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
652 ((props.optimalTilingFeatures & features) == features))
653 {
654 return format;
655 }
656 }
657 return VK_FORMAT_UNDEFINED;
658}
659
660static VkFormat FindDepthFormat()
661{
662 std::vector<VkFormat> formats;
663 formats.push_back(VK_FORMAT_D32_SFLOAT);
664 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
665 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
666
667 return FindSupportedFormat(
668 formats,
669 VK_IMAGE_TILING_OPTIMAL,
670 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
671}
672
673static void CreateSwapchain()
674{
675 // Query surface formats.
676
677 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
678
679 uint32_t formatCount = 0;
680 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
681 g_SurfaceFormats.resize(formatCount);
682 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
683
684 uint32_t presentModeCount = 0;
685 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
686 g_PresentModes.resize(presentModeCount);
687 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
688
689 // Create swap chain
690
691 g_SurfaceFormat = ChooseSurfaceFormat();
692 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
693 g_Extent = ChooseSwapExtent();
694
695 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
696 if((g_SurfaceCapabilities.maxImageCount > 0) &&
697 (imageCount > g_SurfaceCapabilities.maxImageCount))
698 {
699 imageCount = g_SurfaceCapabilities.maxImageCount;
700 }
701
702 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
703 swapChainInfo.surface = g_hSurface;
704 swapChainInfo.minImageCount = imageCount;
705 swapChainInfo.imageFormat = g_SurfaceFormat.format;
706 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
707 swapChainInfo.imageExtent = g_Extent;
708 swapChainInfo.imageArrayLayers = 1;
709 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
710 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
711 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
712 swapChainInfo.presentMode = presentMode;
713 swapChainInfo.clipped = VK_TRUE;
714 swapChainInfo.oldSwapchain = g_hSwapchain;
715
716 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
717 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
718 {
719 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
720 swapChainInfo.queueFamilyIndexCount = 2;
721 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
722 }
723 else
724 {
725 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
726 }
727
728 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
729 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, nullptr, &hNewSwapchain) );
730 if(g_hSwapchain != VK_NULL_HANDLE)
731 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, nullptr);
732 g_hSwapchain = hNewSwapchain;
733
734 // Retrieve swapchain images.
735
736 uint32_t swapchainImageCount = 0;
737 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
738 g_SwapchainImages.resize(swapchainImageCount);
739 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
740
741 // Create swapchain image views.
742
743 for(size_t i = g_SwapchainImageViews.size(); i--; )
744 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], nullptr);
745 g_SwapchainImageViews.clear();
746
747 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
748 g_SwapchainImageViews.resize(swapchainImageCount);
749 for(uint32_t i = 0; i < swapchainImageCount; ++i)
750 {
751 swapchainImageViewInfo.image = g_SwapchainImages[i];
752 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
753 swapchainImageViewInfo.format = g_SurfaceFormat.format;
754 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
755 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
756 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
757 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
758 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
759 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
760 swapchainImageViewInfo.subresourceRange.levelCount = 1;
761 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
762 swapchainImageViewInfo.subresourceRange.layerCount = 1;
763 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, nullptr, &g_SwapchainImageViews[i]) );
764 }
765
766 // Create depth buffer
767
768 g_DepthFormat = FindDepthFormat();
769 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
770
771 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
772 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
773 depthImageInfo.extent.width = g_Extent.width;
774 depthImageInfo.extent.height = g_Extent.height;
775 depthImageInfo.extent.depth = 1;
776 depthImageInfo.mipLevels = 1;
777 depthImageInfo.arrayLayers = 1;
778 depthImageInfo.format = g_DepthFormat;
779 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
780 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
781 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
782 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
783 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
784 depthImageInfo.flags = 0;
785
Adam Sawicki976f9202017-09-12 20:45:14 +0200786 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
787 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200788
Adam Sawicki976f9202017-09-12 20:45:14 +0200789 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200790
791 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
792 depthImageViewInfo.image = g_hDepthImage;
793 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
794 depthImageViewInfo.format = g_DepthFormat;
795 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
796 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
797 depthImageViewInfo.subresourceRange.levelCount = 1;
798 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
799 depthImageViewInfo.subresourceRange.layerCount = 1;
800
801 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, nullptr, &g_hDepthImageView) );
802
Adam Sawickie6e498f2017-06-16 17:21:31 +0200803 // Create pipeline layout
804 {
805 if(g_hPipelineLayout != VK_NULL_HANDLE)
806 {
807 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, nullptr);
808 g_hPipelineLayout = VK_NULL_HANDLE;
809 }
810
811 VkPushConstantRange pushConstantRanges[1];
812 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
813 pushConstantRanges[0].offset = 0;
814 pushConstantRanges[0].size = sizeof(UniformBufferObject);
815 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
816
817 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
818 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
819 pipelineLayoutInfo.setLayoutCount = 1;
820 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
821 pipelineLayoutInfo.pushConstantRangeCount = 1;
822 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
823 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, nullptr, &g_hPipelineLayout) );
824 }
825
826 // Create render pass
827 {
828 if(g_hRenderPass != VK_NULL_HANDLE)
829 {
830 vkDestroyRenderPass(g_hDevice, g_hRenderPass, nullptr);
831 g_hRenderPass = VK_NULL_HANDLE;
832 }
833
834 VkAttachmentDescription attachments[2];
835 ZeroMemory(attachments, sizeof(attachments));
836
837 attachments[0].format = g_SurfaceFormat.format;
838 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
839 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
840 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
841 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
842 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100843 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200844 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
845
846 attachments[1].format = g_DepthFormat;
847 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
848 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
849 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
850 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
851 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100852 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200853 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
854
855 VkAttachmentReference colorAttachmentRef = {};
856 colorAttachmentRef.attachment = 0;
857 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
858
859 VkAttachmentReference depthStencilAttachmentRef = {};
860 depthStencilAttachmentRef.attachment = 1;
861 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
862
863 VkSubpassDescription subpassDesc = {};
864 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
865 subpassDesc.colorAttachmentCount = 1;
866 subpassDesc.pColorAttachments = &colorAttachmentRef;
867 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
868
Adam Sawickie6e498f2017-06-16 17:21:31 +0200869 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
870 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
871 renderPassInfo.pAttachments = attachments;
872 renderPassInfo.subpassCount = 1;
873 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200874 renderPassInfo.dependencyCount = 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200875 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, nullptr, &g_hRenderPass) );
876 }
877
878 // Create pipeline
879 {
880 std::vector<char> vertShaderCode;
881 LoadShader(vertShaderCode, "Shader.vert.spv");
882 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
883 shaderModuleInfo.codeSize = vertShaderCode.size();
884 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
885 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
886 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, nullptr, &hVertShaderModule) );
887
888 std::vector<char> hFragShaderCode;
889 LoadShader(hFragShaderCode, "Shader.frag.spv");
890 shaderModuleInfo.codeSize = hFragShaderCode.size();
891 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
892 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
893 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, nullptr, &fragShaderModule) );
894
895 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
896 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
897 vertPipelineShaderStageInfo.module = hVertShaderModule;
898 vertPipelineShaderStageInfo.pName = "main";
899
900 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
901 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
902 fragPipelineShaderStageInfo.module = fragShaderModule;
903 fragPipelineShaderStageInfo.pName = "main";
904
905 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
906 vertPipelineShaderStageInfo,
907 fragPipelineShaderStageInfo
908 };
909
910 VkVertexInputBindingDescription bindingDescription = {};
911 bindingDescription.binding = 0;
912 bindingDescription.stride = sizeof(Vertex);
913 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
914
915 VkVertexInputAttributeDescription attributeDescriptions[3];
916 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
917
918 attributeDescriptions[0].binding = 0;
919 attributeDescriptions[0].location = 0;
920 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
921 attributeDescriptions[0].offset = offsetof(Vertex, pos);
922
923 attributeDescriptions[1].binding = 0;
924 attributeDescriptions[1].location = 1;
925 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
926 attributeDescriptions[1].offset = offsetof(Vertex, color);
927
928 attributeDescriptions[2].binding = 0;
929 attributeDescriptions[2].location = 2;
930 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
931 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
932
933 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
934 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
935 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
936 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
937 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
938
939 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
940 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
941 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
942
943 VkViewport viewport = {};
944 viewport.x = 0.f;
945 viewport.y = 0.f;
946 viewport.width = (float)g_Extent.width;
947 viewport.height = (float)g_Extent.height;
948 viewport.minDepth = 0.f;
949 viewport.maxDepth = 1.f;
950
951 VkRect2D scissor = {};
952 scissor.offset.x = 0;
953 scissor.offset.y = 0;
954 scissor.extent = g_Extent;
955
956 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
957 pipelineViewportStateInfo.viewportCount = 1;
958 pipelineViewportStateInfo.pViewports = &viewport;
959 pipelineViewportStateInfo.scissorCount = 1;
960 pipelineViewportStateInfo.pScissors = &scissor;
961
962 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
963 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
964 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
965 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
966 pipelineRasterizationStateInfo.lineWidth = 1.f;
967 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
968 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
969 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
970 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
971 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
972 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
973
974 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
975 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
976 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
977 pipelineMultisampleStateInfo.minSampleShading = 1.f;
978 pipelineMultisampleStateInfo.pSampleMask = nullptr;
979 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
980 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
981
982 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
983 pipelineColorBlendAttachmentState.colorWriteMask =
984 VK_COLOR_COMPONENT_R_BIT |
985 VK_COLOR_COMPONENT_G_BIT |
986 VK_COLOR_COMPONENT_B_BIT |
987 VK_COLOR_COMPONENT_A_BIT;
988 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
989 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
990 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
991 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
992 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
993 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
994 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
995
996 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
997 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
998 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
999 pipelineColorBlendStateInfo.attachmentCount = 1;
1000 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
1001
1002 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
1003 depthStencilStateInfo.depthTestEnable = VK_TRUE;
1004 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
1005 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
1006 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
1007 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
1008
1009 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
1010 pipelineInfo.stageCount = 2;
1011 pipelineInfo.pStages = pipelineShaderStageInfos;
1012 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
1013 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
1014 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
1015 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
1016 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
1017 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
1018 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
1019 pipelineInfo.pDynamicState = nullptr;
1020 pipelineInfo.layout = g_hPipelineLayout;
1021 pipelineInfo.renderPass = g_hRenderPass;
1022 pipelineInfo.subpass = 0;
1023 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
1024 pipelineInfo.basePipelineIndex = -1;
1025 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
1026 g_hDevice,
1027 VK_NULL_HANDLE,
1028 1,
1029 &pipelineInfo, nullptr,
1030 &g_hPipeline) );
1031
1032 vkDestroyShaderModule(g_hDevice, fragShaderModule, nullptr);
1033 vkDestroyShaderModule(g_hDevice, hVertShaderModule, nullptr);
1034 }
1035
1036 // Create frambuffers
1037
1038 for(size_t i = g_Framebuffers.size(); i--; )
1039 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], nullptr);
1040 g_Framebuffers.clear();
1041
1042 g_Framebuffers.resize(g_SwapchainImageViews.size());
1043 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1044 {
1045 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1046
1047 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1048 framebufferInfo.renderPass = g_hRenderPass;
1049 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1050 framebufferInfo.pAttachments = attachments;
1051 framebufferInfo.width = g_Extent.width;
1052 framebufferInfo.height = g_Extent.height;
1053 framebufferInfo.layers = 1;
1054 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, nullptr, &g_Framebuffers[i]) );
1055 }
1056
1057 // Create semaphores
1058
1059 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1060 {
1061 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, nullptr);
1062 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1063 }
1064 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1065 {
1066 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, nullptr);
1067 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1068 }
1069
1070 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
1071 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, nullptr, &g_hImageAvailableSemaphore) );
1072 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, nullptr, &g_hRenderFinishedSemaphore) );
1073}
1074
1075static void DestroySwapchain(bool destroyActualSwapchain)
1076{
1077 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1078 {
1079 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, nullptr);
1080 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1081 }
1082 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1083 {
1084 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, nullptr);
1085 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1086 }
1087
1088 for(size_t i = g_Framebuffers.size(); i--; )
1089 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], nullptr);
1090 g_Framebuffers.clear();
1091
1092 if(g_hDepthImageView != VK_NULL_HANDLE)
1093 {
1094 vkDestroyImageView(g_hDevice, g_hDepthImageView, nullptr);
1095 g_hDepthImageView = VK_NULL_HANDLE;
1096 }
1097 if(g_hDepthImage != VK_NULL_HANDLE)
1098 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001099 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001100 g_hDepthImage = VK_NULL_HANDLE;
1101 }
1102
1103 if(g_hPipeline != VK_NULL_HANDLE)
1104 {
1105 vkDestroyPipeline(g_hDevice, g_hPipeline, nullptr);
1106 g_hPipeline = VK_NULL_HANDLE;
1107 }
1108
1109 if(g_hRenderPass != VK_NULL_HANDLE)
1110 {
1111 vkDestroyRenderPass(g_hDevice, g_hRenderPass, nullptr);
1112 g_hRenderPass = VK_NULL_HANDLE;
1113 }
1114
1115 if(g_hPipelineLayout != VK_NULL_HANDLE)
1116 {
1117 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, nullptr);
1118 g_hPipelineLayout = VK_NULL_HANDLE;
1119 }
1120
1121 for(size_t i = g_SwapchainImageViews.size(); i--; )
1122 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], nullptr);
1123 g_SwapchainImageViews.clear();
1124
1125 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1126 {
1127 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, nullptr);
1128 g_hSwapchain = VK_NULL_HANDLE;
1129 }
1130}
1131
1132static void InitializeApplication()
1133{
1134 uint32_t instanceLayerPropCount = 0;
1135 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1136 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1137 if(instanceLayerPropCount > 0)
1138 {
1139 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1140 }
1141
1142 if(g_EnableValidationLayer == true)
1143 {
1144 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1145 {
1146 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1147 g_EnableValidationLayer = false;
1148 }
1149 }
1150
1151 std::vector<const char*> instanceExtensions;
1152 instanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1153 instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
1154
1155 std::vector<const char*> instanceLayers;
1156 if(g_EnableValidationLayer == true)
1157 {
1158 instanceLayers.push_back(VALIDATION_LAYER_NAME);
1159 instanceExtensions.push_back("VK_EXT_debug_report");
1160 }
1161
1162 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1163 appInfo.pApplicationName = APP_TITLE_A;
1164 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1165 appInfo.pEngineName = "Adam Sawicki Engine";
1166 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
1167 appInfo.apiVersion = VK_API_VERSION_1_0;
1168
1169 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1170 instInfo.pApplicationInfo = &appInfo;
1171 instInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
1172 instInfo.ppEnabledExtensionNames = instanceExtensions.data();
1173 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1174 instInfo.ppEnabledLayerNames = instanceLayers.data();
1175
1176 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, NULL, &g_hVulkanInstance) );
1177
1178 // Create VkSurfaceKHR.
1179 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1180 surfaceInfo.hinstance = g_hAppInstance;
1181 surfaceInfo.hwnd = g_hWnd;
1182 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, NULL, &g_hSurface);
1183 assert(result == VK_SUCCESS);
1184
1185 if(g_EnableValidationLayer == true)
1186 RegisterDebugCallbacks();
1187
1188 // Find physical device
1189
1190 uint32_t deviceCount = 0;
1191 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1192 assert(deviceCount > 0);
1193
1194 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1195 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1196
1197 g_hPhysicalDevice = physicalDevices[0];
1198
1199 // Query for features
1200
1201 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1202 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1203
Adam Sawicki51fa9662018-10-03 13:44:29 +02001204 VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
1205 vkGetPhysicalDeviceFeatures(g_hPhysicalDevice, &physicalDeviceFeatures);
1206
1207 g_SparseBindingEnabled = physicalDeviceFeatures.sparseBinding != 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001208
1209 // Find queue family index
1210
1211 uint32_t queueFamilyCount = 0;
1212 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1213 assert(queueFamilyCount > 0);
1214 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1215 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1216 for(uint32_t i = 0;
1217 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001218 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1219 g_PresentQueueFamilyIndex == UINT_MAX ||
1220 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001221 ++i)
1222 {
1223 if(queueFamilies[i].queueCount > 0)
1224 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001225 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001226 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001227 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001228 {
1229 g_GraphicsQueueFamilyIndex = i;
1230 }
1231
1232 VkBool32 surfaceSupported = 0;
1233 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1234 if((res >= 0) && (surfaceSupported == VK_TRUE))
1235 {
1236 g_PresentQueueFamilyIndex = i;
1237 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001238
1239 if(g_SparseBindingEnabled &&
1240 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1241 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1242 {
1243 g_SparseBindingQueueFamilyIndex = i;
1244 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001245 }
1246 }
1247 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1248
Adam Sawicki51fa9662018-10-03 13:44:29 +02001249 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1250
Adam Sawickie6e498f2017-06-16 17:21:31 +02001251 // Create logical device
1252
1253 const float queuePriority = 1.f;
1254
Adam Sawicki51fa9662018-10-03 13:44:29 +02001255 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1256 uint32_t queueCount = 1;
1257 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1258 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1259 queueCreateInfo[0].queueCount = 1;
1260 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1261
1262 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1263 {
1264
1265 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1266 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1267 queueCreateInfo[queueCount].queueCount = 1;
1268 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1269 ++queueCount;
1270 }
1271
1272 if(g_SparseBindingEnabled &&
1273 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1274 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1275 {
1276
1277 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1278 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1279 queueCreateInfo[queueCount].queueCount = 1;
1280 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1281 ++queueCount;
1282 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001283
1284 VkPhysicalDeviceFeatures deviceFeatures = {};
Adam Sawicki51fa9662018-10-03 13:44:29 +02001285 //deviceFeatures.fillModeNonSolid = VK_TRUE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001286 deviceFeatures.samplerAnisotropy = VK_TRUE;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001287 deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001288
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001289 // Determine list of device extensions to enable.
Adam Sawickie6e498f2017-06-16 17:21:31 +02001290 std::vector<const char*> enabledDeviceExtensions;
1291 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001292 {
1293 uint32_t propertyCount = 0;
1294 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, nullptr) );
1295
1296 if(propertyCount)
1297 {
1298 std::vector<VkExtensionProperties> properties{propertyCount};
1299 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, properties.data()) );
1300
1301 for(uint32_t i = 0; i < propertyCount; ++i)
1302 {
1303 if(strcmp(properties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1304 {
1305 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1306 VK_KHR_get_memory_requirements2_enabled = true;
1307 }
1308 else if(strcmp(properties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1309 {
1310 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1311 VK_KHR_dedicated_allocation_enabled = true;
1312 }
1313 }
1314 }
1315 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001316
1317 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1318 deviceCreateInfo.enabledLayerCount = 0;
1319 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1320 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001321 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001322 deviceCreateInfo.queueCreateInfoCount = queueCount;
1323 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001324 deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
1325
1326 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, nullptr, &g_hDevice) );
1327
1328 // Create memory allocator
1329
1330 VmaAllocatorCreateInfo allocatorInfo = {};
1331 allocatorInfo.physicalDevice = g_hPhysicalDevice;
1332 allocatorInfo.device = g_hDevice;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001333
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001334 if(VK_KHR_dedicated_allocation_enabled)
1335 {
1336 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1337 }
Adam Sawickia68c01c2018-03-13 16:40:45 +01001338
1339 VkAllocationCallbacks cpuAllocationCallbacks = {};
1340 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1341 {
1342 cpuAllocationCallbacks.pUserData = CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA;
1343 cpuAllocationCallbacks.pfnAllocation = &CustomCpuAllocation;
1344 cpuAllocationCallbacks.pfnReallocation = &CustomCpuReallocation;
1345 cpuAllocationCallbacks.pfnFree = &CustomCpuFree;
1346 allocatorInfo.pAllocationCallbacks = &cpuAllocationCallbacks;
1347 }
1348
Adam Sawickib0c36362018-11-13 16:17:38 +01001349 // Uncomment to enable recording to CSV file.
1350 /*
1351 {
1352 VmaRecordSettings recordSettings = {};
1353 recordSettings.pFilePath = "VulkanSample.csv";
1354 allocatorInfo.pRecordSettings = &recordSettings;
1355 }
1356 */
1357
Adam Sawickie6e498f2017-06-16 17:21:31 +02001358 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1359
Adam Sawicki51fa9662018-10-03 13:44:29 +02001360 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001361
1362 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1363 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1364 assert(g_hGraphicsQueue);
1365 assert(g_hPresentQueue);
1366
Adam Sawicki51fa9662018-10-03 13:44:29 +02001367 if(g_SparseBindingEnabled)
1368 {
1369 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1370 assert(g_hSparseBindingQueue);
1371 }
1372
Adam Sawickie6e498f2017-06-16 17:21:31 +02001373 // Create command pool
1374
1375 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1376 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1377 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
1378 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, nullptr, &g_hCommandPool) );
1379
1380 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1381 commandBufferInfo.commandPool = g_hCommandPool;
1382 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1383 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1384 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1385
1386 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1387 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1388 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1389 {
1390 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_MainCommandBufferExecutedFances[i]) );
1391 }
1392
Adam Sawicki51fa9662018-10-03 13:44:29 +02001393 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_ImmediateFence) );
1394
Adam Sawickie6e498f2017-06-16 17:21:31 +02001395 commandBufferInfo.commandBufferCount = 1;
1396 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1397
1398 // Create texture sampler
1399
1400 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1401 samplerInfo.magFilter = VK_FILTER_LINEAR;
1402 samplerInfo.minFilter = VK_FILTER_LINEAR;
1403 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1404 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1405 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1406 samplerInfo.anisotropyEnable = VK_TRUE;
1407 samplerInfo.maxAnisotropy = 16;
1408 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1409 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1410 samplerInfo.compareEnable = VK_FALSE;
1411 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1412 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1413 samplerInfo.mipLodBias = 0.f;
1414 samplerInfo.minLod = 0.f;
1415 samplerInfo.maxLod = FLT_MAX;
1416 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, nullptr, &g_hSampler) );
1417
1418 CreateTexture(128, 128);
1419 CreateMesh();
1420
1421 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1422 samplerLayoutBinding.binding = 1;
1423 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1424 samplerLayoutBinding.descriptorCount = 1;
1425 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1426
1427 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1428 descriptorSetLayoutInfo.bindingCount = 1;
1429 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
1430 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, nullptr, &g_hDescriptorSetLayout) );
1431
1432 // Create descriptor pool
1433
1434 VkDescriptorPoolSize descriptorPoolSizes[2];
1435 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1436 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1437 descriptorPoolSizes[0].descriptorCount = 1;
1438 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1439 descriptorPoolSizes[1].descriptorCount = 1;
1440
1441 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1442 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1443 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1444 descriptorPoolInfo.maxSets = 1;
1445 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, nullptr, &g_hDescriptorPool) );
1446
1447 // Create descriptor set layout
1448
1449 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1450 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1451 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1452 descriptorSetInfo.descriptorSetCount = 1;
1453 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1454 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1455
1456 VkDescriptorImageInfo descriptorImageInfo = {};
1457 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1458 descriptorImageInfo.imageView = g_hTextureImageView;
1459 descriptorImageInfo.sampler = g_hSampler;
1460
1461 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1462 writeDescriptorSet.dstSet = g_hDescriptorSet;
1463 writeDescriptorSet.dstBinding = 1;
1464 writeDescriptorSet.dstArrayElement = 0;
1465 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1466 writeDescriptorSet.descriptorCount = 1;
1467 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1468
1469 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1470
1471 CreateSwapchain();
1472}
1473
1474static void FinalizeApplication()
1475{
1476 vkDeviceWaitIdle(g_hDevice);
1477
1478 DestroySwapchain(true);
1479
1480 if(g_hDescriptorPool != VK_NULL_HANDLE)
1481 {
1482 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, nullptr);
1483 g_hDescriptorPool = VK_NULL_HANDLE;
1484 }
1485
1486 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1487 {
1488 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, nullptr);
1489 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1490 }
1491
1492 if(g_hTextureImageView != VK_NULL_HANDLE)
1493 {
1494 vkDestroyImageView(g_hDevice, g_hTextureImageView, nullptr);
1495 g_hTextureImageView = VK_NULL_HANDLE;
1496 }
1497 if(g_hTextureImage != VK_NULL_HANDLE)
1498 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001499 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001500 g_hTextureImage = VK_NULL_HANDLE;
1501 }
1502
1503 if(g_hIndexBuffer != VK_NULL_HANDLE)
1504 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001505 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001506 g_hIndexBuffer = VK_NULL_HANDLE;
1507 }
1508 if(g_hVertexBuffer != VK_NULL_HANDLE)
1509 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001510 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001511 g_hVertexBuffer = VK_NULL_HANDLE;
1512 }
1513
1514 if(g_hSampler != VK_NULL_HANDLE)
1515 {
1516 vkDestroySampler(g_hDevice, g_hSampler, nullptr);
1517 g_hSampler = VK_NULL_HANDLE;
1518 }
1519
Adam Sawicki51fa9662018-10-03 13:44:29 +02001520 if(g_ImmediateFence)
1521 {
1522 vkDestroyFence(g_hDevice, g_ImmediateFence, nullptr);
1523 g_ImmediateFence = VK_NULL_HANDLE;
1524 }
1525
Adam Sawickie6e498f2017-06-16 17:21:31 +02001526 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1527 {
1528 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1529 {
1530 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], nullptr);
1531 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1532 }
1533 }
1534 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1535 {
1536 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1537 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1538 }
1539 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1540 {
1541 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1542 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1543 }
1544
1545 if(g_hCommandPool != VK_NULL_HANDLE)
1546 {
1547 vkDestroyCommandPool(g_hDevice, g_hCommandPool, nullptr);
1548 g_hCommandPool = VK_NULL_HANDLE;
1549 }
1550
1551 if(g_hAllocator != VK_NULL_HANDLE)
1552 {
1553 vmaDestroyAllocator(g_hAllocator);
1554 g_hAllocator = nullptr;
1555 }
1556
1557 if(g_hDevice != VK_NULL_HANDLE)
1558 {
1559 vkDestroyDevice(g_hDevice, nullptr);
1560 g_hDevice = nullptr;
1561 }
1562
1563 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1564 {
1565 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, nullptr);
1566 g_hCallback = VK_NULL_HANDLE;
1567 }
1568
1569 if(g_hSurface != VK_NULL_HANDLE)
1570 {
1571 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, NULL);
1572 g_hSurface = VK_NULL_HANDLE;
1573 }
1574
1575 if(g_hVulkanInstance != VK_NULL_HANDLE)
1576 {
1577 vkDestroyInstance(g_hVulkanInstance, NULL);
1578 g_hVulkanInstance = VK_NULL_HANDLE;
1579 }
1580}
1581
1582static void PrintAllocatorStats()
1583{
1584#if VMA_STATS_STRING_ENABLED
1585 char* statsString = nullptr;
1586 vmaBuildStatsString(g_hAllocator, &statsString, true);
1587 printf("%s\n", statsString);
1588 vmaFreeStatsString(g_hAllocator, statsString);
1589#endif
1590}
1591
1592static void RecreateSwapChain()
1593{
1594 vkDeviceWaitIdle(g_hDevice);
1595 DestroySwapchain(false);
1596 CreateSwapchain();
1597}
1598
1599static void DrawFrame()
1600{
1601 // Begin main command buffer
1602 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1603 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1604 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1605
1606 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1607 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1608
1609 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1610 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1611 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1612
1613 // Acquire swapchain image
1614 uint32_t imageIndex = 0;
1615 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1616 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1617 {
1618 RecreateSwapChain();
1619 return;
1620 }
1621 else if(res < 0)
1622 {
1623 ERR_GUARD_VULKAN(res);
1624 }
1625
1626 // Record geometry pass
1627
1628 VkClearValue clearValues[2];
1629 ZeroMemory(clearValues, sizeof(clearValues));
1630 clearValues[0].color.float32[0] = 0.25f;
1631 clearValues[0].color.float32[1] = 0.25f;
1632 clearValues[0].color.float32[2] = 0.5f;
1633 clearValues[0].color.float32[3] = 1.0f;
1634 clearValues[1].depthStencil.depth = 1.0f;
1635
1636 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1637 renderPassBeginInfo.renderPass = g_hRenderPass;
1638 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1639 renderPassBeginInfo.renderArea.offset.x = 0;
1640 renderPassBeginInfo.renderArea.offset.y = 0;
1641 renderPassBeginInfo.renderArea.extent = g_Extent;
1642 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1643 renderPassBeginInfo.pClearValues = clearValues;
1644 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1645
1646 vkCmdBindPipeline(
1647 hCommandBuffer,
1648 VK_PIPELINE_BIND_POINT_GRAPHICS,
1649 g_hPipeline);
1650
Adam Sawicki82c3f332018-06-11 15:27:33 +02001651 mat4 view = mat4::LookAt(
1652 vec3(0.f, 0.f, 0.f),
1653 vec3(0.f, -2.f, 4.f),
1654 vec3(0.f, 1.f, 0.f));
1655 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001656 1.0471975511966f, // 60 degrees
1657 (float)g_Extent.width / (float)g_Extent.height,
1658 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001659 1000.f);
1660 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001661
1662 vkCmdBindDescriptorSets(
1663 hCommandBuffer,
1664 VK_PIPELINE_BIND_POINT_GRAPHICS,
1665 g_hPipelineLayout,
1666 0,
1667 1,
1668 &g_hDescriptorSet,
1669 0,
1670 nullptr);
1671
Adam Sawicki82c3f332018-06-11 15:27:33 +02001672 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1673 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001674
1675 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001676 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001677 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1678
1679 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1680 VkDeviceSize offsets[] = { 0 };
1681 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1682
1683 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1684
1685 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1686
1687 vkCmdEndRenderPass(hCommandBuffer);
1688
1689 vkEndCommandBuffer(hCommandBuffer);
1690
1691 // Submit command buffer
1692
1693 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1694 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1695 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1696 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1697 submitInfo.waitSemaphoreCount = 1;
1698 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1699 submitInfo.pWaitDstStageMask = submitWaitStages;
1700 submitInfo.commandBufferCount = 1;
1701 submitInfo.pCommandBuffers = &hCommandBuffer;
1702 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1703 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1704 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1705
1706 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1707
1708 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1709 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1710 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1711 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1712 presentInfo.swapchainCount = 1;
1713 presentInfo.pSwapchains = swapchains;
1714 presentInfo.pImageIndices = &imageIndex;
1715 presentInfo.pResults = nullptr;
1716 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1717 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1718 {
1719 RecreateSwapChain();
1720 }
1721 else
1722 ERR_GUARD_VULKAN(res);
1723}
1724
1725static void HandlePossibleSizeChange()
1726{
1727 RECT clientRect;
1728 GetClientRect(g_hWnd, &clientRect);
1729 LONG newSizeX = clientRect.right - clientRect.left;
1730 LONG newSizeY = clientRect.bottom - clientRect.top;
1731 if((newSizeX > 0) &&
1732 (newSizeY > 0) &&
1733 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1734 {
1735 g_SizeX = newSizeX;
1736 g_SizeY = newSizeY;
1737
1738 RecreateSwapChain();
1739 }
1740}
1741
1742static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1743{
1744 switch(msg)
1745 {
1746 case WM_CREATE:
1747 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1748 g_hWnd = hWnd;
1749 InitializeApplication();
1750 PrintAllocatorStats();
1751 return 0;
1752
1753 case WM_DESTROY:
1754 FinalizeApplication();
1755 PostQuitMessage(0);
1756 return 0;
1757
1758 // This prevents app from freezing when left Alt is pressed
1759 // (which normally enters modal menu loop).
1760 case WM_SYSKEYDOWN:
1761 case WM_SYSKEYUP:
1762 return 0;
1763
1764 case WM_SIZE:
1765 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1766 HandlePossibleSizeChange();
1767 return 0;
1768
1769 case WM_EXITSIZEMOVE:
1770 HandlePossibleSizeChange();
1771 return 0;
1772
1773 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001774 switch(wParam)
1775 {
1776 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001777 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001778 break;
1779 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001780 try
1781 {
1782 Test();
1783 }
1784 catch(const std::exception& ex)
1785 {
1786 printf("ERROR: %s\n", ex.what());
1787 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001788 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001789 case 'S':
1790 try
1791 {
1792 if(g_SparseBindingEnabled)
1793 {
1794 TestSparseBinding();
1795 }
1796 else
1797 {
1798 printf("Sparse binding not supported.\n");
1799 }
1800 }
1801 catch(const std::exception& ex)
1802 {
1803 printf("ERROR: %s\n", ex.what());
1804 }
1805 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001806 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001807 return 0;
1808
1809 default:
1810 break;
1811 }
1812
1813 return DefWindowProc(hWnd, msg, wParam, lParam);
1814}
1815
1816int main()
1817{
1818 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1819
1820 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1821 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1822 wndClassDesc.hbrBackground = NULL;
1823 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1824 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1825 wndClassDesc.hInstance = g_hAppInstance;
1826 wndClassDesc.lpfnWndProc = WndProc;
1827 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1828
1829 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1830 assert(hWndClass);
1831
1832 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1833 const DWORD exStyle = 0;
1834
1835 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1836 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1837
Adam Sawicki86ccd632017-07-04 14:57:53 +02001838 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001839 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1840 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1841 NULL, NULL, g_hAppInstance, NULL);
1842
1843 MSG msg;
1844 for(;;)
1845 {
1846 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1847 {
1848 if(msg.message == WM_QUIT)
1849 break;
1850 TranslateMessage(&msg);
1851 DispatchMessage(&msg);
1852 }
1853 if(g_hDevice != VK_NULL_HANDLE)
1854 DrawFrame();
1855 }
1856
1857 return 0;
1858}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001859
Adam Sawickif1a793c2018-03-13 15:42:22 +01001860#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001861
Adam Sawickif1a793c2018-03-13 15:42:22 +01001862#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001863
1864int main()
1865{
1866}
1867
Adam Sawickif1a793c2018-03-13 15:42:22 +01001868#endif // #ifdef _WIN32