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