blob: 0da5be2eb76ca17dbb5b6494be0e1d97af9c50a5 [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 Sawickie6e498f2017-06-16 17:21:31 +020094static VkCommandBuffer g_hTemporaryCommandBuffer;
95
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 Sawickie6e498f2017-06-16 17:21:31 +0200133static void BeginSingleTimeCommands()
134{
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
140static void EndSingleTimeCommands()
141{
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
152static void LoadShader(std::vector<char>& out, const char* fileName)
153{
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 {
1225 if((g_GraphicsQueueFamilyIndex != 0) &&
1226 ((queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0))
1227 {
1228 g_GraphicsQueueFamilyIndex = i;
1229 }
1230
1231 VkBool32 surfaceSupported = 0;
1232 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1233 if((res >= 0) && (surfaceSupported == VK_TRUE))
1234 {
1235 g_PresentQueueFamilyIndex = i;
1236 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001237
1238 if(g_SparseBindingEnabled &&
1239 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1240 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1241 {
1242 g_SparseBindingQueueFamilyIndex = i;
1243 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001244 }
1245 }
1246 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1247
Adam Sawicki51fa9662018-10-03 13:44:29 +02001248 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1249
Adam Sawickie6e498f2017-06-16 17:21:31 +02001250 // Create logical device
1251
1252 const float queuePriority = 1.f;
1253
Adam Sawicki51fa9662018-10-03 13:44:29 +02001254 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1255 uint32_t queueCount = 1;
1256 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1257 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1258 queueCreateInfo[0].queueCount = 1;
1259 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1260
1261 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1262 {
1263
1264 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1265 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1266 queueCreateInfo[queueCount].queueCount = 1;
1267 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1268 ++queueCount;
1269 }
1270
1271 if(g_SparseBindingEnabled &&
1272 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1273 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1274 {
1275
1276 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1277 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1278 queueCreateInfo[queueCount].queueCount = 1;
1279 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1280 ++queueCount;
1281 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001282
1283 VkPhysicalDeviceFeatures deviceFeatures = {};
Adam Sawicki51fa9662018-10-03 13:44:29 +02001284 //deviceFeatures.fillModeNonSolid = VK_TRUE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001285 deviceFeatures.samplerAnisotropy = VK_TRUE;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001286 deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001287
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001288 // Determine list of device extensions to enable.
Adam Sawickie6e498f2017-06-16 17:21:31 +02001289 std::vector<const char*> enabledDeviceExtensions;
1290 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001291 {
1292 uint32_t propertyCount = 0;
1293 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, nullptr) );
1294
1295 if(propertyCount)
1296 {
1297 std::vector<VkExtensionProperties> properties{propertyCount};
1298 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, properties.data()) );
1299
1300 for(uint32_t i = 0; i < propertyCount; ++i)
1301 {
1302 if(strcmp(properties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1303 {
1304 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1305 VK_KHR_get_memory_requirements2_enabled = true;
1306 }
1307 else if(strcmp(properties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1308 {
1309 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1310 VK_KHR_dedicated_allocation_enabled = true;
1311 }
1312 }
1313 }
1314 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001315
1316 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1317 deviceCreateInfo.enabledLayerCount = 0;
1318 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1319 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001320 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001321 deviceCreateInfo.queueCreateInfoCount = queueCount;
1322 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001323 deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
1324
1325 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, nullptr, &g_hDevice) );
1326
1327 // Create memory allocator
1328
1329 VmaAllocatorCreateInfo allocatorInfo = {};
1330 allocatorInfo.physicalDevice = g_hPhysicalDevice;
1331 allocatorInfo.device = g_hDevice;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001332
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001333 if(VK_KHR_dedicated_allocation_enabled)
1334 {
1335 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1336 }
Adam Sawickia68c01c2018-03-13 16:40:45 +01001337
1338 VkAllocationCallbacks cpuAllocationCallbacks = {};
1339 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1340 {
1341 cpuAllocationCallbacks.pUserData = CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA;
1342 cpuAllocationCallbacks.pfnAllocation = &CustomCpuAllocation;
1343 cpuAllocationCallbacks.pfnReallocation = &CustomCpuReallocation;
1344 cpuAllocationCallbacks.pfnFree = &CustomCpuFree;
1345 allocatorInfo.pAllocationCallbacks = &cpuAllocationCallbacks;
1346 }
1347
Adam Sawickib0c36362018-11-13 16:17:38 +01001348 // Uncomment to enable recording to CSV file.
1349 /*
1350 {
1351 VmaRecordSettings recordSettings = {};
1352 recordSettings.pFilePath = "VulkanSample.csv";
1353 allocatorInfo.pRecordSettings = &recordSettings;
1354 }
1355 */
1356
Adam Sawickie6e498f2017-06-16 17:21:31 +02001357 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1358
Adam Sawicki51fa9662018-10-03 13:44:29 +02001359 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001360
1361 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1362 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1363 assert(g_hGraphicsQueue);
1364 assert(g_hPresentQueue);
1365
Adam Sawicki51fa9662018-10-03 13:44:29 +02001366 if(g_SparseBindingEnabled)
1367 {
1368 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1369 assert(g_hSparseBindingQueue);
1370 }
1371
Adam Sawickie6e498f2017-06-16 17:21:31 +02001372 // Create command pool
1373
1374 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1375 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1376 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
1377 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, nullptr, &g_hCommandPool) );
1378
1379 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1380 commandBufferInfo.commandPool = g_hCommandPool;
1381 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1382 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1383 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1384
1385 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1386 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1387 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1388 {
1389 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_MainCommandBufferExecutedFances[i]) );
1390 }
1391
Adam Sawicki51fa9662018-10-03 13:44:29 +02001392 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_ImmediateFence) );
1393
Adam Sawickie6e498f2017-06-16 17:21:31 +02001394 commandBufferInfo.commandBufferCount = 1;
1395 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1396
1397 // Create texture sampler
1398
1399 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1400 samplerInfo.magFilter = VK_FILTER_LINEAR;
1401 samplerInfo.minFilter = VK_FILTER_LINEAR;
1402 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1403 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1404 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1405 samplerInfo.anisotropyEnable = VK_TRUE;
1406 samplerInfo.maxAnisotropy = 16;
1407 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1408 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1409 samplerInfo.compareEnable = VK_FALSE;
1410 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1411 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1412 samplerInfo.mipLodBias = 0.f;
1413 samplerInfo.minLod = 0.f;
1414 samplerInfo.maxLod = FLT_MAX;
1415 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, nullptr, &g_hSampler) );
1416
1417 CreateTexture(128, 128);
1418 CreateMesh();
1419
1420 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1421 samplerLayoutBinding.binding = 1;
1422 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1423 samplerLayoutBinding.descriptorCount = 1;
1424 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1425
1426 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1427 descriptorSetLayoutInfo.bindingCount = 1;
1428 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
1429 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, nullptr, &g_hDescriptorSetLayout) );
1430
1431 // Create descriptor pool
1432
1433 VkDescriptorPoolSize descriptorPoolSizes[2];
1434 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1435 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1436 descriptorPoolSizes[0].descriptorCount = 1;
1437 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1438 descriptorPoolSizes[1].descriptorCount = 1;
1439
1440 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1441 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1442 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1443 descriptorPoolInfo.maxSets = 1;
1444 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, nullptr, &g_hDescriptorPool) );
1445
1446 // Create descriptor set layout
1447
1448 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1449 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1450 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1451 descriptorSetInfo.descriptorSetCount = 1;
1452 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1453 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1454
1455 VkDescriptorImageInfo descriptorImageInfo = {};
1456 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1457 descriptorImageInfo.imageView = g_hTextureImageView;
1458 descriptorImageInfo.sampler = g_hSampler;
1459
1460 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1461 writeDescriptorSet.dstSet = g_hDescriptorSet;
1462 writeDescriptorSet.dstBinding = 1;
1463 writeDescriptorSet.dstArrayElement = 0;
1464 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1465 writeDescriptorSet.descriptorCount = 1;
1466 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1467
1468 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1469
1470 CreateSwapchain();
1471}
1472
1473static void FinalizeApplication()
1474{
1475 vkDeviceWaitIdle(g_hDevice);
1476
1477 DestroySwapchain(true);
1478
1479 if(g_hDescriptorPool != VK_NULL_HANDLE)
1480 {
1481 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, nullptr);
1482 g_hDescriptorPool = VK_NULL_HANDLE;
1483 }
1484
1485 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1486 {
1487 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, nullptr);
1488 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1489 }
1490
1491 if(g_hTextureImageView != VK_NULL_HANDLE)
1492 {
1493 vkDestroyImageView(g_hDevice, g_hTextureImageView, nullptr);
1494 g_hTextureImageView = VK_NULL_HANDLE;
1495 }
1496 if(g_hTextureImage != VK_NULL_HANDLE)
1497 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001498 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001499 g_hTextureImage = VK_NULL_HANDLE;
1500 }
1501
1502 if(g_hIndexBuffer != VK_NULL_HANDLE)
1503 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001504 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001505 g_hIndexBuffer = VK_NULL_HANDLE;
1506 }
1507 if(g_hVertexBuffer != VK_NULL_HANDLE)
1508 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001509 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001510 g_hVertexBuffer = VK_NULL_HANDLE;
1511 }
1512
1513 if(g_hSampler != VK_NULL_HANDLE)
1514 {
1515 vkDestroySampler(g_hDevice, g_hSampler, nullptr);
1516 g_hSampler = VK_NULL_HANDLE;
1517 }
1518
Adam Sawicki51fa9662018-10-03 13:44:29 +02001519 if(g_ImmediateFence)
1520 {
1521 vkDestroyFence(g_hDevice, g_ImmediateFence, nullptr);
1522 g_ImmediateFence = VK_NULL_HANDLE;
1523 }
1524
Adam Sawickie6e498f2017-06-16 17:21:31 +02001525 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1526 {
1527 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1528 {
1529 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], nullptr);
1530 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1531 }
1532 }
1533 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1534 {
1535 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1536 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1537 }
1538 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1539 {
1540 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1541 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1542 }
1543
1544 if(g_hCommandPool != VK_NULL_HANDLE)
1545 {
1546 vkDestroyCommandPool(g_hDevice, g_hCommandPool, nullptr);
1547 g_hCommandPool = VK_NULL_HANDLE;
1548 }
1549
1550 if(g_hAllocator != VK_NULL_HANDLE)
1551 {
1552 vmaDestroyAllocator(g_hAllocator);
1553 g_hAllocator = nullptr;
1554 }
1555
1556 if(g_hDevice != VK_NULL_HANDLE)
1557 {
1558 vkDestroyDevice(g_hDevice, nullptr);
1559 g_hDevice = nullptr;
1560 }
1561
1562 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1563 {
1564 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, nullptr);
1565 g_hCallback = VK_NULL_HANDLE;
1566 }
1567
1568 if(g_hSurface != VK_NULL_HANDLE)
1569 {
1570 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, NULL);
1571 g_hSurface = VK_NULL_HANDLE;
1572 }
1573
1574 if(g_hVulkanInstance != VK_NULL_HANDLE)
1575 {
1576 vkDestroyInstance(g_hVulkanInstance, NULL);
1577 g_hVulkanInstance = VK_NULL_HANDLE;
1578 }
1579}
1580
1581static void PrintAllocatorStats()
1582{
1583#if VMA_STATS_STRING_ENABLED
1584 char* statsString = nullptr;
1585 vmaBuildStatsString(g_hAllocator, &statsString, true);
1586 printf("%s\n", statsString);
1587 vmaFreeStatsString(g_hAllocator, statsString);
1588#endif
1589}
1590
1591static void RecreateSwapChain()
1592{
1593 vkDeviceWaitIdle(g_hDevice);
1594 DestroySwapchain(false);
1595 CreateSwapchain();
1596}
1597
1598static void DrawFrame()
1599{
1600 // Begin main command buffer
1601 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1602 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1603 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1604
1605 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1606 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1607
1608 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1609 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1610 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1611
1612 // Acquire swapchain image
1613 uint32_t imageIndex = 0;
1614 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1615 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1616 {
1617 RecreateSwapChain();
1618 return;
1619 }
1620 else if(res < 0)
1621 {
1622 ERR_GUARD_VULKAN(res);
1623 }
1624
1625 // Record geometry pass
1626
1627 VkClearValue clearValues[2];
1628 ZeroMemory(clearValues, sizeof(clearValues));
1629 clearValues[0].color.float32[0] = 0.25f;
1630 clearValues[0].color.float32[1] = 0.25f;
1631 clearValues[0].color.float32[2] = 0.5f;
1632 clearValues[0].color.float32[3] = 1.0f;
1633 clearValues[1].depthStencil.depth = 1.0f;
1634
1635 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1636 renderPassBeginInfo.renderPass = g_hRenderPass;
1637 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1638 renderPassBeginInfo.renderArea.offset.x = 0;
1639 renderPassBeginInfo.renderArea.offset.y = 0;
1640 renderPassBeginInfo.renderArea.extent = g_Extent;
1641 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1642 renderPassBeginInfo.pClearValues = clearValues;
1643 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1644
1645 vkCmdBindPipeline(
1646 hCommandBuffer,
1647 VK_PIPELINE_BIND_POINT_GRAPHICS,
1648 g_hPipeline);
1649
Adam Sawicki82c3f332018-06-11 15:27:33 +02001650 mat4 view = mat4::LookAt(
1651 vec3(0.f, 0.f, 0.f),
1652 vec3(0.f, -2.f, 4.f),
1653 vec3(0.f, 1.f, 0.f));
1654 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001655 1.0471975511966f, // 60 degrees
1656 (float)g_Extent.width / (float)g_Extent.height,
1657 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001658 1000.f);
1659 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001660
1661 vkCmdBindDescriptorSets(
1662 hCommandBuffer,
1663 VK_PIPELINE_BIND_POINT_GRAPHICS,
1664 g_hPipelineLayout,
1665 0,
1666 1,
1667 &g_hDescriptorSet,
1668 0,
1669 nullptr);
1670
Adam Sawicki82c3f332018-06-11 15:27:33 +02001671 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1672 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001673
1674 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001675 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001676 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1677
1678 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1679 VkDeviceSize offsets[] = { 0 };
1680 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1681
1682 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1683
1684 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1685
1686 vkCmdEndRenderPass(hCommandBuffer);
1687
1688 vkEndCommandBuffer(hCommandBuffer);
1689
1690 // Submit command buffer
1691
1692 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1693 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1694 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1695 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1696 submitInfo.waitSemaphoreCount = 1;
1697 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1698 submitInfo.pWaitDstStageMask = submitWaitStages;
1699 submitInfo.commandBufferCount = 1;
1700 submitInfo.pCommandBuffers = &hCommandBuffer;
1701 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1702 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1703 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1704
1705 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1706
1707 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1708 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1709 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1710 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1711 presentInfo.swapchainCount = 1;
1712 presentInfo.pSwapchains = swapchains;
1713 presentInfo.pImageIndices = &imageIndex;
1714 presentInfo.pResults = nullptr;
1715 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1716 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1717 {
1718 RecreateSwapChain();
1719 }
1720 else
1721 ERR_GUARD_VULKAN(res);
1722}
1723
1724static void HandlePossibleSizeChange()
1725{
1726 RECT clientRect;
1727 GetClientRect(g_hWnd, &clientRect);
1728 LONG newSizeX = clientRect.right - clientRect.left;
1729 LONG newSizeY = clientRect.bottom - clientRect.top;
1730 if((newSizeX > 0) &&
1731 (newSizeY > 0) &&
1732 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1733 {
1734 g_SizeX = newSizeX;
1735 g_SizeY = newSizeY;
1736
1737 RecreateSwapChain();
1738 }
1739}
1740
1741static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1742{
1743 switch(msg)
1744 {
1745 case WM_CREATE:
1746 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1747 g_hWnd = hWnd;
1748 InitializeApplication();
1749 PrintAllocatorStats();
1750 return 0;
1751
1752 case WM_DESTROY:
1753 FinalizeApplication();
1754 PostQuitMessage(0);
1755 return 0;
1756
1757 // This prevents app from freezing when left Alt is pressed
1758 // (which normally enters modal menu loop).
1759 case WM_SYSKEYDOWN:
1760 case WM_SYSKEYUP:
1761 return 0;
1762
1763 case WM_SIZE:
1764 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1765 HandlePossibleSizeChange();
1766 return 0;
1767
1768 case WM_EXITSIZEMOVE:
1769 HandlePossibleSizeChange();
1770 return 0;
1771
1772 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001773 switch(wParam)
1774 {
1775 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001776 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001777 break;
1778 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001779 try
1780 {
1781 Test();
1782 }
1783 catch(const std::exception& ex)
1784 {
1785 printf("ERROR: %s\n", ex.what());
1786 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001787 break;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001788 case 'S':
Adam Sawickia7d77692018-10-03 16:15:27 +02001789 try
1790 {
1791 TestSparseBinding();
1792 }
1793 catch(const std::exception& ex)
1794 {
1795 printf("ERROR: %s\n", ex.what());
1796 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001797 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001798 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001799 return 0;
1800
1801 default:
1802 break;
1803 }
1804
1805 return DefWindowProc(hWnd, msg, wParam, lParam);
1806}
1807
1808int main()
1809{
1810 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1811
1812 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1813 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1814 wndClassDesc.hbrBackground = NULL;
1815 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1816 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1817 wndClassDesc.hInstance = g_hAppInstance;
1818 wndClassDesc.lpfnWndProc = WndProc;
1819 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1820
1821 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1822 assert(hWndClass);
1823
1824 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1825 const DWORD exStyle = 0;
1826
1827 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1828 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1829
Adam Sawicki86ccd632017-07-04 14:57:53 +02001830 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001831 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1832 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1833 NULL, NULL, g_hAppInstance, NULL);
1834
1835 MSG msg;
1836 for(;;)
1837 {
1838 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1839 {
1840 if(msg.message == WM_QUIT)
1841 break;
1842 TranslateMessage(&msg);
1843 DispatchMessage(&msg);
1844 }
1845 if(g_hDevice != VK_NULL_HANDLE)
1846 DrawFrame();
1847 }
1848
1849 return 0;
1850}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001851
Adam Sawickif1a793c2018-03-13 15:42:22 +01001852#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001853
Adam Sawickif1a793c2018-03-13 15:42:22 +01001854#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001855
1856int main()
1857{
1858}
1859
Adam Sawickif1a793c2018-03-13 15:42:22 +01001860#endif // #ifdef _WIN32