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