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