blob: 2f4a339e35e268807660a092f236581aa7f7d575 [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawickiae5c4662019-01-02 10:23:35 +01002// Copyright (c) 2017-2019 Advanced Micro Devices, Inc. All rights reserved.
Adam Sawickie6e498f2017-06-16 17:21:31 +02003//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21//
22
Adam Sawickif1a793c2018-03-13 15:42:22 +010023#ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +020024
Adam Sawicki51fa9662018-10-03 13:44:29 +020025#include "SparseBindingTest.h"
Adam Sawickif1a793c2018-03-13 15:42:22 +010026#include "Tests.h"
27#include "VmaUsage.h"
28#include "Common.h"
Adam Sawickie6e498f2017-06-16 17:21:31 +020029
30static const char* const SHADER_PATH1 = "./";
31static const char* const SHADER_PATH2 = "../bin/";
32static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
33static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_LUNARG_standard_validation";
Adam Sawicki6c8b7a22019-03-05 13:40:29 +010034static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.3.0-development";
35static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.3.0-development";
Adam Sawickie6e498f2017-06-16 17:21:31 +020036
37static const bool VSYNC = true;
38static const uint32_t COMMAND_BUFFER_COUNT = 2;
Adam Sawickia68c01c2018-03-13 16:40:45 +010039static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
40static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +020041
Adam Sawickib8333fb2018-03-13 16:15:53 +010042VkPhysicalDevice g_hPhysicalDevice;
43VkDevice g_hDevice;
44VmaAllocator g_hAllocator;
45bool g_MemoryAliasingWarningEnabled = true;
46
Adam Sawickia68c01c2018-03-13 16:40:45 +010047static bool g_EnableValidationLayer = true;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010048static bool VK_KHR_get_memory_requirements2_enabled = false;
49static bool VK_KHR_dedicated_allocation_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020050bool g_SparseBindingEnabled = false;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010051
Adam Sawickie6e498f2017-06-16 17:21:31 +020052static HINSTANCE g_hAppInstance;
53static HWND g_hWnd;
54static LONG g_SizeX = 1280, g_SizeY = 720;
55static VkInstance g_hVulkanInstance;
56static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020057static VkQueue g_hPresentQueue;
58static VkSurfaceFormatKHR g_SurfaceFormat;
59static VkExtent2D g_Extent;
60static VkSwapchainKHR g_hSwapchain;
61static std::vector<VkImage> g_SwapchainImages;
62static std::vector<VkImageView> g_SwapchainImageViews;
63static std::vector<VkFramebuffer> g_Framebuffers;
64static VkCommandPool g_hCommandPool;
65static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
66static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020067VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020068static uint32_t g_NextCommandBufferIndex;
69static VkSemaphore g_hImageAvailableSemaphore;
70static VkSemaphore g_hRenderFinishedSemaphore;
71static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
72static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020073static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020074static VkDescriptorSetLayout g_hDescriptorSetLayout;
75static VkDescriptorPool g_hDescriptorPool;
76static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
77static VkSampler g_hSampler;
78static VkFormat g_DepthFormat;
79static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +020080static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +020081static VkImageView g_hDepthImageView;
82
83static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
84static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
85static std::vector<VkPresentModeKHR> g_PresentModes;
86
87static PFN_vkCreateDebugReportCallbackEXT g_pvkCreateDebugReportCallbackEXT;
88static PFN_vkDebugReportMessageEXT g_pvkDebugReportMessageEXT;
89static PFN_vkDestroyDebugReportCallbackEXT g_pvkDestroyDebugReportCallbackEXT;
90static VkDebugReportCallbackEXT g_hCallback;
91
Adam Sawickie6e498f2017-06-16 17:21:31 +020092static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +020093VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +010094VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +020095
96static VkPipelineLayout g_hPipelineLayout;
97static VkRenderPass g_hRenderPass;
98static VkPipeline g_hPipeline;
99
100static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200101static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200102static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200103static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200104static uint32_t g_VertexCount;
105static uint32_t g_IndexCount;
106
107static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200108static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200109static VkImageView g_hTextureImageView;
110
Adam Sawickia68c01c2018-03-13 16:40:45 +0100111static void* CustomCpuAllocation(
112 void* pUserData, size_t size, size_t alignment,
113 VkSystemAllocationScope allocationScope)
114{
115 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
116 return _aligned_malloc(size, alignment);
117}
118
119static void* CustomCpuReallocation(
120 void* pUserData, void* pOriginal, size_t size, size_t alignment,
121 VkSystemAllocationScope allocationScope)
122{
123 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
124 return _aligned_realloc(pOriginal, size, alignment);
125}
126
127static void CustomCpuFree(void* pUserData, void* pMemory)
128{
129 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
130 _aligned_free(pMemory);
131}
132
Adam 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{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100415 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200416
417 const VkDeviceSize imageSize = sizeX * sizeY * 4;
418
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100419 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
420 stagingBufInfo.size = imageSize;
421 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
422
423 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
424 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
425 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200426
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100427 VkBuffer stagingBuf = VK_NULL_HANDLE;
428 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
429 VmaAllocationInfo stagingBufAllocInfo = {};
430 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200431
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100432 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
433 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200434 for(uint32_t y = 0; y < sizeY; ++y)
435 {
436 uint32_t* pPixelData = (uint32_t*)pRowData;
437 for(uint32_t x = 0; x < sizeY; ++x)
438 {
439 *pPixelData =
440 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
441 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
442 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
443 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
444 ++pPixelData;
445 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100446 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200447 }
448
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200449 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
450
Adam Sawicki10844a82017-08-16 17:32:09 +0200451 // Create g_hTextureImage in GPU memory.
452
Adam Sawickie6e498f2017-06-16 17:21:31 +0200453 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
454 imageInfo.imageType = VK_IMAGE_TYPE_2D;
455 imageInfo.extent.width = sizeX;
456 imageInfo.extent.height = sizeY;
457 imageInfo.extent.depth = 1;
458 imageInfo.mipLevels = 1;
459 imageInfo.arrayLayers = 1;
460 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
461 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
462 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
463 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
464 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
465 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
466 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200467
Adam Sawicki976f9202017-09-12 20:45:14 +0200468 VmaAllocationCreateInfo imageAllocCreateInfo = {};
469 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200470
Adam Sawicki976f9202017-09-12 20:45:14 +0200471 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200472
Adam Sawicki10844a82017-08-16 17:32:09 +0200473 // Transition image layouts, copy image.
474
475 BeginSingleTimeCommands();
476
477 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200478 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
479 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200480 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
481 imgMemBarrier.subresourceRange.baseMipLevel = 0;
482 imgMemBarrier.subresourceRange.levelCount = 1;
483 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
484 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200485 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
486 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
487 imgMemBarrier.image = g_hTextureImage;
488 imgMemBarrier.srcAccessMask = 0;
489 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
490
491 vkCmdPipelineBarrier(
492 g_hTemporaryCommandBuffer,
493 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
494 VK_PIPELINE_STAGE_TRANSFER_BIT,
495 0,
496 0, nullptr,
497 0, nullptr,
498 1, &imgMemBarrier);
499
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100500 VkBufferImageCopy region = {};
501 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
502 region.imageSubresource.layerCount = 1;
503 region.imageExtent.width = sizeX;
504 region.imageExtent.height = sizeY;
505 region.imageExtent.depth = 1;
506
507 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200508
509 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
510 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
511 imgMemBarrier.image = g_hTextureImage;
512 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
513 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
514
515 vkCmdPipelineBarrier(
516 g_hTemporaryCommandBuffer,
517 VK_PIPELINE_STAGE_TRANSFER_BIT,
518 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
519 0,
520 0, nullptr,
521 0, nullptr,
522 1, &imgMemBarrier);
523
524 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200525
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100526 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200527
528 // Create ImageView
529
530 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
531 textureImageViewInfo.image = g_hTextureImage;
532 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
533 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
534 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
535 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
536 textureImageViewInfo.subresourceRange.levelCount = 1;
537 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
538 textureImageViewInfo.subresourceRange.layerCount = 1;
539 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, nullptr, &g_hTextureImageView) );
540}
541
542struct UniformBufferObject
543{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200544 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200545};
546
547static void RegisterDebugCallbacks()
548{
549 g_pvkCreateDebugReportCallbackEXT =
550 reinterpret_cast<PFN_vkCreateDebugReportCallbackEXT>
551 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkCreateDebugReportCallbackEXT"));
552 g_pvkDebugReportMessageEXT =
553 reinterpret_cast<PFN_vkDebugReportMessageEXT>
554 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDebugReportMessageEXT"));
555 g_pvkDestroyDebugReportCallbackEXT =
556 reinterpret_cast<PFN_vkDestroyDebugReportCallbackEXT>
557 (vkGetInstanceProcAddr(g_hVulkanInstance, "vkDestroyDebugReportCallbackEXT"));
558 assert(g_pvkCreateDebugReportCallbackEXT);
559 assert(g_pvkDebugReportMessageEXT);
560 assert(g_pvkDestroyDebugReportCallbackEXT);
561
562 VkDebugReportCallbackCreateInfoEXT callbackCreateInfo;
563 callbackCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
564 callbackCreateInfo.pNext = nullptr;
565 callbackCreateInfo.flags = //VK_DEBUG_REPORT_INFORMATION_BIT_EXT |
566 VK_DEBUG_REPORT_ERROR_BIT_EXT |
567 VK_DEBUG_REPORT_WARNING_BIT_EXT |
568 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT /*|
569 VK_DEBUG_REPORT_DEBUG_BIT_EXT*/;
570 callbackCreateInfo.pfnCallback = &MyDebugReportCallback;
571 callbackCreateInfo.pUserData = nullptr;
572
573 ERR_GUARD_VULKAN( g_pvkCreateDebugReportCallbackEXT(g_hVulkanInstance, &callbackCreateInfo, nullptr, &g_hCallback) );
574}
575
576static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
577{
578 const VkLayerProperties* propsEnd = pProps + propCount;
579 return std::find_if(
580 pProps,
581 propsEnd,
582 [pLayerName](const VkLayerProperties& prop) -> bool {
583 return strcmp(pLayerName, prop.layerName) == 0;
584 }) != propsEnd;
585}
586
587static VkFormat FindSupportedFormat(
588 const std::vector<VkFormat>& candidates,
589 VkImageTiling tiling,
590 VkFormatFeatureFlags features)
591{
592 for (VkFormat format : candidates)
593 {
594 VkFormatProperties props;
595 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
596
597 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
598 ((props.linearTilingFeatures & features) == features))
599 {
600 return format;
601 }
602 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
603 ((props.optimalTilingFeatures & features) == features))
604 {
605 return format;
606 }
607 }
608 return VK_FORMAT_UNDEFINED;
609}
610
611static VkFormat FindDepthFormat()
612{
613 std::vector<VkFormat> formats;
614 formats.push_back(VK_FORMAT_D32_SFLOAT);
615 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
616 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
617
618 return FindSupportedFormat(
619 formats,
620 VK_IMAGE_TILING_OPTIMAL,
621 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
622}
623
624static void CreateSwapchain()
625{
626 // Query surface formats.
627
628 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
629
630 uint32_t formatCount = 0;
631 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
632 g_SurfaceFormats.resize(formatCount);
633 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
634
635 uint32_t presentModeCount = 0;
636 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
637 g_PresentModes.resize(presentModeCount);
638 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
639
640 // Create swap chain
641
642 g_SurfaceFormat = ChooseSurfaceFormat();
643 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
644 g_Extent = ChooseSwapExtent();
645
646 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
647 if((g_SurfaceCapabilities.maxImageCount > 0) &&
648 (imageCount > g_SurfaceCapabilities.maxImageCount))
649 {
650 imageCount = g_SurfaceCapabilities.maxImageCount;
651 }
652
653 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
654 swapChainInfo.surface = g_hSurface;
655 swapChainInfo.minImageCount = imageCount;
656 swapChainInfo.imageFormat = g_SurfaceFormat.format;
657 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
658 swapChainInfo.imageExtent = g_Extent;
659 swapChainInfo.imageArrayLayers = 1;
660 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
661 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
662 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
663 swapChainInfo.presentMode = presentMode;
664 swapChainInfo.clipped = VK_TRUE;
665 swapChainInfo.oldSwapchain = g_hSwapchain;
666
667 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
668 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
669 {
670 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
671 swapChainInfo.queueFamilyIndexCount = 2;
672 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
673 }
674 else
675 {
676 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
677 }
678
679 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
680 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, nullptr, &hNewSwapchain) );
681 if(g_hSwapchain != VK_NULL_HANDLE)
682 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, nullptr);
683 g_hSwapchain = hNewSwapchain;
684
685 // Retrieve swapchain images.
686
687 uint32_t swapchainImageCount = 0;
688 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
689 g_SwapchainImages.resize(swapchainImageCount);
690 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
691
692 // Create swapchain image views.
693
694 for(size_t i = g_SwapchainImageViews.size(); i--; )
695 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], nullptr);
696 g_SwapchainImageViews.clear();
697
698 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
699 g_SwapchainImageViews.resize(swapchainImageCount);
700 for(uint32_t i = 0; i < swapchainImageCount; ++i)
701 {
702 swapchainImageViewInfo.image = g_SwapchainImages[i];
703 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
704 swapchainImageViewInfo.format = g_SurfaceFormat.format;
705 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
706 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
707 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
708 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
709 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
710 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
711 swapchainImageViewInfo.subresourceRange.levelCount = 1;
712 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
713 swapchainImageViewInfo.subresourceRange.layerCount = 1;
714 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, nullptr, &g_SwapchainImageViews[i]) );
715 }
716
717 // Create depth buffer
718
719 g_DepthFormat = FindDepthFormat();
720 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
721
722 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
723 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
724 depthImageInfo.extent.width = g_Extent.width;
725 depthImageInfo.extent.height = g_Extent.height;
726 depthImageInfo.extent.depth = 1;
727 depthImageInfo.mipLevels = 1;
728 depthImageInfo.arrayLayers = 1;
729 depthImageInfo.format = g_DepthFormat;
730 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
731 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
732 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
733 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
734 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
735 depthImageInfo.flags = 0;
736
Adam Sawicki976f9202017-09-12 20:45:14 +0200737 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
738 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200739
Adam Sawicki976f9202017-09-12 20:45:14 +0200740 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200741
742 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
743 depthImageViewInfo.image = g_hDepthImage;
744 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
745 depthImageViewInfo.format = g_DepthFormat;
746 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
747 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
748 depthImageViewInfo.subresourceRange.levelCount = 1;
749 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
750 depthImageViewInfo.subresourceRange.layerCount = 1;
751
752 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, nullptr, &g_hDepthImageView) );
753
Adam Sawickie6e498f2017-06-16 17:21:31 +0200754 // Create pipeline layout
755 {
756 if(g_hPipelineLayout != VK_NULL_HANDLE)
757 {
758 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, nullptr);
759 g_hPipelineLayout = VK_NULL_HANDLE;
760 }
761
762 VkPushConstantRange pushConstantRanges[1];
763 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
764 pushConstantRanges[0].offset = 0;
765 pushConstantRanges[0].size = sizeof(UniformBufferObject);
766 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
767
768 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
769 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
770 pipelineLayoutInfo.setLayoutCount = 1;
771 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
772 pipelineLayoutInfo.pushConstantRangeCount = 1;
773 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
774 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, nullptr, &g_hPipelineLayout) );
775 }
776
777 // Create render pass
778 {
779 if(g_hRenderPass != VK_NULL_HANDLE)
780 {
781 vkDestroyRenderPass(g_hDevice, g_hRenderPass, nullptr);
782 g_hRenderPass = VK_NULL_HANDLE;
783 }
784
785 VkAttachmentDescription attachments[2];
786 ZeroMemory(attachments, sizeof(attachments));
787
788 attachments[0].format = g_SurfaceFormat.format;
789 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
790 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
791 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
792 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
793 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100794 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200795 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
796
797 attachments[1].format = g_DepthFormat;
798 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
799 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
800 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
801 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
802 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +0100803 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200804 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
805
806 VkAttachmentReference colorAttachmentRef = {};
807 colorAttachmentRef.attachment = 0;
808 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
809
810 VkAttachmentReference depthStencilAttachmentRef = {};
811 depthStencilAttachmentRef.attachment = 1;
812 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
813
814 VkSubpassDescription subpassDesc = {};
815 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
816 subpassDesc.colorAttachmentCount = 1;
817 subpassDesc.pColorAttachments = &colorAttachmentRef;
818 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
819
Adam Sawickie6e498f2017-06-16 17:21:31 +0200820 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
821 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
822 renderPassInfo.pAttachments = attachments;
823 renderPassInfo.subpassCount = 1;
824 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +0200825 renderPassInfo.dependencyCount = 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200826 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, nullptr, &g_hRenderPass) );
827 }
828
829 // Create pipeline
830 {
831 std::vector<char> vertShaderCode;
832 LoadShader(vertShaderCode, "Shader.vert.spv");
833 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
834 shaderModuleInfo.codeSize = vertShaderCode.size();
835 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
836 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
837 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, nullptr, &hVertShaderModule) );
838
839 std::vector<char> hFragShaderCode;
840 LoadShader(hFragShaderCode, "Shader.frag.spv");
841 shaderModuleInfo.codeSize = hFragShaderCode.size();
842 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
843 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
844 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, nullptr, &fragShaderModule) );
845
846 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
847 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
848 vertPipelineShaderStageInfo.module = hVertShaderModule;
849 vertPipelineShaderStageInfo.pName = "main";
850
851 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
852 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
853 fragPipelineShaderStageInfo.module = fragShaderModule;
854 fragPipelineShaderStageInfo.pName = "main";
855
856 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
857 vertPipelineShaderStageInfo,
858 fragPipelineShaderStageInfo
859 };
860
861 VkVertexInputBindingDescription bindingDescription = {};
862 bindingDescription.binding = 0;
863 bindingDescription.stride = sizeof(Vertex);
864 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
865
866 VkVertexInputAttributeDescription attributeDescriptions[3];
867 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
868
869 attributeDescriptions[0].binding = 0;
870 attributeDescriptions[0].location = 0;
871 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
872 attributeDescriptions[0].offset = offsetof(Vertex, pos);
873
874 attributeDescriptions[1].binding = 0;
875 attributeDescriptions[1].location = 1;
876 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
877 attributeDescriptions[1].offset = offsetof(Vertex, color);
878
879 attributeDescriptions[2].binding = 0;
880 attributeDescriptions[2].location = 2;
881 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
882 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
883
884 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
885 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
886 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
887 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
888 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
889
890 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
891 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
892 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
893
894 VkViewport viewport = {};
895 viewport.x = 0.f;
896 viewport.y = 0.f;
897 viewport.width = (float)g_Extent.width;
898 viewport.height = (float)g_Extent.height;
899 viewport.minDepth = 0.f;
900 viewport.maxDepth = 1.f;
901
902 VkRect2D scissor = {};
903 scissor.offset.x = 0;
904 scissor.offset.y = 0;
905 scissor.extent = g_Extent;
906
907 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
908 pipelineViewportStateInfo.viewportCount = 1;
909 pipelineViewportStateInfo.pViewports = &viewport;
910 pipelineViewportStateInfo.scissorCount = 1;
911 pipelineViewportStateInfo.pScissors = &scissor;
912
913 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
914 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
915 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
916 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
917 pipelineRasterizationStateInfo.lineWidth = 1.f;
918 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
919 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
920 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
921 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
922 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
923 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
924
925 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
926 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
927 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
928 pipelineMultisampleStateInfo.minSampleShading = 1.f;
929 pipelineMultisampleStateInfo.pSampleMask = nullptr;
930 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
931 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
932
933 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
934 pipelineColorBlendAttachmentState.colorWriteMask =
935 VK_COLOR_COMPONENT_R_BIT |
936 VK_COLOR_COMPONENT_G_BIT |
937 VK_COLOR_COMPONENT_B_BIT |
938 VK_COLOR_COMPONENT_A_BIT;
939 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
940 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
941 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
942 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
943 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
944 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
945 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
946
947 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
948 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
949 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
950 pipelineColorBlendStateInfo.attachmentCount = 1;
951 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
952
953 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
954 depthStencilStateInfo.depthTestEnable = VK_TRUE;
955 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
956 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
957 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
958 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
959
960 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
961 pipelineInfo.stageCount = 2;
962 pipelineInfo.pStages = pipelineShaderStageInfos;
963 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
964 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
965 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
966 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
967 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
968 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
969 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
970 pipelineInfo.pDynamicState = nullptr;
971 pipelineInfo.layout = g_hPipelineLayout;
972 pipelineInfo.renderPass = g_hRenderPass;
973 pipelineInfo.subpass = 0;
974 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
975 pipelineInfo.basePipelineIndex = -1;
976 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
977 g_hDevice,
978 VK_NULL_HANDLE,
979 1,
980 &pipelineInfo, nullptr,
981 &g_hPipeline) );
982
983 vkDestroyShaderModule(g_hDevice, fragShaderModule, nullptr);
984 vkDestroyShaderModule(g_hDevice, hVertShaderModule, nullptr);
985 }
986
987 // Create frambuffers
988
989 for(size_t i = g_Framebuffers.size(); i--; )
990 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], nullptr);
991 g_Framebuffers.clear();
992
993 g_Framebuffers.resize(g_SwapchainImageViews.size());
994 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
995 {
996 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
997
998 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
999 framebufferInfo.renderPass = g_hRenderPass;
1000 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1001 framebufferInfo.pAttachments = attachments;
1002 framebufferInfo.width = g_Extent.width;
1003 framebufferInfo.height = g_Extent.height;
1004 framebufferInfo.layers = 1;
1005 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, nullptr, &g_Framebuffers[i]) );
1006 }
1007
1008 // Create semaphores
1009
1010 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1011 {
1012 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, nullptr);
1013 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1014 }
1015 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1016 {
1017 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, nullptr);
1018 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1019 }
1020
1021 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
1022 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, nullptr, &g_hImageAvailableSemaphore) );
1023 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, nullptr, &g_hRenderFinishedSemaphore) );
1024}
1025
1026static void DestroySwapchain(bool destroyActualSwapchain)
1027{
1028 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1029 {
1030 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, nullptr);
1031 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1032 }
1033 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1034 {
1035 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, nullptr);
1036 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1037 }
1038
1039 for(size_t i = g_Framebuffers.size(); i--; )
1040 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], nullptr);
1041 g_Framebuffers.clear();
1042
1043 if(g_hDepthImageView != VK_NULL_HANDLE)
1044 {
1045 vkDestroyImageView(g_hDevice, g_hDepthImageView, nullptr);
1046 g_hDepthImageView = VK_NULL_HANDLE;
1047 }
1048 if(g_hDepthImage != VK_NULL_HANDLE)
1049 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001050 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001051 g_hDepthImage = VK_NULL_HANDLE;
1052 }
1053
1054 if(g_hPipeline != VK_NULL_HANDLE)
1055 {
1056 vkDestroyPipeline(g_hDevice, g_hPipeline, nullptr);
1057 g_hPipeline = VK_NULL_HANDLE;
1058 }
1059
1060 if(g_hRenderPass != VK_NULL_HANDLE)
1061 {
1062 vkDestroyRenderPass(g_hDevice, g_hRenderPass, nullptr);
1063 g_hRenderPass = VK_NULL_HANDLE;
1064 }
1065
1066 if(g_hPipelineLayout != VK_NULL_HANDLE)
1067 {
1068 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, nullptr);
1069 g_hPipelineLayout = VK_NULL_HANDLE;
1070 }
1071
1072 for(size_t i = g_SwapchainImageViews.size(); i--; )
1073 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], nullptr);
1074 g_SwapchainImageViews.clear();
1075
1076 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1077 {
1078 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, nullptr);
1079 g_hSwapchain = VK_NULL_HANDLE;
1080 }
1081}
1082
1083static void InitializeApplication()
1084{
1085 uint32_t instanceLayerPropCount = 0;
1086 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
1087 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
1088 if(instanceLayerPropCount > 0)
1089 {
1090 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
1091 }
1092
1093 if(g_EnableValidationLayer == true)
1094 {
1095 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
1096 {
1097 printf("Layer \"%s\" not supported.", VALIDATION_LAYER_NAME);
1098 g_EnableValidationLayer = false;
1099 }
1100 }
1101
1102 std::vector<const char*> instanceExtensions;
1103 instanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
1104 instanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
1105
1106 std::vector<const char*> instanceLayers;
1107 if(g_EnableValidationLayer == true)
1108 {
1109 instanceLayers.push_back(VALIDATION_LAYER_NAME);
1110 instanceExtensions.push_back("VK_EXT_debug_report");
1111 }
1112
1113 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
1114 appInfo.pApplicationName = APP_TITLE_A;
1115 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
1116 appInfo.pEngineName = "Adam Sawicki Engine";
1117 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
1118 appInfo.apiVersion = VK_API_VERSION_1_0;
1119
1120 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
1121 instInfo.pApplicationInfo = &appInfo;
1122 instInfo.enabledExtensionCount = static_cast<uint32_t>(instanceExtensions.size());
1123 instInfo.ppEnabledExtensionNames = instanceExtensions.data();
1124 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
1125 instInfo.ppEnabledLayerNames = instanceLayers.data();
1126
1127 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, NULL, &g_hVulkanInstance) );
1128
1129 // Create VkSurfaceKHR.
1130 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1131 surfaceInfo.hinstance = g_hAppInstance;
1132 surfaceInfo.hwnd = g_hWnd;
1133 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, NULL, &g_hSurface);
1134 assert(result == VK_SUCCESS);
1135
1136 if(g_EnableValidationLayer == true)
1137 RegisterDebugCallbacks();
1138
1139 // Find physical device
1140
1141 uint32_t deviceCount = 0;
1142 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr) );
1143 assert(deviceCount > 0);
1144
1145 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
1146 ERR_GUARD_VULKAN( vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()) );
1147
1148 g_hPhysicalDevice = physicalDevices[0];
1149
1150 // Query for features
1151
1152 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1153 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
1154
Adam Sawicki51fa9662018-10-03 13:44:29 +02001155 VkPhysicalDeviceFeatures physicalDeviceFeatures = {};
1156 vkGetPhysicalDeviceFeatures(g_hPhysicalDevice, &physicalDeviceFeatures);
1157
1158 g_SparseBindingEnabled = physicalDeviceFeatures.sparseBinding != 0;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001159
1160 // Find queue family index
1161
1162 uint32_t queueFamilyCount = 0;
1163 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1164 assert(queueFamilyCount > 0);
1165 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1166 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1167 for(uint32_t i = 0;
1168 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001169 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1170 g_PresentQueueFamilyIndex == UINT_MAX ||
1171 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001172 ++i)
1173 {
1174 if(queueFamilies[i].queueCount > 0)
1175 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001176 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001177 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001178 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001179 {
1180 g_GraphicsQueueFamilyIndex = i;
1181 }
1182
1183 VkBool32 surfaceSupported = 0;
1184 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1185 if((res >= 0) && (surfaceSupported == VK_TRUE))
1186 {
1187 g_PresentQueueFamilyIndex = i;
1188 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001189
1190 if(g_SparseBindingEnabled &&
1191 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1192 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1193 {
1194 g_SparseBindingQueueFamilyIndex = i;
1195 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001196 }
1197 }
1198 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1199
Adam Sawicki51fa9662018-10-03 13:44:29 +02001200 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1201
Adam Sawickie6e498f2017-06-16 17:21:31 +02001202 // Create logical device
1203
1204 const float queuePriority = 1.f;
1205
Adam Sawicki51fa9662018-10-03 13:44:29 +02001206 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1207 uint32_t queueCount = 1;
1208 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1209 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1210 queueCreateInfo[0].queueCount = 1;
1211 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1212
1213 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1214 {
1215
1216 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1217 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1218 queueCreateInfo[queueCount].queueCount = 1;
1219 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1220 ++queueCount;
1221 }
1222
1223 if(g_SparseBindingEnabled &&
1224 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1225 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1226 {
1227
1228 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1229 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1230 queueCreateInfo[queueCount].queueCount = 1;
1231 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1232 ++queueCount;
1233 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001234
1235 VkPhysicalDeviceFeatures deviceFeatures = {};
Adam Sawicki51fa9662018-10-03 13:44:29 +02001236 //deviceFeatures.fillModeNonSolid = VK_TRUE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001237 deviceFeatures.samplerAnisotropy = VK_TRUE;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001238 deviceFeatures.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001239
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001240 // Determine list of device extensions to enable.
Adam Sawickie6e498f2017-06-16 17:21:31 +02001241 std::vector<const char*> enabledDeviceExtensions;
1242 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001243 {
1244 uint32_t propertyCount = 0;
1245 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, nullptr) );
1246
1247 if(propertyCount)
1248 {
1249 std::vector<VkExtensionProperties> properties{propertyCount};
1250 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &propertyCount, properties.data()) );
1251
1252 for(uint32_t i = 0; i < propertyCount; ++i)
1253 {
1254 if(strcmp(properties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
1255 {
1256 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1257 VK_KHR_get_memory_requirements2_enabled = true;
1258 }
1259 else if(strcmp(properties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
1260 {
1261 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1262 VK_KHR_dedicated_allocation_enabled = true;
1263 }
1264 }
1265 }
1266 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001267
1268 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
1269 deviceCreateInfo.enabledLayerCount = 0;
1270 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1271 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001272 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02001273 deviceCreateInfo.queueCreateInfoCount = queueCount;
1274 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001275 deviceCreateInfo.pEnabledFeatures = &deviceFeatures;
1276
1277 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, nullptr, &g_hDevice) );
1278
1279 // Create memory allocator
1280
1281 VmaAllocatorCreateInfo allocatorInfo = {};
1282 allocatorInfo.physicalDevice = g_hPhysicalDevice;
1283 allocatorInfo.device = g_hDevice;
Adam Sawickia68c01c2018-03-13 16:40:45 +01001284
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001285 if(VK_KHR_dedicated_allocation_enabled)
1286 {
1287 allocatorInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1288 }
Adam Sawickia68c01c2018-03-13 16:40:45 +01001289
1290 VkAllocationCallbacks cpuAllocationCallbacks = {};
1291 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1292 {
1293 cpuAllocationCallbacks.pUserData = CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA;
1294 cpuAllocationCallbacks.pfnAllocation = &CustomCpuAllocation;
1295 cpuAllocationCallbacks.pfnReallocation = &CustomCpuReallocation;
1296 cpuAllocationCallbacks.pfnFree = &CustomCpuFree;
1297 allocatorInfo.pAllocationCallbacks = &cpuAllocationCallbacks;
1298 }
1299
Adam Sawickib0c36362018-11-13 16:17:38 +01001300 // Uncomment to enable recording to CSV file.
1301 /*
1302 {
1303 VmaRecordSettings recordSettings = {};
1304 recordSettings.pFilePath = "VulkanSample.csv";
1305 allocatorInfo.pRecordSettings = &recordSettings;
1306 }
1307 */
1308
Adam Sawickie6e498f2017-06-16 17:21:31 +02001309 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
1310
Adam Sawicki51fa9662018-10-03 13:44:29 +02001311 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02001312
1313 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
1314 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
1315 assert(g_hGraphicsQueue);
1316 assert(g_hPresentQueue);
1317
Adam Sawicki51fa9662018-10-03 13:44:29 +02001318 if(g_SparseBindingEnabled)
1319 {
1320 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
1321 assert(g_hSparseBindingQueue);
1322 }
1323
Adam Sawickie6e498f2017-06-16 17:21:31 +02001324 // Create command pool
1325
1326 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
1327 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1328 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
1329 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, nullptr, &g_hCommandPool) );
1330
1331 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
1332 commandBufferInfo.commandPool = g_hCommandPool;
1333 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1334 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
1335 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
1336
1337 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
1338 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1339 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
1340 {
1341 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_MainCommandBufferExecutedFances[i]) );
1342 }
1343
Adam Sawicki51fa9662018-10-03 13:44:29 +02001344 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, nullptr, &g_ImmediateFence) );
1345
Adam Sawickie6e498f2017-06-16 17:21:31 +02001346 commandBufferInfo.commandBufferCount = 1;
1347 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
1348
1349 // Create texture sampler
1350
1351 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
1352 samplerInfo.magFilter = VK_FILTER_LINEAR;
1353 samplerInfo.minFilter = VK_FILTER_LINEAR;
1354 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1355 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1356 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
1357 samplerInfo.anisotropyEnable = VK_TRUE;
1358 samplerInfo.maxAnisotropy = 16;
1359 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
1360 samplerInfo.unnormalizedCoordinates = VK_FALSE;
1361 samplerInfo.compareEnable = VK_FALSE;
1362 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
1363 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
1364 samplerInfo.mipLodBias = 0.f;
1365 samplerInfo.minLod = 0.f;
1366 samplerInfo.maxLod = FLT_MAX;
1367 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, nullptr, &g_hSampler) );
1368
1369 CreateTexture(128, 128);
1370 CreateMesh();
1371
1372 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
1373 samplerLayoutBinding.binding = 1;
1374 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1375 samplerLayoutBinding.descriptorCount = 1;
1376 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1377
1378 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
1379 descriptorSetLayoutInfo.bindingCount = 1;
1380 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
1381 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, nullptr, &g_hDescriptorSetLayout) );
1382
1383 // Create descriptor pool
1384
1385 VkDescriptorPoolSize descriptorPoolSizes[2];
1386 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
1387 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1388 descriptorPoolSizes[0].descriptorCount = 1;
1389 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1390 descriptorPoolSizes[1].descriptorCount = 1;
1391
1392 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
1393 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
1394 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
1395 descriptorPoolInfo.maxSets = 1;
1396 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, nullptr, &g_hDescriptorPool) );
1397
1398 // Create descriptor set layout
1399
1400 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1401 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
1402 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
1403 descriptorSetInfo.descriptorSetCount = 1;
1404 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
1405 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
1406
1407 VkDescriptorImageInfo descriptorImageInfo = {};
1408 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
1409 descriptorImageInfo.imageView = g_hTextureImageView;
1410 descriptorImageInfo.sampler = g_hSampler;
1411
1412 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
1413 writeDescriptorSet.dstSet = g_hDescriptorSet;
1414 writeDescriptorSet.dstBinding = 1;
1415 writeDescriptorSet.dstArrayElement = 0;
1416 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1417 writeDescriptorSet.descriptorCount = 1;
1418 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
1419
1420 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
1421
1422 CreateSwapchain();
1423}
1424
1425static void FinalizeApplication()
1426{
1427 vkDeviceWaitIdle(g_hDevice);
1428
1429 DestroySwapchain(true);
1430
1431 if(g_hDescriptorPool != VK_NULL_HANDLE)
1432 {
1433 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, nullptr);
1434 g_hDescriptorPool = VK_NULL_HANDLE;
1435 }
1436
1437 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
1438 {
1439 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, nullptr);
1440 g_hDescriptorSetLayout = VK_NULL_HANDLE;
1441 }
1442
1443 if(g_hTextureImageView != VK_NULL_HANDLE)
1444 {
1445 vkDestroyImageView(g_hDevice, g_hTextureImageView, nullptr);
1446 g_hTextureImageView = VK_NULL_HANDLE;
1447 }
1448 if(g_hTextureImage != VK_NULL_HANDLE)
1449 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001450 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001451 g_hTextureImage = VK_NULL_HANDLE;
1452 }
1453
1454 if(g_hIndexBuffer != VK_NULL_HANDLE)
1455 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001456 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001457 g_hIndexBuffer = VK_NULL_HANDLE;
1458 }
1459 if(g_hVertexBuffer != VK_NULL_HANDLE)
1460 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001461 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001462 g_hVertexBuffer = VK_NULL_HANDLE;
1463 }
1464
1465 if(g_hSampler != VK_NULL_HANDLE)
1466 {
1467 vkDestroySampler(g_hDevice, g_hSampler, nullptr);
1468 g_hSampler = VK_NULL_HANDLE;
1469 }
1470
Adam Sawicki51fa9662018-10-03 13:44:29 +02001471 if(g_ImmediateFence)
1472 {
1473 vkDestroyFence(g_hDevice, g_ImmediateFence, nullptr);
1474 g_ImmediateFence = VK_NULL_HANDLE;
1475 }
1476
Adam Sawickie6e498f2017-06-16 17:21:31 +02001477 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
1478 {
1479 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
1480 {
1481 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], nullptr);
1482 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
1483 }
1484 }
1485 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
1486 {
1487 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
1488 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
1489 }
1490 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
1491 {
1492 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
1493 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
1494 }
1495
1496 if(g_hCommandPool != VK_NULL_HANDLE)
1497 {
1498 vkDestroyCommandPool(g_hDevice, g_hCommandPool, nullptr);
1499 g_hCommandPool = VK_NULL_HANDLE;
1500 }
1501
1502 if(g_hAllocator != VK_NULL_HANDLE)
1503 {
1504 vmaDestroyAllocator(g_hAllocator);
1505 g_hAllocator = nullptr;
1506 }
1507
1508 if(g_hDevice != VK_NULL_HANDLE)
1509 {
1510 vkDestroyDevice(g_hDevice, nullptr);
1511 g_hDevice = nullptr;
1512 }
1513
1514 if(g_pvkDestroyDebugReportCallbackEXT && g_hCallback != VK_NULL_HANDLE)
1515 {
1516 g_pvkDestroyDebugReportCallbackEXT(g_hVulkanInstance, g_hCallback, nullptr);
1517 g_hCallback = VK_NULL_HANDLE;
1518 }
1519
1520 if(g_hSurface != VK_NULL_HANDLE)
1521 {
1522 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, NULL);
1523 g_hSurface = VK_NULL_HANDLE;
1524 }
1525
1526 if(g_hVulkanInstance != VK_NULL_HANDLE)
1527 {
1528 vkDestroyInstance(g_hVulkanInstance, NULL);
1529 g_hVulkanInstance = VK_NULL_HANDLE;
1530 }
1531}
1532
1533static void PrintAllocatorStats()
1534{
1535#if VMA_STATS_STRING_ENABLED
1536 char* statsString = nullptr;
1537 vmaBuildStatsString(g_hAllocator, &statsString, true);
1538 printf("%s\n", statsString);
1539 vmaFreeStatsString(g_hAllocator, statsString);
1540#endif
1541}
1542
1543static void RecreateSwapChain()
1544{
1545 vkDeviceWaitIdle(g_hDevice);
1546 DestroySwapchain(false);
1547 CreateSwapchain();
1548}
1549
1550static void DrawFrame()
1551{
1552 // Begin main command buffer
1553 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
1554 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
1555 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
1556
1557 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
1558 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
1559
1560 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
1561 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1562 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
1563
1564 // Acquire swapchain image
1565 uint32_t imageIndex = 0;
1566 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
1567 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1568 {
1569 RecreateSwapChain();
1570 return;
1571 }
1572 else if(res < 0)
1573 {
1574 ERR_GUARD_VULKAN(res);
1575 }
1576
1577 // Record geometry pass
1578
1579 VkClearValue clearValues[2];
1580 ZeroMemory(clearValues, sizeof(clearValues));
1581 clearValues[0].color.float32[0] = 0.25f;
1582 clearValues[0].color.float32[1] = 0.25f;
1583 clearValues[0].color.float32[2] = 0.5f;
1584 clearValues[0].color.float32[3] = 1.0f;
1585 clearValues[1].depthStencil.depth = 1.0f;
1586
1587 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
1588 renderPassBeginInfo.renderPass = g_hRenderPass;
1589 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
1590 renderPassBeginInfo.renderArea.offset.x = 0;
1591 renderPassBeginInfo.renderArea.offset.y = 0;
1592 renderPassBeginInfo.renderArea.extent = g_Extent;
1593 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
1594 renderPassBeginInfo.pClearValues = clearValues;
1595 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
1596
1597 vkCmdBindPipeline(
1598 hCommandBuffer,
1599 VK_PIPELINE_BIND_POINT_GRAPHICS,
1600 g_hPipeline);
1601
Adam Sawicki82c3f332018-06-11 15:27:33 +02001602 mat4 view = mat4::LookAt(
1603 vec3(0.f, 0.f, 0.f),
1604 vec3(0.f, -2.f, 4.f),
1605 vec3(0.f, 1.f, 0.f));
1606 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001607 1.0471975511966f, // 60 degrees
1608 (float)g_Extent.width / (float)g_Extent.height,
1609 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02001610 1000.f);
1611 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001612
1613 vkCmdBindDescriptorSets(
1614 hCommandBuffer,
1615 VK_PIPELINE_BIND_POINT_GRAPHICS,
1616 g_hPipelineLayout,
1617 0,
1618 1,
1619 &g_hDescriptorSet,
1620 0,
1621 nullptr);
1622
Adam Sawicki82c3f332018-06-11 15:27:33 +02001623 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
1624 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001625
1626 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02001627 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001628 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
1629
1630 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
1631 VkDeviceSize offsets[] = { 0 };
1632 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
1633
1634 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
1635
1636 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
1637
1638 vkCmdEndRenderPass(hCommandBuffer);
1639
1640 vkEndCommandBuffer(hCommandBuffer);
1641
1642 // Submit command buffer
1643
1644 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
1645 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
1646 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
1647 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
1648 submitInfo.waitSemaphoreCount = 1;
1649 submitInfo.pWaitSemaphores = submitWaitSemaphores;
1650 submitInfo.pWaitDstStageMask = submitWaitStages;
1651 submitInfo.commandBufferCount = 1;
1652 submitInfo.pCommandBuffers = &hCommandBuffer;
1653 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
1654 submitInfo.pSignalSemaphores = submitSignalSemaphores;
1655 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
1656
1657 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
1658
1659 VkSwapchainKHR swapchains[] = { g_hSwapchain };
1660 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
1661 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
1662 presentInfo.pWaitSemaphores = presentWaitSemaphores;
1663 presentInfo.swapchainCount = 1;
1664 presentInfo.pSwapchains = swapchains;
1665 presentInfo.pImageIndices = &imageIndex;
1666 presentInfo.pResults = nullptr;
1667 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
1668 if(res == VK_ERROR_OUT_OF_DATE_KHR)
1669 {
1670 RecreateSwapChain();
1671 }
1672 else
1673 ERR_GUARD_VULKAN(res);
1674}
1675
1676static void HandlePossibleSizeChange()
1677{
1678 RECT clientRect;
1679 GetClientRect(g_hWnd, &clientRect);
1680 LONG newSizeX = clientRect.right - clientRect.left;
1681 LONG newSizeY = clientRect.bottom - clientRect.top;
1682 if((newSizeX > 0) &&
1683 (newSizeY > 0) &&
1684 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
1685 {
1686 g_SizeX = newSizeX;
1687 g_SizeY = newSizeY;
1688
1689 RecreateSwapChain();
1690 }
1691}
1692
1693static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
1694{
1695 switch(msg)
1696 {
1697 case WM_CREATE:
1698 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
1699 g_hWnd = hWnd;
1700 InitializeApplication();
1701 PrintAllocatorStats();
1702 return 0;
1703
1704 case WM_DESTROY:
1705 FinalizeApplication();
1706 PostQuitMessage(0);
1707 return 0;
1708
1709 // This prevents app from freezing when left Alt is pressed
1710 // (which normally enters modal menu loop).
1711 case WM_SYSKEYDOWN:
1712 case WM_SYSKEYUP:
1713 return 0;
1714
1715 case WM_SIZE:
1716 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
1717 HandlePossibleSizeChange();
1718 return 0;
1719
1720 case WM_EXITSIZEMOVE:
1721 HandlePossibleSizeChange();
1722 return 0;
1723
1724 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01001725 switch(wParam)
1726 {
1727 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02001728 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01001729 break;
1730 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02001731 try
1732 {
1733 Test();
1734 }
1735 catch(const std::exception& ex)
1736 {
1737 printf("ERROR: %s\n", ex.what());
1738 }
Adam Sawickib8333fb2018-03-13 16:15:53 +01001739 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01001740 case 'S':
1741 try
1742 {
1743 if(g_SparseBindingEnabled)
1744 {
1745 TestSparseBinding();
1746 }
1747 else
1748 {
1749 printf("Sparse binding not supported.\n");
1750 }
1751 }
1752 catch(const std::exception& ex)
1753 {
1754 printf("ERROR: %s\n", ex.what());
1755 }
1756 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01001757 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001758 return 0;
1759
1760 default:
1761 break;
1762 }
1763
1764 return DefWindowProc(hWnd, msg, wParam, lParam);
1765}
1766
1767int main()
1768{
1769 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
1770
1771 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
1772 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
1773 wndClassDesc.hbrBackground = NULL;
1774 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
1775 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1776 wndClassDesc.hInstance = g_hAppInstance;
1777 wndClassDesc.lpfnWndProc = WndProc;
1778 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
1779
1780 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
1781 assert(hWndClass);
1782
1783 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
1784 const DWORD exStyle = 0;
1785
1786 RECT rect = { 0, 0, g_SizeX, g_SizeY };
1787 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
1788
Adam Sawicki86ccd632017-07-04 14:57:53 +02001789 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02001790 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
1791 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
1792 NULL, NULL, g_hAppInstance, NULL);
1793
1794 MSG msg;
1795 for(;;)
1796 {
1797 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
1798 {
1799 if(msg.message == WM_QUIT)
1800 break;
1801 TranslateMessage(&msg);
1802 DispatchMessage(&msg);
1803 }
1804 if(g_hDevice != VK_NULL_HANDLE)
1805 DrawFrame();
1806 }
1807
1808 return 0;
1809}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001810
Adam Sawickif1a793c2018-03-13 15:42:22 +01001811#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001812
Adam Sawickif1a793c2018-03-13 15:42:22 +01001813#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02001814
1815int main()
1816{
1817}
1818
Adam Sawickif1a793c2018-03-13 15:42:22 +01001819#endif // #ifdef _WIN32