blob: 0d07cfbb1a7b0acc6cd37e6a80cc3ca5541457e2 [file] [log] [blame]
Adam Sawickie6e498f2017-06-16 17:21:31 +02001//
Adam Sawickiaa183742021-02-16 17:28:49 +01002// Copyright (c) 2017-2021 Advanced Micro Devices, Inc. All rights reserved.
Adam Sawickie6e498f2017-06-16 17:21:31 +02003//
4// Permission is hereby granted, free of charge, to any person obtaining a copy
5// of this software and associated documentation files (the "Software"), to deal
6// in the Software without restriction, including without limitation the rights
7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8// copies of the Software, and to permit persons to whom the Software is
9// furnished to do so, subject to the following conditions:
10//
11// The above copyright notice and this permission notice shall be included in
12// all copies or substantial portions of the Software.
13//
14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20// THE SOFTWARE.
21//
22
Adam Sawickif1a793c2018-03-13 15:42:22 +010023#ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +020024
Adam Sawicki51fa9662018-10-03 13:44:29 +020025#include "SparseBindingTest.h"
Adam Sawickif1a793c2018-03-13 15:42:22 +010026#include "Tests.h"
27#include "VmaUsage.h"
28#include "Common.h"
Adam Sawicki8317ba92019-11-18 13:14:11 +010029#include <atomic>
Adam Sawickia75a61b2021-03-11 15:15:38 +010030#include <Shlwapi.h>
31
32#pragma comment(lib, "shlwapi.lib")
Adam Sawickie6e498f2017-06-16 17:21:31 +020033
34static const char* const SHADER_PATH1 = "./";
35static const char* const SHADER_PATH2 = "../bin/";
36static const wchar_t* const WINDOW_CLASS_NAME = L"VULKAN_MEMORY_ALLOCATOR_SAMPLE";
Adam Sawicki8caf0bd2020-07-15 16:56:30 +020037static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
Adam Sawicki8ef0d202020-03-02 15:43:47 +010038static const char* const APP_TITLE_A = "Vulkan Memory Allocator Sample 2.4.0";
39static const wchar_t* const APP_TITLE_W = L"Vulkan Memory Allocator Sample 2.4.0";
Adam Sawickie6e498f2017-06-16 17:21:31 +020040
41static const bool VSYNC = true;
42static const uint32_t COMMAND_BUFFER_COUNT = 2;
Adam Sawickia68c01c2018-03-13 16:40:45 +010043static void* const CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA = (void*)(intptr_t)43564544;
Adam Sawicki8317ba92019-11-18 13:14:11 +010044static const bool USE_CUSTOM_CPU_ALLOCATION_CALLBACKS = true;
Adam Sawickie6e498f2017-06-16 17:21:31 +020045
Adam Sawickia75a61b2021-03-11 15:15:38 +010046enum class ExitCode : int
47{
48 GPUList = 2,
49 Help = 1,
50 Success = 0,
51 RuntimeError = -1,
52 CommandLineError = -2,
53};
54
Adam Sawickib8333fb2018-03-13 16:15:53 +010055VkPhysicalDevice g_hPhysicalDevice;
56VkDevice g_hDevice;
57VmaAllocator g_hAllocator;
Adam Sawicki4ac8ff82019-11-18 14:47:33 +010058VkInstance g_hVulkanInstance;
Adam Sawickib8333fb2018-03-13 16:15:53 +010059
Adam Sawicki50882502020-02-07 16:51:31 +010060bool g_EnableValidationLayer = true;
61bool VK_KHR_get_memory_requirements2_enabled = false;
62bool VK_KHR_get_physical_device_properties2_enabled = false;
63bool VK_KHR_dedicated_allocation_enabled = false;
64bool VK_KHR_bind_memory2_enabled = false;
65bool VK_EXT_memory_budget_enabled = false;
66bool VK_AMD_device_coherent_memory_enabled = false;
Adam Sawickie73e9882020-03-20 18:05:42 +010067bool VK_KHR_buffer_device_address_enabled = false;
Adam Sawickif2012052021-01-11 18:04:42 +010068bool VK_EXT_memory_priority_enabled = false;
Adam Sawicki8caf0bd2020-07-15 16:56:30 +020069bool VK_EXT_debug_utils_enabled = false;
Adam Sawicki51fa9662018-10-03 13:44:29 +020070bool g_SparseBindingEnabled = false;
Adam Sawickie73e9882020-03-20 18:05:42 +010071
72// # Pointers to functions from extensions
Adam Sawicki0a3c6b52021-03-02 16:48:32 +010073PFN_vkGetBufferDeviceAddressKHR g_vkGetBufferDeviceAddressKHR;
Adam Sawicki6cc5e852018-03-13 16:37:54 +010074
Adam Sawickie6e498f2017-06-16 17:21:31 +020075static HINSTANCE g_hAppInstance;
76static HWND g_hWnd;
77static LONG g_SizeX = 1280, g_SizeY = 720;
Adam Sawickie6e498f2017-06-16 17:21:31 +020078static VkSurfaceKHR g_hSurface;
Adam Sawickie6e498f2017-06-16 17:21:31 +020079static VkQueue g_hPresentQueue;
80static VkSurfaceFormatKHR g_SurfaceFormat;
81static VkExtent2D g_Extent;
82static VkSwapchainKHR g_hSwapchain;
83static std::vector<VkImage> g_SwapchainImages;
84static std::vector<VkImageView> g_SwapchainImageViews;
85static std::vector<VkFramebuffer> g_Framebuffers;
86static VkCommandPool g_hCommandPool;
87static VkCommandBuffer g_MainCommandBuffers[COMMAND_BUFFER_COUNT];
88static VkFence g_MainCommandBufferExecutedFances[COMMAND_BUFFER_COUNT];
Adam Sawicki51fa9662018-10-03 13:44:29 +020089VkFence g_ImmediateFence;
Adam Sawickie6e498f2017-06-16 17:21:31 +020090static uint32_t g_NextCommandBufferIndex;
91static VkSemaphore g_hImageAvailableSemaphore;
92static VkSemaphore g_hRenderFinishedSemaphore;
93static uint32_t g_GraphicsQueueFamilyIndex = UINT_MAX;
94static uint32_t g_PresentQueueFamilyIndex = UINT_MAX;
Adam Sawicki51fa9662018-10-03 13:44:29 +020095static uint32_t g_SparseBindingQueueFamilyIndex = UINT_MAX;
Adam Sawickie6e498f2017-06-16 17:21:31 +020096static VkDescriptorSetLayout g_hDescriptorSetLayout;
97static VkDescriptorPool g_hDescriptorPool;
98static VkDescriptorSet g_hDescriptorSet; // Automatically destroyed with m_DescriptorPool.
99static VkSampler g_hSampler;
100static VkFormat g_DepthFormat;
101static VkImage g_hDepthImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200102static VmaAllocation g_hDepthImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200103static VkImageView g_hDepthImageView;
104
105static VkSurfaceCapabilitiesKHR g_SurfaceCapabilities;
106static std::vector<VkSurfaceFormatKHR> g_SurfaceFormats;
107static std::vector<VkPresentModeKHR> g_PresentModes;
108
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200109static const VkDebugUtilsMessageSeverityFlagsEXT DEBUG_UTILS_MESSENGER_MESSAGE_SEVERITY =
110 //VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
111 //VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
112 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
113 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
114static const VkDebugUtilsMessageTypeFlagsEXT DEBUG_UTILS_MESSENGER_MESSAGE_TYPE =
115 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
116 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
117 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
118static PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT_Func;
119static PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT_Func;
Adam Sawicki41b41112021-03-02 15:11:18 +0100120static PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT_Func;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200121
Adam Sawickie6e498f2017-06-16 17:21:31 +0200122static VkQueue g_hGraphicsQueue;
Adam Sawicki51fa9662018-10-03 13:44:29 +0200123VkQueue g_hSparseBindingQueue;
Adam Sawicki978fcf52018-12-05 14:38:48 +0100124VkCommandBuffer g_hTemporaryCommandBuffer;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200125
126static VkPipelineLayout g_hPipelineLayout;
127static VkRenderPass g_hRenderPass;
128static VkPipeline g_hPipeline;
129
130static VkBuffer g_hVertexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200131static VmaAllocation g_hVertexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200132static VkBuffer g_hIndexBuffer;
Adam Sawicki819860e2017-07-04 14:30:38 +0200133static VmaAllocation g_hIndexBufferAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200134static uint32_t g_VertexCount;
135static uint32_t g_IndexCount;
136
137static VkImage g_hTextureImage;
Adam Sawicki819860e2017-07-04 14:30:38 +0200138static VmaAllocation g_hTextureImageAlloc;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200139static VkImageView g_hTextureImageView;
140
Adam Sawicki8317ba92019-11-18 13:14:11 +0100141static std::atomic_uint32_t g_CpuAllocCount;
142
Adam Sawickia68c01c2018-03-13 16:40:45 +0100143static void* CustomCpuAllocation(
144 void* pUserData, size_t size, size_t alignment,
145 VkSystemAllocationScope allocationScope)
146{
147 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100148 void* const result = _aligned_malloc(size, alignment);
149 if(result)
150 {
151 ++g_CpuAllocCount;
152 }
153 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100154}
155
156static void* CustomCpuReallocation(
157 void* pUserData, void* pOriginal, size_t size, size_t alignment,
158 VkSystemAllocationScope allocationScope)
159{
160 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100161 void* const result = _aligned_realloc(pOriginal, size, alignment);
162 if(pOriginal && !result)
163 {
164 --g_CpuAllocCount;
165 }
166 else if(!pOriginal && result)
167 {
168 ++g_CpuAllocCount;
169 }
170 return result;
Adam Sawickia68c01c2018-03-13 16:40:45 +0100171}
172
173static void CustomCpuFree(void* pUserData, void* pMemory)
174{
175 assert(pUserData == CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA);
Adam Sawicki8317ba92019-11-18 13:14:11 +0100176 if(pMemory)
177 {
178 const uint32_t oldAllocCount = g_CpuAllocCount.fetch_sub(1);
179 TEST(oldAllocCount > 0);
180 _aligned_free(pMemory);
181 }
Adam Sawickia68c01c2018-03-13 16:40:45 +0100182}
183
Adam Sawicki1f84f622019-07-02 13:40:01 +0200184static const VkAllocationCallbacks g_CpuAllocationCallbacks = {
185 CUSTOM_CPU_ALLOCATION_CALLBACK_USER_DATA, // pUserData
186 &CustomCpuAllocation, // pfnAllocation
187 &CustomCpuReallocation, // pfnReallocation
188 &CustomCpuFree // pfnFree
189};
190
191const VkAllocationCallbacks* g_Allocs;
192
Adam Sawickia75a61b2021-03-11 15:15:38 +0100193struct GPUSelection
194{
195 uint32_t Index = UINT32_MAX;
196 std::wstring Substring;
197};
198
199class VulkanUsage
200{
201public:
202 void Init();
203 ~VulkanUsage();
204 void PrintPhysicalDeviceList() const;
205 // If failed, returns VK_NULL_HANDLE.
206 VkPhysicalDevice SelectPhysicalDevice(const GPUSelection& GPUSelection) const;
207
208private:
209 VkDebugUtilsMessengerEXT m_DebugUtilsMessenger = VK_NULL_HANDLE;
210
211 void RegisterDebugCallbacks();
212 static bool IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName);
213};
214
215struct CommandLineParameters
216{
217 bool m_Help = false;
218 bool m_List = false;
219 GPUSelection m_GPUSelection;
220
221 bool Parse(int argc, wchar_t** argv)
222 {
223 for(int i = 1; i < argc; ++i)
224 {
225 if(_wcsicmp(argv[i], L"-h") == 0 || _wcsicmp(argv[i], L"--Help") == 0)
226 {
227 m_Help = true;
228 }
229 else if(_wcsicmp(argv[i], L"-l") == 0 || _wcsicmp(argv[i], L"--List") == 0)
230 {
231 m_List = true;
232 }
233 else if((_wcsicmp(argv[i], L"-g") == 0 || _wcsicmp(argv[i], L"--GPU") == 0) && i + 1 < argc)
234 {
235 m_GPUSelection.Substring = argv[i + 1];
236 ++i;
237 }
238 else if((_wcsicmp(argv[i], L"-i") == 0 || _wcsicmp(argv[i], L"--GPUIndex") == 0) && i + 1 < argc)
239 {
240 m_GPUSelection.Index = _wtoi(argv[i + 1]);
241 ++i;
242 }
243 else
244 return false;
245 }
246 return true;
247 }
248} g_CommandLineParameters;
249
Adam Sawicki41b41112021-03-02 15:11:18 +0100250void SetDebugUtilsObjectName(VkObjectType type, uint64_t handle, const char* name)
251{
252 if(vkSetDebugUtilsObjectNameEXT_Func == nullptr)
253 return;
254
255 VkDebugUtilsObjectNameInfoEXT info = { VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT };
256 info.objectType = type;
257 info.objectHandle = handle;
258 info.pObjectName = name;
259 vkSetDebugUtilsObjectNameEXT_Func(g_hDevice, &info);
260}
261
Adam Sawicki978fcf52018-12-05 14:38:48 +0100262void BeginSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200263{
264 VkCommandBufferBeginInfo cmdBufBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
265 cmdBufBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
266 ERR_GUARD_VULKAN( vkBeginCommandBuffer(g_hTemporaryCommandBuffer, &cmdBufBeginInfo) );
267}
268
Adam Sawicki978fcf52018-12-05 14:38:48 +0100269void EndSingleTimeCommands()
Adam Sawickie6e498f2017-06-16 17:21:31 +0200270{
271 ERR_GUARD_VULKAN( vkEndCommandBuffer(g_hTemporaryCommandBuffer) );
272
273 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
274 submitInfo.commandBufferCount = 1;
275 submitInfo.pCommandBuffers = &g_hTemporaryCommandBuffer;
276
277 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE) );
278 ERR_GUARD_VULKAN( vkQueueWaitIdle(g_hGraphicsQueue) );
279}
280
Adam Sawickida6c1942018-12-05 17:34:34 +0100281void LoadShader(std::vector<char>& out, const char* fileName)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200282{
283 std::ifstream file(std::string(SHADER_PATH1) + fileName, std::ios::ate | std::ios::binary);
284 if(file.is_open() == false)
285 file.open(std::string(SHADER_PATH2) + fileName, std::ios::ate | std::ios::binary);
286 assert(file.is_open());
287 size_t fileSize = (size_t)file.tellg();
288 if(fileSize > 0)
289 {
290 out.resize(fileSize);
291 file.seekg(0);
292 file.read(out.data(), fileSize);
293 file.close();
294 }
295 else
296 out.clear();
297}
298
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200299static VkBool32 VKAPI_PTR MyDebugReportCallback(
300 VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
301 VkDebugUtilsMessageTypeFlagsEXT messageTypes,
302 const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
303 void* pUserData)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200304{
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200305 assert(pCallbackData && pCallbackData->pMessageIdName && pCallbackData->pMessage);
Adam Sawickib8333fb2018-03-13 16:15:53 +0100306
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200307 switch(messageSeverity)
Adam Sawickib8333fb2018-03-13 16:15:53 +0100308 {
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200309 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
Adam Sawickib8333fb2018-03-13 16:15:53 +0100310 SetConsoleColor(CONSOLE_COLOR::WARNING);
311 break;
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200312 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
Adam Sawickib8333fb2018-03-13 16:15:53 +0100313 SetConsoleColor(CONSOLE_COLOR::ERROR_);
314 break;
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200315 case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
316 SetConsoleColor(CONSOLE_COLOR::NORMAL);
317 break;
318 default: // VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
Adam Sawickib8333fb2018-03-13 16:15:53 +0100319 SetConsoleColor(CONSOLE_COLOR::INFO);
320 }
321
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200322 printf("%s \xBA %s\n", pCallbackData->pMessageIdName, pCallbackData->pMessage);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200323
Adam Sawickib8333fb2018-03-13 16:15:53 +0100324 SetConsoleColor(CONSOLE_COLOR::NORMAL);
325
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200326 if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT ||
327 messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
Adam Sawickie6e498f2017-06-16 17:21:31 +0200328 {
Adam Sawicki8caf0bd2020-07-15 16:56:30 +0200329 OutputDebugStringA(pCallbackData->pMessage);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200330 OutputDebugStringA("\n");
331 }
332
333 return VK_FALSE;
334}
335
336static VkSurfaceFormatKHR ChooseSurfaceFormat()
337{
338 assert(!g_SurfaceFormats.empty());
339
340 if((g_SurfaceFormats.size() == 1) && (g_SurfaceFormats[0].format == VK_FORMAT_UNDEFINED))
341 {
342 VkSurfaceFormatKHR result = { VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
343 return result;
344 }
345
346 for(const auto& format : g_SurfaceFormats)
347 {
348 if((format.format == VK_FORMAT_B8G8R8A8_UNORM) &&
349 (format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR))
350 {
351 return format;
352 }
353 }
354
355 return g_SurfaceFormats[0];
356}
357
358VkPresentModeKHR ChooseSwapPresentMode()
359{
360 VkPresentModeKHR preferredMode = VSYNC ? VK_PRESENT_MODE_MAILBOX_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR;
361
362 if(std::find(g_PresentModes.begin(), g_PresentModes.end(), preferredMode) !=
363 g_PresentModes.end())
364 {
365 return preferredMode;
366 }
367
368 return VK_PRESENT_MODE_FIFO_KHR;
369}
370
371static VkExtent2D ChooseSwapExtent()
372{
373 if(g_SurfaceCapabilities.currentExtent.width != UINT_MAX)
374 return g_SurfaceCapabilities.currentExtent;
375
376 VkExtent2D result = {
377 std::max(g_SurfaceCapabilities.minImageExtent.width,
378 std::min(g_SurfaceCapabilities.maxImageExtent.width, (uint32_t)g_SizeX)),
379 std::max(g_SurfaceCapabilities.minImageExtent.height,
380 std::min(g_SurfaceCapabilities.maxImageExtent.height, (uint32_t)g_SizeY)) };
381 return result;
382}
383
Adam Sawickia75a61b2021-03-11 15:15:38 +0100384static constexpr uint32_t GetVulkanApiVersion()
385{
386#if VMA_VULKAN_VERSION == 1002000
387 return VK_API_VERSION_1_2;
388#elif VMA_VULKAN_VERSION == 1001000
389 return VK_API_VERSION_1_1;
390#elif VMA_VULKAN_VERSION == 1000000
391 return VK_API_VERSION_1_0;
392#else
393#error Invalid VMA_VULKAN_VERSION.
394 return UINT32_MAX;
395#endif
396}
397
398void VulkanUsage::Init()
399{
400 g_hAppInstance = (HINSTANCE)GetModuleHandle(NULL);
401
402 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
403 {
404 g_Allocs = &g_CpuAllocationCallbacks;
405 }
406
407 uint32_t instanceLayerPropCount = 0;
408 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, nullptr) );
409 std::vector<VkLayerProperties> instanceLayerProps(instanceLayerPropCount);
410 if(instanceLayerPropCount > 0)
411 {
412 ERR_GUARD_VULKAN( vkEnumerateInstanceLayerProperties(&instanceLayerPropCount, instanceLayerProps.data()) );
413 }
414
415 if(g_EnableValidationLayer)
416 {
417 if(IsLayerSupported(instanceLayerProps.data(), instanceLayerProps.size(), VALIDATION_LAYER_NAME) == false)
418 {
419 wprintf(L"Layer \"%hs\" not supported.", VALIDATION_LAYER_NAME);
420 g_EnableValidationLayer = false;
421 }
422 }
423
424 uint32_t availableInstanceExtensionCount = 0;
425 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, nullptr) );
426 std::vector<VkExtensionProperties> availableInstanceExtensions(availableInstanceExtensionCount);
427 if(availableInstanceExtensionCount > 0)
428 {
429 ERR_GUARD_VULKAN( vkEnumerateInstanceExtensionProperties(nullptr, &availableInstanceExtensionCount, availableInstanceExtensions.data()) );
430 }
431
432 std::vector<const char*> enabledInstanceExtensions;
433 enabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
434 enabledInstanceExtensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
435
436 std::vector<const char*> instanceLayers;
437 if(g_EnableValidationLayer)
438 {
439 instanceLayers.push_back(VALIDATION_LAYER_NAME);
440 }
441
442 for(const auto& extensionProperties : availableInstanceExtensions)
443 {
444 if(strcmp(extensionProperties.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0)
445 {
446 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
447 {
448 enabledInstanceExtensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
449 VK_KHR_get_physical_device_properties2_enabled = true;
450 }
451 }
452 else if(strcmp(extensionProperties.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0)
453 {
454 enabledInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
455 VK_EXT_debug_utils_enabled = true;
456 }
457 }
458
459 VkApplicationInfo appInfo = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
460 appInfo.pApplicationName = APP_TITLE_A;
461 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
462 appInfo.pEngineName = "Adam Sawicki Engine";
463 appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
464 appInfo.apiVersion = GetVulkanApiVersion();
465
466 VkInstanceCreateInfo instInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
467 instInfo.pApplicationInfo = &appInfo;
468 instInfo.enabledExtensionCount = static_cast<uint32_t>(enabledInstanceExtensions.size());
469 instInfo.ppEnabledExtensionNames = enabledInstanceExtensions.data();
470 instInfo.enabledLayerCount = static_cast<uint32_t>(instanceLayers.size());
471 instInfo.ppEnabledLayerNames = instanceLayers.data();
472
473 wprintf(L"Vulkan API version used: ");
474 switch(appInfo.apiVersion)
475 {
476 case VK_API_VERSION_1_0: wprintf(L"1.0\n"); break;
477 case VK_API_VERSION_1_1: wprintf(L"1.1\n"); break;
478 case VK_API_VERSION_1_2: wprintf(L"1.2\n"); break;
479 default: assert(0);
480 }
481
482 ERR_GUARD_VULKAN( vkCreateInstance(&instInfo, g_Allocs, &g_hVulkanInstance) );
483
484 if(VK_EXT_debug_utils_enabled)
485 {
486 RegisterDebugCallbacks();
487 }
488}
489
490VulkanUsage::~VulkanUsage()
491{
492 if(m_DebugUtilsMessenger)
493 {
494 vkDestroyDebugUtilsMessengerEXT_Func(g_hVulkanInstance, m_DebugUtilsMessenger, g_Allocs);
495 }
496
497 if(g_hVulkanInstance)
498 {
499 vkDestroyInstance(g_hVulkanInstance, g_Allocs);
500 g_hVulkanInstance = VK_NULL_HANDLE;
501 }
502}
503
504void VulkanUsage::PrintPhysicalDeviceList() const
505{
506 uint32_t deviceCount = 0;
507 ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr));
508 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
509 if(deviceCount > 0)
510 {
511 ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()));
512 }
513
514 for(size_t i = 0; i < deviceCount; ++i)
515 {
516 VkPhysicalDeviceProperties props = {};
517 vkGetPhysicalDeviceProperties(physicalDevices[i], &props);
518 wprintf(L"Physical device %zu: %hs\n", i, props.deviceName);
519 }
520}
521
522VkPhysicalDevice VulkanUsage::SelectPhysicalDevice(const GPUSelection& GPUSelection) const
523{
524 uint32_t deviceCount = 0;
525 ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, nullptr));
526 std::vector<VkPhysicalDevice> physicalDevices(deviceCount);
527 if(deviceCount > 0)
528 {
529 ERR_GUARD_VULKAN(vkEnumeratePhysicalDevices(g_hVulkanInstance, &deviceCount, physicalDevices.data()));
530 }
531
532 if(GPUSelection.Index != UINT32_MAX)
533 {
534 // Cannot specify both index and name.
535 if(!GPUSelection.Substring.empty())
536 {
537 return VK_NULL_HANDLE;
538 }
539
540 return GPUSelection.Index < deviceCount ? physicalDevices[GPUSelection.Index] : VK_NULL_HANDLE;
541 }
542
543 if(!GPUSelection.Substring.empty())
544 {
545 VkPhysicalDevice result = VK_NULL_HANDLE;
546 std::wstring name;
547 for(uint32_t i = 0; i < deviceCount; ++i)
548 {
549 VkPhysicalDeviceProperties props = {};
550 vkGetPhysicalDeviceProperties(physicalDevices[i], &props);
551 if(ConvertCharsToUnicode(&name, props.deviceName, strlen(props.deviceName), CP_UTF8) &&
552 StrStrI(name.c_str(), GPUSelection.Substring.c_str()))
553 {
554 // Second matching device found - error.
555 if(result != VK_NULL_HANDLE)
556 {
557 return VK_NULL_HANDLE;
558 }
559 // First matching device found.
560 result = physicalDevices[i];
561 }
562 }
563 // Found or not, return it.
564 return result;
565 }
566
567 // Select first one.
568 return deviceCount > 0 ? physicalDevices[0] : VK_NULL_HANDLE;
569}
570
571void VulkanUsage::RegisterDebugCallbacks()
572{
573 vkCreateDebugUtilsMessengerEXT_Func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
574 g_hVulkanInstance, "vkCreateDebugUtilsMessengerEXT");
575 vkDestroyDebugUtilsMessengerEXT_Func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
576 g_hVulkanInstance, "vkDestroyDebugUtilsMessengerEXT");
577 vkSetDebugUtilsObjectNameEXT_Func = (PFN_vkSetDebugUtilsObjectNameEXT)vkGetInstanceProcAddr(
578 g_hVulkanInstance, "vkSetDebugUtilsObjectNameEXT");
579 assert(vkCreateDebugUtilsMessengerEXT_Func);
580 assert(vkDestroyDebugUtilsMessengerEXT_Func);
581 assert(vkSetDebugUtilsObjectNameEXT_Func);
582
583 VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = { VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT };
584 messengerCreateInfo.messageSeverity = DEBUG_UTILS_MESSENGER_MESSAGE_SEVERITY;
585 messengerCreateInfo.messageType = DEBUG_UTILS_MESSENGER_MESSAGE_TYPE;
586 messengerCreateInfo.pfnUserCallback = MyDebugReportCallback;
587 ERR_GUARD_VULKAN( vkCreateDebugUtilsMessengerEXT_Func(g_hVulkanInstance, &messengerCreateInfo, g_Allocs, &m_DebugUtilsMessenger) );
588}
589
590bool VulkanUsage::IsLayerSupported(const VkLayerProperties* pProps, size_t propCount, const char* pLayerName)
591{
592 const VkLayerProperties* propsEnd = pProps + propCount;
593 return std::find_if(
594 pProps,
595 propsEnd,
596 [pLayerName](const VkLayerProperties& prop) -> bool {
597 return strcmp(pLayerName, prop.layerName) == 0;
598 }) != propsEnd;
599}
600
Adam Sawickie6e498f2017-06-16 17:21:31 +0200601struct Vertex
602{
603 float pos[3];
604 float color[3];
605 float texCoord[2];
606};
607
608static void CreateMesh()
609{
610 assert(g_hAllocator);
611
612 static Vertex vertices[] = {
613 // -X
614 { { -1.f, -1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 0.f} },
615 { { -1.f, -1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 0.f} },
616 { { -1.f, 1.f, -1.f}, {1.0f, 0.0f, 0.0f}, {0.f, 1.f} },
617 { { -1.f, 1.f, 1.f}, {1.0f, 0.0f, 0.0f}, {1.f, 1.f} },
618 // +X
619 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 0.f} },
620 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 0.f} },
621 { { 1.f, 1.f, 1.f}, {0.0f, 1.0f, 0.0f}, {0.f, 1.f} },
622 { { 1.f, 1.f, -1.f}, {0.0f, 1.0f, 0.0f}, {1.f, 1.f} },
623 // -Z
624 { { 1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 0.f} },
625 { {-1.f, -1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 0.f} },
626 { { 1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {0.f, 1.f} },
627 { {-1.f, 1.f, -1.f}, {0.0f, 0.0f, 1.0f}, {1.f, 1.f} },
628 // +Z
629 { {-1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 0.f} },
630 { { 1.f, -1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 0.f} },
631 { {-1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {0.f, 1.f} },
632 { { 1.f, 1.f, 1.f}, {1.0f, 1.0f, 0.0f}, {1.f, 1.f} },
633 // -Y
634 { {-1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 0.f} },
635 { { 1.f, -1.f, -1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 0.f} },
636 { {-1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {0.f, 1.f} },
637 { { 1.f, -1.f, 1.f}, {0.0f, 1.0f, 1.0f}, {1.f, 1.f} },
638 // +Y
639 { { 1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 0.f} },
640 { {-1.f, 1.f, -1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 0.f} },
641 { { 1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {0.f, 1.f} },
642 { {-1.f, 1.f, 1.f}, {1.0f, 0.0f, 1.0f}, {1.f, 1.f} },
643 };
644 static uint16_t indices[] = {
645 0, 1, 2, 3, USHRT_MAX,
646 4, 5, 6, 7, USHRT_MAX,
647 8, 9, 10, 11, USHRT_MAX,
648 12, 13, 14, 15, USHRT_MAX,
649 16, 17, 18, 19, USHRT_MAX,
650 20, 21, 22, 23, USHRT_MAX,
651 };
652
653 size_t vertexBufferSize = sizeof(Vertex) * _countof(vertices);
654 size_t indexBufferSize = sizeof(uint16_t) * _countof(indices);
655 g_IndexCount = (uint32_t)_countof(indices);
656
657 // Create vertex buffer
658
659 VkBufferCreateInfo vbInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
660 vbInfo.size = vertexBufferSize;
661 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
662 vbInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200663
Adam Sawicki976f9202017-09-12 20:45:14 +0200664 VmaAllocationCreateInfo vbAllocCreateInfo = {};
665 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100666 vbAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200667
Adam Sawicki819860e2017-07-04 14:30:38 +0200668 VkBuffer stagingVertexBuffer = VK_NULL_HANDLE;
669 VmaAllocation stagingVertexBufferAlloc = VK_NULL_HANDLE;
670 VmaAllocationInfo stagingVertexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200671 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &stagingVertexBuffer, &stagingVertexBufferAlloc, &stagingVertexBufferAllocInfo) );
Adam Sawicki819860e2017-07-04 14:30:38 +0200672
673 memcpy(stagingVertexBufferAllocInfo.pMappedData, vertices, vertexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200674
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200675 // No need to flush stagingVertexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
676
Adam Sawickie6e498f2017-06-16 17:21:31 +0200677 vbInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200678 vbAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
679 vbAllocCreateInfo.flags = 0;
680 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &vbInfo, &vbAllocCreateInfo, &g_hVertexBuffer, &g_hVertexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200681
682 // Create index buffer
683
684 VkBufferCreateInfo ibInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
685 ibInfo.size = indexBufferSize;
686 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
687 ibInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200688
Adam Sawicki976f9202017-09-12 20:45:14 +0200689 VmaAllocationCreateInfo ibAllocCreateInfo = {};
690 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
Adam Sawicki5268dbb2017-11-08 12:52:05 +0100691 ibAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200692
Adam Sawickie6e498f2017-06-16 17:21:31 +0200693 VkBuffer stagingIndexBuffer = VK_NULL_HANDLE;
Adam Sawicki819860e2017-07-04 14:30:38 +0200694 VmaAllocation stagingIndexBufferAlloc = VK_NULL_HANDLE;
695 VmaAllocationInfo stagingIndexBufferAllocInfo = {};
Adam Sawicki976f9202017-09-12 20:45:14 +0200696 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &stagingIndexBuffer, &stagingIndexBufferAlloc, &stagingIndexBufferAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200697
Adam Sawicki819860e2017-07-04 14:30:38 +0200698 memcpy(stagingIndexBufferAllocInfo.pMappedData, indices, indexBufferSize);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200699
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200700 // No need to flush stagingIndexBuffer memory because CPU_ONLY memory is always HOST_COHERENT.
701
Adam Sawickie6e498f2017-06-16 17:21:31 +0200702 ibInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
Adam Sawicki976f9202017-09-12 20:45:14 +0200703 ibAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
704 ibAllocCreateInfo.flags = 0;
705 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &ibInfo, &ibAllocCreateInfo, &g_hIndexBuffer, &g_hIndexBufferAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200706
707 // Copy buffers
708
709 BeginSingleTimeCommands();
710
711 VkBufferCopy vbCopyRegion = {};
712 vbCopyRegion.srcOffset = 0;
713 vbCopyRegion.dstOffset = 0;
714 vbCopyRegion.size = vbInfo.size;
715 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingVertexBuffer, g_hVertexBuffer, 1, &vbCopyRegion);
716
717 VkBufferCopy ibCopyRegion = {};
718 ibCopyRegion.srcOffset = 0;
719 ibCopyRegion.dstOffset = 0;
720 ibCopyRegion.size = ibInfo.size;
721 vkCmdCopyBuffer(g_hTemporaryCommandBuffer, stagingIndexBuffer, g_hIndexBuffer, 1, &ibCopyRegion);
722
723 EndSingleTimeCommands();
724
Adam Sawicki819860e2017-07-04 14:30:38 +0200725 vmaDestroyBuffer(g_hAllocator, stagingIndexBuffer, stagingIndexBufferAlloc);
726 vmaDestroyBuffer(g_hAllocator, stagingVertexBuffer, stagingVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200727}
728
Adam Sawickie6e498f2017-06-16 17:21:31 +0200729static void CreateTexture(uint32_t sizeX, uint32_t sizeY)
730{
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100731 // Create staging buffer.
Adam Sawickie6e498f2017-06-16 17:21:31 +0200732
733 const VkDeviceSize imageSize = sizeX * sizeY * 4;
734
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100735 VkBufferCreateInfo stagingBufInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
736 stagingBufInfo.size = imageSize;
737 stagingBufInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
738
739 VmaAllocationCreateInfo stagingBufAllocCreateInfo = {};
740 stagingBufAllocCreateInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
741 stagingBufAllocCreateInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
Adam Sawicki819860e2017-07-04 14:30:38 +0200742
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100743 VkBuffer stagingBuf = VK_NULL_HANDLE;
744 VmaAllocation stagingBufAlloc = VK_NULL_HANDLE;
745 VmaAllocationInfo stagingBufAllocInfo = {};
746 ERR_GUARD_VULKAN( vmaCreateBuffer(g_hAllocator, &stagingBufInfo, &stagingBufAllocCreateInfo, &stagingBuf, &stagingBufAlloc, &stagingBufAllocInfo) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200747
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100748 char* const pImageData = (char*)stagingBufAllocInfo.pMappedData;
749 uint8_t* pRowData = (uint8_t*)pImageData;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200750 for(uint32_t y = 0; y < sizeY; ++y)
751 {
752 uint32_t* pPixelData = (uint32_t*)pRowData;
753 for(uint32_t x = 0; x < sizeY; ++x)
754 {
755 *pPixelData =
756 ((x & 0x18) == 0x08 ? 0x000000FF : 0x00000000) |
757 ((x & 0x18) == 0x10 ? 0x0000FFFF : 0x00000000) |
758 ((y & 0x18) == 0x08 ? 0x0000FF00 : 0x00000000) |
759 ((y & 0x18) == 0x10 ? 0x00FF0000 : 0x00000000);
760 ++pPixelData;
761 }
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100762 pRowData += sizeX * 4;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200763 }
764
Adam Sawicki2f16fa52017-07-04 14:43:20 +0200765 // No need to flush stagingImage memory because CPU_ONLY memory is always HOST_COHERENT.
766
Adam Sawicki10844a82017-08-16 17:32:09 +0200767 // Create g_hTextureImage in GPU memory.
768
Adam Sawickie6e498f2017-06-16 17:21:31 +0200769 VkImageCreateInfo imageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
770 imageInfo.imageType = VK_IMAGE_TYPE_2D;
771 imageInfo.extent.width = sizeX;
772 imageInfo.extent.height = sizeY;
773 imageInfo.extent.depth = 1;
774 imageInfo.mipLevels = 1;
775 imageInfo.arrayLayers = 1;
776 imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
777 imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
778 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
779 imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
780 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
781 imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
782 imageInfo.flags = 0;
Adam Sawicki10844a82017-08-16 17:32:09 +0200783
Adam Sawicki976f9202017-09-12 20:45:14 +0200784 VmaAllocationCreateInfo imageAllocCreateInfo = {};
785 imageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawicki10844a82017-08-16 17:32:09 +0200786
Adam Sawicki976f9202017-09-12 20:45:14 +0200787 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &imageInfo, &imageAllocCreateInfo, &g_hTextureImage, &g_hTextureImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200788
Adam Sawicki10844a82017-08-16 17:32:09 +0200789 // Transition image layouts, copy image.
790
791 BeginSingleTimeCommands();
792
793 VkImageMemoryBarrier imgMemBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
Adam Sawicki10844a82017-08-16 17:32:09 +0200794 imgMemBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
795 imgMemBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Adam Sawicki10844a82017-08-16 17:32:09 +0200796 imgMemBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
797 imgMemBarrier.subresourceRange.baseMipLevel = 0;
798 imgMemBarrier.subresourceRange.levelCount = 1;
799 imgMemBarrier.subresourceRange.baseArrayLayer = 0;
800 imgMemBarrier.subresourceRange.layerCount = 1;
Adam Sawicki10844a82017-08-16 17:32:09 +0200801 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
802 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
803 imgMemBarrier.image = g_hTextureImage;
804 imgMemBarrier.srcAccessMask = 0;
805 imgMemBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
806
807 vkCmdPipelineBarrier(
808 g_hTemporaryCommandBuffer,
809 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
810 VK_PIPELINE_STAGE_TRANSFER_BIT,
811 0,
812 0, nullptr,
813 0, nullptr,
814 1, &imgMemBarrier);
815
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100816 VkBufferImageCopy region = {};
817 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
818 region.imageSubresource.layerCount = 1;
819 region.imageExtent.width = sizeX;
820 region.imageExtent.height = sizeY;
821 region.imageExtent.depth = 1;
822
823 vkCmdCopyBufferToImage(g_hTemporaryCommandBuffer, stagingBuf, g_hTextureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
Adam Sawicki10844a82017-08-16 17:32:09 +0200824
825 imgMemBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
826 imgMemBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
827 imgMemBarrier.image = g_hTextureImage;
828 imgMemBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
829 imgMemBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
830
831 vkCmdPipelineBarrier(
832 g_hTemporaryCommandBuffer,
833 VK_PIPELINE_STAGE_TRANSFER_BIT,
834 VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
835 0,
836 0, nullptr,
837 0, nullptr,
838 1, &imgMemBarrier);
839
840 EndSingleTimeCommands();
Adam Sawickie6e498f2017-06-16 17:21:31 +0200841
Adam Sawickif43e9cd2019-02-20 14:55:31 +0100842 vmaDestroyBuffer(g_hAllocator, stagingBuf, stagingBufAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200843
844 // Create ImageView
845
846 VkImageViewCreateInfo textureImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
847 textureImageViewInfo.image = g_hTextureImage;
848 textureImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
849 textureImageViewInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
850 textureImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
851 textureImageViewInfo.subresourceRange.baseMipLevel = 0;
852 textureImageViewInfo.subresourceRange.levelCount = 1;
853 textureImageViewInfo.subresourceRange.baseArrayLayer = 0;
854 textureImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200855 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &textureImageViewInfo, g_Allocs, &g_hTextureImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200856}
857
858struct UniformBufferObject
859{
Adam Sawicki82c3f332018-06-11 15:27:33 +0200860 mat4 ModelViewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +0200861};
862
Adam Sawickie6e498f2017-06-16 17:21:31 +0200863static VkFormat FindSupportedFormat(
864 const std::vector<VkFormat>& candidates,
865 VkImageTiling tiling,
866 VkFormatFeatureFlags features)
867{
868 for (VkFormat format : candidates)
869 {
870 VkFormatProperties props;
871 vkGetPhysicalDeviceFormatProperties(g_hPhysicalDevice, format, &props);
872
873 if ((tiling == VK_IMAGE_TILING_LINEAR) &&
874 ((props.linearTilingFeatures & features) == features))
875 {
876 return format;
877 }
878 else if ((tiling == VK_IMAGE_TILING_OPTIMAL) &&
879 ((props.optimalTilingFeatures & features) == features))
880 {
881 return format;
882 }
883 }
884 return VK_FORMAT_UNDEFINED;
885}
886
887static VkFormat FindDepthFormat()
888{
889 std::vector<VkFormat> formats;
890 formats.push_back(VK_FORMAT_D32_SFLOAT);
891 formats.push_back(VK_FORMAT_D32_SFLOAT_S8_UINT);
892 formats.push_back(VK_FORMAT_D24_UNORM_S8_UINT);
893
894 return FindSupportedFormat(
895 formats,
896 VK_IMAGE_TILING_OPTIMAL,
897 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT);
898}
899
900static void CreateSwapchain()
901{
902 // Query surface formats.
903
904 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_hPhysicalDevice, g_hSurface, &g_SurfaceCapabilities) );
905
906 uint32_t formatCount = 0;
907 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, nullptr) );
908 g_SurfaceFormats.resize(formatCount);
909 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfaceFormatsKHR(g_hPhysicalDevice, g_hSurface, &formatCount, g_SurfaceFormats.data()) );
910
911 uint32_t presentModeCount = 0;
912 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, nullptr) );
913 g_PresentModes.resize(presentModeCount);
914 ERR_GUARD_VULKAN( vkGetPhysicalDeviceSurfacePresentModesKHR(g_hPhysicalDevice, g_hSurface, &presentModeCount, g_PresentModes.data()) );
915
916 // Create swap chain
917
918 g_SurfaceFormat = ChooseSurfaceFormat();
919 VkPresentModeKHR presentMode = ChooseSwapPresentMode();
920 g_Extent = ChooseSwapExtent();
921
922 uint32_t imageCount = g_SurfaceCapabilities.minImageCount + 1;
923 if((g_SurfaceCapabilities.maxImageCount > 0) &&
924 (imageCount > g_SurfaceCapabilities.maxImageCount))
925 {
926 imageCount = g_SurfaceCapabilities.maxImageCount;
927 }
928
929 VkSwapchainCreateInfoKHR swapChainInfo = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
930 swapChainInfo.surface = g_hSurface;
931 swapChainInfo.minImageCount = imageCount;
932 swapChainInfo.imageFormat = g_SurfaceFormat.format;
933 swapChainInfo.imageColorSpace = g_SurfaceFormat.colorSpace;
934 swapChainInfo.imageExtent = g_Extent;
935 swapChainInfo.imageArrayLayers = 1;
936 swapChainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
937 swapChainInfo.preTransform = g_SurfaceCapabilities.currentTransform;
938 swapChainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
939 swapChainInfo.presentMode = presentMode;
940 swapChainInfo.clipped = VK_TRUE;
941 swapChainInfo.oldSwapchain = g_hSwapchain;
942
943 uint32_t queueFamilyIndices[] = { g_GraphicsQueueFamilyIndex, g_PresentQueueFamilyIndex };
944 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
945 {
946 swapChainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
947 swapChainInfo.queueFamilyIndexCount = 2;
948 swapChainInfo.pQueueFamilyIndices = queueFamilyIndices;
949 }
950 else
951 {
952 swapChainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
953 }
954
955 VkSwapchainKHR hNewSwapchain = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200956 ERR_GUARD_VULKAN( vkCreateSwapchainKHR(g_hDevice, &swapChainInfo, g_Allocs, &hNewSwapchain) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200957 if(g_hSwapchain != VK_NULL_HANDLE)
Adam Sawicki1f84f622019-07-02 13:40:01 +0200958 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200959 g_hSwapchain = hNewSwapchain;
960
961 // Retrieve swapchain images.
962
963 uint32_t swapchainImageCount = 0;
964 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, nullptr) );
965 g_SwapchainImages.resize(swapchainImageCount);
966 ERR_GUARD_VULKAN( vkGetSwapchainImagesKHR(g_hDevice, g_hSwapchain, &swapchainImageCount, g_SwapchainImages.data()) );
967
968 // Create swapchain image views.
969
970 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +0200971 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +0200972 g_SwapchainImageViews.clear();
973
974 VkImageViewCreateInfo swapchainImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
975 g_SwapchainImageViews.resize(swapchainImageCount);
976 for(uint32_t i = 0; i < swapchainImageCount; ++i)
977 {
978 swapchainImageViewInfo.image = g_SwapchainImages[i];
979 swapchainImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
980 swapchainImageViewInfo.format = g_SurfaceFormat.format;
981 swapchainImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
982 swapchainImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
983 swapchainImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
984 swapchainImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
985 swapchainImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
986 swapchainImageViewInfo.subresourceRange.baseMipLevel = 0;
987 swapchainImageViewInfo.subresourceRange.levelCount = 1;
988 swapchainImageViewInfo.subresourceRange.baseArrayLayer = 0;
989 swapchainImageViewInfo.subresourceRange.layerCount = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +0200990 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &swapchainImageViewInfo, g_Allocs, &g_SwapchainImageViews[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +0200991 }
992
993 // Create depth buffer
994
995 g_DepthFormat = FindDepthFormat();
996 assert(g_DepthFormat != VK_FORMAT_UNDEFINED);
997
998 VkImageCreateInfo depthImageInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
999 depthImageInfo.imageType = VK_IMAGE_TYPE_2D;
1000 depthImageInfo.extent.width = g_Extent.width;
1001 depthImageInfo.extent.height = g_Extent.height;
1002 depthImageInfo.extent.depth = 1;
1003 depthImageInfo.mipLevels = 1;
1004 depthImageInfo.arrayLayers = 1;
1005 depthImageInfo.format = g_DepthFormat;
1006 depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1007 depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1008 depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1009 depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1010 depthImageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
1011 depthImageInfo.flags = 0;
1012
Adam Sawicki976f9202017-09-12 20:45:14 +02001013 VmaAllocationCreateInfo depthImageAllocCreateInfo = {};
1014 depthImageAllocCreateInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001015
Adam Sawicki976f9202017-09-12 20:45:14 +02001016 ERR_GUARD_VULKAN( vmaCreateImage(g_hAllocator, &depthImageInfo, &depthImageAllocCreateInfo, &g_hDepthImage, &g_hDepthImageAlloc, nullptr) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001017
1018 VkImageViewCreateInfo depthImageViewInfo = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO };
1019 depthImageViewInfo.image = g_hDepthImage;
1020 depthImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1021 depthImageViewInfo.format = g_DepthFormat;
1022 depthImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
1023 depthImageViewInfo.subresourceRange.baseMipLevel = 0;
1024 depthImageViewInfo.subresourceRange.levelCount = 1;
1025 depthImageViewInfo.subresourceRange.baseArrayLayer = 0;
1026 depthImageViewInfo.subresourceRange.layerCount = 1;
1027
Adam Sawicki1f84f622019-07-02 13:40:01 +02001028 ERR_GUARD_VULKAN( vkCreateImageView(g_hDevice, &depthImageViewInfo, g_Allocs, &g_hDepthImageView) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001029
Adam Sawickie6e498f2017-06-16 17:21:31 +02001030 // Create pipeline layout
1031 {
1032 if(g_hPipelineLayout != VK_NULL_HANDLE)
1033 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001034 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001035 g_hPipelineLayout = VK_NULL_HANDLE;
1036 }
1037
1038 VkPushConstantRange pushConstantRanges[1];
1039 ZeroMemory(&pushConstantRanges, sizeof pushConstantRanges);
1040 pushConstantRanges[0].offset = 0;
1041 pushConstantRanges[0].size = sizeof(UniformBufferObject);
1042 pushConstantRanges[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
1043
1044 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
1045 VkPipelineLayoutCreateInfo pipelineLayoutInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO };
1046 pipelineLayoutInfo.setLayoutCount = 1;
1047 pipelineLayoutInfo.pSetLayouts = descriptorSetLayouts;
1048 pipelineLayoutInfo.pushConstantRangeCount = 1;
1049 pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001050 ERR_GUARD_VULKAN( vkCreatePipelineLayout(g_hDevice, &pipelineLayoutInfo, g_Allocs, &g_hPipelineLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001051 }
1052
1053 // Create render pass
1054 {
1055 if(g_hRenderPass != VK_NULL_HANDLE)
1056 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001057 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001058 g_hRenderPass = VK_NULL_HANDLE;
1059 }
1060
1061 VkAttachmentDescription attachments[2];
1062 ZeroMemory(attachments, sizeof(attachments));
1063
1064 attachments[0].format = g_SurfaceFormat.format;
1065 attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
1066 attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1067 attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1068 attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1069 attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +01001070 attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001071 attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1072
1073 attachments[1].format = g_DepthFormat;
1074 attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
1075 attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1076 attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1077 attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1078 attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
Adam Sawicki8eb9d8e2017-11-13 16:30:14 +01001079 attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001080 attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1081
1082 VkAttachmentReference colorAttachmentRef = {};
1083 colorAttachmentRef.attachment = 0;
1084 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1085
1086 VkAttachmentReference depthStencilAttachmentRef = {};
1087 depthStencilAttachmentRef.attachment = 1;
1088 depthStencilAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1089
1090 VkSubpassDescription subpassDesc = {};
1091 subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1092 subpassDesc.colorAttachmentCount = 1;
1093 subpassDesc.pColorAttachments = &colorAttachmentRef;
1094 subpassDesc.pDepthStencilAttachment = &depthStencilAttachmentRef;
1095
Adam Sawickie6e498f2017-06-16 17:21:31 +02001096 VkRenderPassCreateInfo renderPassInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO };
1097 renderPassInfo.attachmentCount = (uint32_t)_countof(attachments);
1098 renderPassInfo.pAttachments = attachments;
1099 renderPassInfo.subpassCount = 1;
1100 renderPassInfo.pSubpasses = &subpassDesc;
Adam Sawicki14137d12017-10-16 18:06:05 +02001101 renderPassInfo.dependencyCount = 0;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001102 ERR_GUARD_VULKAN( vkCreateRenderPass(g_hDevice, &renderPassInfo, g_Allocs, &g_hRenderPass) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001103 }
1104
1105 // Create pipeline
1106 {
1107 std::vector<char> vertShaderCode;
1108 LoadShader(vertShaderCode, "Shader.vert.spv");
1109 VkShaderModuleCreateInfo shaderModuleInfo = { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO };
1110 shaderModuleInfo.codeSize = vertShaderCode.size();
1111 shaderModuleInfo.pCode = (const uint32_t*)vertShaderCode.data();
1112 VkShaderModule hVertShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001113 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &hVertShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001114
1115 std::vector<char> hFragShaderCode;
1116 LoadShader(hFragShaderCode, "Shader.frag.spv");
1117 shaderModuleInfo.codeSize = hFragShaderCode.size();
1118 shaderModuleInfo.pCode = (const uint32_t*)hFragShaderCode.data();
1119 VkShaderModule fragShaderModule = VK_NULL_HANDLE;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001120 ERR_GUARD_VULKAN( vkCreateShaderModule(g_hDevice, &shaderModuleInfo, g_Allocs, &fragShaderModule) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001121
1122 VkPipelineShaderStageCreateInfo vertPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
1123 vertPipelineShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
1124 vertPipelineShaderStageInfo.module = hVertShaderModule;
1125 vertPipelineShaderStageInfo.pName = "main";
1126
1127 VkPipelineShaderStageCreateInfo fragPipelineShaderStageInfo = { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO };
1128 fragPipelineShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1129 fragPipelineShaderStageInfo.module = fragShaderModule;
1130 fragPipelineShaderStageInfo.pName = "main";
1131
1132 VkPipelineShaderStageCreateInfo pipelineShaderStageInfos[] = {
1133 vertPipelineShaderStageInfo,
1134 fragPipelineShaderStageInfo
1135 };
1136
1137 VkVertexInputBindingDescription bindingDescription = {};
1138 bindingDescription.binding = 0;
1139 bindingDescription.stride = sizeof(Vertex);
1140 bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1141
1142 VkVertexInputAttributeDescription attributeDescriptions[3];
1143 ZeroMemory(attributeDescriptions, sizeof(attributeDescriptions));
1144
1145 attributeDescriptions[0].binding = 0;
1146 attributeDescriptions[0].location = 0;
1147 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1148 attributeDescriptions[0].offset = offsetof(Vertex, pos);
1149
1150 attributeDescriptions[1].binding = 0;
1151 attributeDescriptions[1].location = 1;
1152 attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
1153 attributeDescriptions[1].offset = offsetof(Vertex, color);
1154
1155 attributeDescriptions[2].binding = 0;
1156 attributeDescriptions[2].location = 2;
1157 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1158 attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
1159
1160 VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
1161 pipelineVertexInputStateInfo.vertexBindingDescriptionCount = 1;
1162 pipelineVertexInputStateInfo.pVertexBindingDescriptions = &bindingDescription;
1163 pipelineVertexInputStateInfo.vertexAttributeDescriptionCount = _countof(attributeDescriptions);
1164 pipelineVertexInputStateInfo.pVertexAttributeDescriptions = attributeDescriptions;
1165
1166 VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
1167 pipelineInputAssemblyStateInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
1168 pipelineInputAssemblyStateInfo.primitiveRestartEnable = VK_TRUE;
1169
1170 VkViewport viewport = {};
1171 viewport.x = 0.f;
1172 viewport.y = 0.f;
1173 viewport.width = (float)g_Extent.width;
1174 viewport.height = (float)g_Extent.height;
1175 viewport.minDepth = 0.f;
1176 viewport.maxDepth = 1.f;
1177
1178 VkRect2D scissor = {};
1179 scissor.offset.x = 0;
1180 scissor.offset.y = 0;
1181 scissor.extent = g_Extent;
1182
1183 VkPipelineViewportStateCreateInfo pipelineViewportStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO };
1184 pipelineViewportStateInfo.viewportCount = 1;
1185 pipelineViewportStateInfo.pViewports = &viewport;
1186 pipelineViewportStateInfo.scissorCount = 1;
1187 pipelineViewportStateInfo.pScissors = &scissor;
1188
1189 VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
1190 pipelineRasterizationStateInfo.depthClampEnable = VK_FALSE;
1191 pipelineRasterizationStateInfo.rasterizerDiscardEnable = VK_FALSE;
1192 pipelineRasterizationStateInfo.polygonMode = VK_POLYGON_MODE_FILL;
1193 pipelineRasterizationStateInfo.lineWidth = 1.f;
1194 pipelineRasterizationStateInfo.cullMode = VK_CULL_MODE_BACK_BIT;
1195 pipelineRasterizationStateInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
1196 pipelineRasterizationStateInfo.depthBiasEnable = VK_FALSE;
1197 pipelineRasterizationStateInfo.depthBiasConstantFactor = 0.f;
1198 pipelineRasterizationStateInfo.depthBiasClamp = 0.f;
1199 pipelineRasterizationStateInfo.depthBiasSlopeFactor = 0.f;
1200
1201 VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
1202 pipelineMultisampleStateInfo.sampleShadingEnable = VK_FALSE;
1203 pipelineMultisampleStateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
1204 pipelineMultisampleStateInfo.minSampleShading = 1.f;
1205 pipelineMultisampleStateInfo.pSampleMask = nullptr;
1206 pipelineMultisampleStateInfo.alphaToCoverageEnable = VK_FALSE;
1207 pipelineMultisampleStateInfo.alphaToOneEnable = VK_FALSE;
1208
1209 VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
1210 pipelineColorBlendAttachmentState.colorWriteMask =
1211 VK_COLOR_COMPONENT_R_BIT |
1212 VK_COLOR_COMPONENT_G_BIT |
1213 VK_COLOR_COMPONENT_B_BIT |
1214 VK_COLOR_COMPONENT_A_BIT;
1215 pipelineColorBlendAttachmentState.blendEnable = VK_FALSE;
1216 pipelineColorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
1217 pipelineColorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
1218 pipelineColorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; // Optional
1219 pipelineColorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; // Optional
1220 pipelineColorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; // Optional
1221 pipelineColorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; // Optional
1222
1223 VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO };
1224 pipelineColorBlendStateInfo.logicOpEnable = VK_FALSE;
1225 pipelineColorBlendStateInfo.logicOp = VK_LOGIC_OP_COPY;
1226 pipelineColorBlendStateInfo.attachmentCount = 1;
1227 pipelineColorBlendStateInfo.pAttachments = &pipelineColorBlendAttachmentState;
1228
1229 VkPipelineDepthStencilStateCreateInfo depthStencilStateInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
1230 depthStencilStateInfo.depthTestEnable = VK_TRUE;
1231 depthStencilStateInfo.depthWriteEnable = VK_TRUE;
1232 depthStencilStateInfo.depthCompareOp = VK_COMPARE_OP_LESS;
1233 depthStencilStateInfo.depthBoundsTestEnable = VK_FALSE;
1234 depthStencilStateInfo.stencilTestEnable = VK_FALSE;
1235
1236 VkGraphicsPipelineCreateInfo pipelineInfo = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO };
1237 pipelineInfo.stageCount = 2;
1238 pipelineInfo.pStages = pipelineShaderStageInfos;
1239 pipelineInfo.pVertexInputState = &pipelineVertexInputStateInfo;
1240 pipelineInfo.pInputAssemblyState = &pipelineInputAssemblyStateInfo;
1241 pipelineInfo.pViewportState = &pipelineViewportStateInfo;
1242 pipelineInfo.pRasterizationState = &pipelineRasterizationStateInfo;
1243 pipelineInfo.pMultisampleState = &pipelineMultisampleStateInfo;
1244 pipelineInfo.pDepthStencilState = &depthStencilStateInfo;
1245 pipelineInfo.pColorBlendState = &pipelineColorBlendStateInfo;
1246 pipelineInfo.pDynamicState = nullptr;
1247 pipelineInfo.layout = g_hPipelineLayout;
1248 pipelineInfo.renderPass = g_hRenderPass;
1249 pipelineInfo.subpass = 0;
1250 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
1251 pipelineInfo.basePipelineIndex = -1;
1252 ERR_GUARD_VULKAN( vkCreateGraphicsPipelines(
1253 g_hDevice,
1254 VK_NULL_HANDLE,
1255 1,
Adam Sawicki1f84f622019-07-02 13:40:01 +02001256 &pipelineInfo,
1257 g_Allocs,
Adam Sawickie6e498f2017-06-16 17:21:31 +02001258 &g_hPipeline) );
1259
Adam Sawicki1f84f622019-07-02 13:40:01 +02001260 vkDestroyShaderModule(g_hDevice, fragShaderModule, g_Allocs);
1261 vkDestroyShaderModule(g_hDevice, hVertShaderModule, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001262 }
1263
1264 // Create frambuffers
1265
1266 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001267 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001268 g_Framebuffers.clear();
1269
1270 g_Framebuffers.resize(g_SwapchainImageViews.size());
1271 for(size_t i = 0; i < g_SwapchainImages.size(); ++i)
1272 {
1273 VkImageView attachments[] = { g_SwapchainImageViews[i], g_hDepthImageView };
1274
1275 VkFramebufferCreateInfo framebufferInfo = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO };
1276 framebufferInfo.renderPass = g_hRenderPass;
1277 framebufferInfo.attachmentCount = (uint32_t)_countof(attachments);
1278 framebufferInfo.pAttachments = attachments;
1279 framebufferInfo.width = g_Extent.width;
1280 framebufferInfo.height = g_Extent.height;
1281 framebufferInfo.layers = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001282 ERR_GUARD_VULKAN( vkCreateFramebuffer(g_hDevice, &framebufferInfo, g_Allocs, &g_Framebuffers[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001283 }
1284
1285 // Create semaphores
1286
1287 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1288 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001289 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001290 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1291 }
1292 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1293 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001294 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001295 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1296 }
1297
1298 VkSemaphoreCreateInfo semaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO };
Adam Sawicki1f84f622019-07-02 13:40:01 +02001299 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hImageAvailableSemaphore) );
1300 ERR_GUARD_VULKAN( vkCreateSemaphore(g_hDevice, &semaphoreInfo, g_Allocs, &g_hRenderFinishedSemaphore) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02001301}
1302
1303static void DestroySwapchain(bool destroyActualSwapchain)
1304{
1305 if(g_hImageAvailableSemaphore != VK_NULL_HANDLE)
1306 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001307 vkDestroySemaphore(g_hDevice, g_hImageAvailableSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001308 g_hImageAvailableSemaphore = VK_NULL_HANDLE;
1309 }
1310 if(g_hRenderFinishedSemaphore != VK_NULL_HANDLE)
1311 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001312 vkDestroySemaphore(g_hDevice, g_hRenderFinishedSemaphore, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001313 g_hRenderFinishedSemaphore = VK_NULL_HANDLE;
1314 }
1315
1316 for(size_t i = g_Framebuffers.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001317 vkDestroyFramebuffer(g_hDevice, g_Framebuffers[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001318 g_Framebuffers.clear();
1319
1320 if(g_hDepthImageView != VK_NULL_HANDLE)
1321 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001322 vkDestroyImageView(g_hDevice, g_hDepthImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001323 g_hDepthImageView = VK_NULL_HANDLE;
1324 }
1325 if(g_hDepthImage != VK_NULL_HANDLE)
1326 {
Adam Sawicki819860e2017-07-04 14:30:38 +02001327 vmaDestroyImage(g_hAllocator, g_hDepthImage, g_hDepthImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001328 g_hDepthImage = VK_NULL_HANDLE;
1329 }
1330
1331 if(g_hPipeline != VK_NULL_HANDLE)
1332 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001333 vkDestroyPipeline(g_hDevice, g_hPipeline, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001334 g_hPipeline = VK_NULL_HANDLE;
1335 }
1336
1337 if(g_hRenderPass != VK_NULL_HANDLE)
1338 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001339 vkDestroyRenderPass(g_hDevice, g_hRenderPass, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001340 g_hRenderPass = VK_NULL_HANDLE;
1341 }
1342
1343 if(g_hPipelineLayout != VK_NULL_HANDLE)
1344 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001345 vkDestroyPipelineLayout(g_hDevice, g_hPipelineLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001346 g_hPipelineLayout = VK_NULL_HANDLE;
1347 }
1348
1349 for(size_t i = g_SwapchainImageViews.size(); i--; )
Adam Sawicki1f84f622019-07-02 13:40:01 +02001350 vkDestroyImageView(g_hDevice, g_SwapchainImageViews[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001351 g_SwapchainImageViews.clear();
1352
1353 if(destroyActualSwapchain && (g_hSwapchain != VK_NULL_HANDLE))
1354 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02001355 vkDestroySwapchainKHR(g_hDevice, g_hSwapchain, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001356 g_hSwapchain = VK_NULL_HANDLE;
1357 }
1358}
1359
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001360static void PrintEnabledFeatures()
1361{
Adam Sawickiafd50562021-02-26 11:59:58 +01001362 wprintf(L"Enabled extensions and features:\n");
Adam Sawickie8a85442020-03-06 14:48:30 +01001363 wprintf(L"Validation layer: %d\n", g_EnableValidationLayer ? 1 : 0);
1364 wprintf(L"Sparse binding: %d\n", g_SparseBindingEnabled ? 1 : 0);
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001365 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1366 {
Adam Sawickie8a85442020-03-06 14:48:30 +01001367 wprintf(L"VK_KHR_get_memory_requirements2: %d\n", VK_KHR_get_memory_requirements2_enabled ? 1 : 0);
1368 wprintf(L"VK_KHR_get_physical_device_properties2: %d\n", VK_KHR_get_physical_device_properties2_enabled ? 1 : 0);
1369 wprintf(L"VK_KHR_dedicated_allocation: %d\n", VK_KHR_dedicated_allocation_enabled ? 1 : 0);
1370 wprintf(L"VK_KHR_bind_memory2: %d\n", VK_KHR_bind_memory2_enabled ? 1 : 0);
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001371 }
Adam Sawickie8a85442020-03-06 14:48:30 +01001372 wprintf(L"VK_EXT_memory_budget: %d\n", VK_EXT_memory_budget_enabled ? 1 : 0);
1373 wprintf(L"VK_AMD_device_coherent_memory: %d\n", VK_AMD_device_coherent_memory_enabled ? 1 : 0);
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001374 if(GetVulkanApiVersion() < VK_API_VERSION_1_2)
1375 {
1376 wprintf(L"VK_KHR_buffer_device_address: %d\n", VK_KHR_buffer_device_address_enabled ? 1 : 0);
1377 }
1378 else
1379 {
1380 wprintf(L"bufferDeviceAddress: %d\n", VK_KHR_buffer_device_address_enabled ? 1 : 0);
1381 }
Adam Sawickif2012052021-01-11 18:04:42 +01001382 wprintf(L"VK_EXT_memory_priority: %d\n", VK_EXT_memory_priority ? 1 : 0);
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001383}
1384
Adam Sawicki50882502020-02-07 16:51:31 +01001385void SetAllocatorCreateInfo(VmaAllocatorCreateInfo& outInfo)
1386{
1387 outInfo = {};
1388
1389 outInfo.physicalDevice = g_hPhysicalDevice;
1390 outInfo.device = g_hDevice;
1391 outInfo.instance = g_hVulkanInstance;
1392 outInfo.vulkanApiVersion = GetVulkanApiVersion();
1393
1394 if(VK_KHR_dedicated_allocation_enabled)
1395 {
1396 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_DEDICATED_ALLOCATION_BIT;
1397 }
1398 if(VK_KHR_bind_memory2_enabled)
1399 {
1400 outInfo.flags |= VMA_ALLOCATOR_CREATE_KHR_BIND_MEMORY2_BIT;
1401 }
1402#if !defined(VMA_MEMORY_BUDGET) || VMA_MEMORY_BUDGET == 1
Adam Sawicki6a93b8a2020-03-09 16:58:18 +01001403 if(VK_EXT_memory_budget_enabled && (
1404 GetVulkanApiVersion() >= VK_API_VERSION_1_1 || VK_KHR_get_physical_device_properties2_enabled))
Adam Sawicki50882502020-02-07 16:51:31 +01001405 {
1406 outInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
1407 }
1408#endif
1409 if(VK_AMD_device_coherent_memory_enabled)
1410 {
1411 outInfo.flags |= VMA_ALLOCATOR_CREATE_AMD_DEVICE_COHERENT_MEMORY_BIT;
1412 }
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001413 if(VK_KHR_buffer_device_address_enabled)
Adam Sawickie73e9882020-03-20 18:05:42 +01001414 {
1415 outInfo.flags |= VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
1416 }
Adam Sawickif2012052021-01-11 18:04:42 +01001417#if !defined(VMA_MEMORY_PRIORITY) || VMA_MEMORY_PRIORITY == 1
1418 if(VK_EXT_memory_priority_enabled)
1419 {
1420 outInfo.flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_PRIORITY_BIT;
1421 }
1422#endif
Adam Sawicki50882502020-02-07 16:51:31 +01001423
1424 if(USE_CUSTOM_CPU_ALLOCATION_CALLBACKS)
1425 {
1426 outInfo.pAllocationCallbacks = &g_CpuAllocationCallbacks;
1427 }
1428
1429 // Uncomment to enable recording to CSV file.
1430 /*
1431 static VmaRecordSettings recordSettings = {};
1432 recordSettings.pFilePath = "VulkanSample.csv";
1433 outInfo.pRecordSettings = &recordSettings;
1434 */
1435
1436 // Uncomment to enable HeapSizeLimit.
1437 /*
1438 static std::array<VkDeviceSize, VK_MAX_MEMORY_HEAPS> heapSizeLimit;
1439 std::fill(heapSizeLimit.begin(), heapSizeLimit.end(), VK_WHOLE_SIZE);
1440 heapSizeLimit[0] = 512ull * 1024 * 1024;
1441 outInfo.pHeapSizeLimit = heapSizeLimit.data();
1442 */
1443}
1444
Adam Sawickie8a85442020-03-06 14:48:30 +01001445static void PrintPhysicalDeviceProperties(const VkPhysicalDeviceProperties& properties)
1446{
Adam Sawickiafd50562021-02-26 11:59:58 +01001447 wprintf(L"physicalDeviceProperties:\n");
1448 wprintf(L" driverVersion: 0x%X\n", properties.driverVersion);
1449 wprintf(L" vendorID: 0x%X (%s)\n", properties.vendorID, VendorIDToStr(properties.vendorID));
1450 wprintf(L" deviceID: 0x%X\n", properties.deviceID);
1451 wprintf(L" deviceType: %u (%s)\n", properties.deviceType, PhysicalDeviceTypeToStr(properties.deviceType));
1452 wprintf(L" deviceName: %hs\n", properties.deviceName);
1453 wprintf(L" limits:\n");
1454 wprintf(L" maxMemoryAllocationCount: %u\n", properties.limits.maxMemoryAllocationCount);
1455 wprintf(L" bufferImageGranularity: %llu B\n", properties.limits.bufferImageGranularity);
1456 wprintf(L" nonCoherentAtomSize: %llu B\n", properties.limits.nonCoherentAtomSize);
1457}
1458
1459#if VMA_VULKAN_VERSION >= 1002000
1460static void PrintPhysicalDeviceVulkan11Properties(const VkPhysicalDeviceVulkan11Properties& properties)
1461{
1462 wprintf(L"physicalDeviceVulkan11Properties:\n");
1463 std::wstring sizeStr = SizeToStr(properties.maxMemoryAllocationSize);
1464 wprintf(L" maxMemoryAllocationSize: %llu B (%s)\n", properties.maxMemoryAllocationSize, sizeStr.c_str());
1465}
1466static void PrintPhysicalDeviceVulkan12Properties(const VkPhysicalDeviceVulkan12Properties& properties)
1467{
1468 wprintf(L"physicalDeviceVulkan12Properties:\n");
1469 std::wstring str = DriverIDToStr(properties.driverID);
1470 wprintf(L" driverID: %u (%s)\n", properties.driverID, str.c_str());
1471 wprintf(L" driverName: %hs\n", properties.driverName);
1472 wprintf(L" driverInfo: %hs\n", properties.driverInfo);
1473}
1474#endif // #if VMA_VULKAN_VERSION > 1002000
1475
1476static void AddFlagToStr(std::wstring& inout, const wchar_t* flagStr)
1477{
1478 if(!inout.empty())
1479 inout += L", ";
1480 inout += flagStr;
1481}
1482
1483static std::wstring HeapFlagsToStr(VkMemoryHeapFlags flags)
1484{
1485 std::wstring result;
1486 if(flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)
1487 AddFlagToStr(result, L"DEVICE_LOCAL");
1488 if(flags & VK_MEMORY_HEAP_MULTI_INSTANCE_BIT)
1489 AddFlagToStr(result, L"MULTI_INSTANCE");
1490 return result;
1491}
1492
1493static std::wstring PropertyFlagsToStr(VkMemoryPropertyFlags flags)
1494{
1495 std::wstring result;
1496 if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
1497 AddFlagToStr(result, L"DEVICE_LOCAL");
1498 if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
1499 AddFlagToStr(result, L"HOST_VISIBLE");
1500 if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
1501 AddFlagToStr(result, L"HOST_COHERENT");
1502 if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
1503 AddFlagToStr(result, L"HOST_CACHED");
1504 if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
1505 AddFlagToStr(result, L"LAZILY_ALLOCATED");
1506
1507#if VMA_VULKAN_VERSION >= 1001000
1508 if(flags & VK_MEMORY_PROPERTY_PROTECTED_BIT)
1509 AddFlagToStr(result, L"PROTECTED");
1510#endif
1511
1512#if VK_AMD_device_coherent_memory
1513 if(flags & VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD)
1514 AddFlagToStr(result, L"DEVICE_COHERENT (AMD)");
1515 if(flags & VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD)
1516 AddFlagToStr(result, L"DEVICE_UNCACHED (AMD)");
1517#endif
1518
1519 return result;
1520}
1521
1522static void PrintMemoryTypes()
1523{
1524 wprintf(L"MEMORY HEAPS:\n");
1525 const VkPhysicalDeviceMemoryProperties* memProps = nullptr;
1526 vmaGetMemoryProperties(g_hAllocator, &memProps);
1527
1528 wprintf(L"heapCount=%u, typeCount=%u\n", memProps->memoryHeapCount, memProps->memoryTypeCount);
1529
1530 std::wstring sizeStr, flagsStr;
1531 for(uint32_t heapIndex = 0; heapIndex < memProps->memoryHeapCount; ++heapIndex)
1532 {
1533 const VkMemoryHeap& heap = memProps->memoryHeaps[heapIndex];
1534 sizeStr = SizeToStr(heap.size);
1535 flagsStr = HeapFlagsToStr(heap.flags);
1536 wprintf(L"Heap %u: %llu B (%s) %s\n", heapIndex, heap.size, sizeStr.c_str(), flagsStr.c_str());
1537
1538 for(uint32_t typeIndex = 0; typeIndex < memProps->memoryTypeCount; ++typeIndex)
1539 {
1540 const VkMemoryType& type = memProps->memoryTypes[typeIndex];
1541 if(type.heapIndex == heapIndex)
1542 {
1543 flagsStr = PropertyFlagsToStr(type.propertyFlags);
1544 wprintf(L" Type %u: %s\n", typeIndex, flagsStr.c_str());
1545 }
1546 }
1547 }
1548}
1549
1550#if 0
1551template<typename It, typename MapFunc>
1552inline VkDeviceSize MapSum(It beg, It end, MapFunc mapFunc)
1553{
1554 VkDeviceSize result = 0;
1555 for(It it = beg; it != end; ++it)
1556 result += mapFunc(*it);
1557 return result;
1558}
1559#endif
1560
1561static bool CanCreateVertexBuffer(uint32_t allowedMemoryTypeBits)
1562{
1563 VkBufferCreateInfo bufCreateInfo = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO };
1564 bufCreateInfo.size = 0x10000;
1565 bufCreateInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
1566
1567 VkBuffer buf = VK_NULL_HANDLE;
1568 VkResult res = vkCreateBuffer(g_hDevice, &bufCreateInfo, g_Allocs, &buf);
1569 assert(res == VK_SUCCESS);
1570
1571 VkMemoryRequirements memReq = {};
1572 vkGetBufferMemoryRequirements(g_hDevice, buf, &memReq);
1573
1574 vkDestroyBuffer(g_hDevice, buf, g_Allocs);
1575
1576 return (memReq.memoryTypeBits & allowedMemoryTypeBits) != 0;
1577}
1578
1579static bool CanCreateOptimalSampledImage(uint32_t allowedMemoryTypeBits)
1580{
1581 VkImageCreateInfo imgCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
1582 imgCreateInfo.imageType = VK_IMAGE_TYPE_2D;
1583 imgCreateInfo.extent.width = 256;
1584 imgCreateInfo.extent.height = 256;
1585 imgCreateInfo.extent.depth = 1;
1586 imgCreateInfo.mipLevels = 1;
1587 imgCreateInfo.arrayLayers = 1;
1588 imgCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM;
1589 imgCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
1590 imgCreateInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
1591 imgCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
1592 imgCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
1593
1594 VkImage img = VK_NULL_HANDLE;
1595 VkResult res = vkCreateImage(g_hDevice, &imgCreateInfo, g_Allocs, &img);
1596 assert(res == VK_SUCCESS);
1597
1598 VkMemoryRequirements memReq = {};
1599 vkGetImageMemoryRequirements(g_hDevice, img, &memReq);
1600
1601 vkDestroyImage(g_hDevice, img, g_Allocs);
1602
1603 return (memReq.memoryTypeBits & allowedMemoryTypeBits) != 0;
1604}
1605
1606static void PrintMemoryConclusions()
1607{
1608 wprintf(L"Conclusions:\n");
1609
1610 const VkPhysicalDeviceProperties* props = nullptr;
1611 const VkPhysicalDeviceMemoryProperties* memProps = nullptr;
1612 vmaGetPhysicalDeviceProperties(g_hAllocator, &props);
1613 vmaGetMemoryProperties(g_hAllocator, &memProps);
1614
1615 const uint32_t heapCount = memProps->memoryHeapCount;
1616
1617 uint32_t deviceLocalHeapCount = 0;
1618 uint32_t hostVisibleHeapCount = 0;
1619 uint32_t deviceLocalAndHostVisibleHeapCount = 0;
1620 VkDeviceSize deviceLocalHeapSumSize = 0;
1621 VkDeviceSize hostVisibleHeapSumSize = 0;
1622 VkDeviceSize deviceLocalAndHostVisibleHeapSumSize = 0;
1623
1624 for(uint32_t heapIndex = 0; heapIndex < heapCount; ++heapIndex)
1625 {
1626 const VkMemoryHeap& heap = memProps->memoryHeaps[heapIndex];
1627 const bool isDeviceLocal = (heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0;
1628 bool isHostVisible = false;
1629 for(uint32_t typeIndex = 0; typeIndex < memProps->memoryTypeCount; ++typeIndex)
1630 {
1631 const VkMemoryType& type = memProps->memoryTypes[typeIndex];
1632 if(type.heapIndex == heapIndex && (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT))
1633 {
1634 isHostVisible = true;
1635 break;
1636 }
1637 }
1638 if(isDeviceLocal)
1639 {
1640 ++deviceLocalHeapCount;
1641 deviceLocalHeapSumSize += heap.size;
1642 }
1643 if(isHostVisible)
1644 {
1645 ++hostVisibleHeapCount;
1646 hostVisibleHeapSumSize += heap.size;
1647 if(isDeviceLocal)
1648 {
1649 ++deviceLocalAndHostVisibleHeapCount;
1650 deviceLocalAndHostVisibleHeapSumSize += heap.size;
1651 }
1652 }
1653 }
1654
1655 uint32_t hostVisibleNotHostCoherentTypeCount = 0;
1656 uint32_t notDeviceLocalNotHostVisibleTypeCount = 0;
1657 uint32_t amdSpecificTypeCount = 0;
1658 uint32_t lazilyAllocatedTypeCount = 0;
1659 uint32_t allTypeBits = 0;
1660 uint32_t deviceLocalTypeBits = 0;
1661 for(uint32_t typeIndex = 0; typeIndex < memProps->memoryTypeCount; ++typeIndex)
1662 {
1663 const VkMemoryType& type = memProps->memoryTypes[typeIndex];
1664 allTypeBits |= 1u << typeIndex;
1665 if(type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
1666 {
1667 deviceLocalTypeBits |= 1u << typeIndex;
1668 }
1669 if((type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
1670 (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0)
1671 {
1672 ++hostVisibleNotHostCoherentTypeCount;
1673 }
1674 if((type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0 &&
1675 (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0)
1676 {
1677 ++notDeviceLocalNotHostVisibleTypeCount;
1678 }
1679 if(type.propertyFlags & (VK_MEMORY_PROPERTY_DEVICE_COHERENT_BIT_AMD | VK_MEMORY_PROPERTY_DEVICE_UNCACHED_BIT_AMD))
1680 {
1681 ++amdSpecificTypeCount;
1682 }
1683 if(type.propertyFlags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
1684 {
1685 ++lazilyAllocatedTypeCount;
1686 }
1687 }
1688
1689 assert(deviceLocalHeapCount > 0);
1690 if(deviceLocalHeapCount == heapCount)
1691 wprintf(L"- All heaps are DEVICE_LOCAL.\n");
1692 else
1693 wprintf(L"- %u heaps are DEVICE_LOCAL, total %s.\n", deviceLocalHeapCount, SizeToStr(deviceLocalHeapSumSize).c_str());
1694
1695 assert(hostVisibleHeapCount > 0);
1696 if(hostVisibleHeapCount == heapCount)
1697 wprintf(L"- All heaps are HOST_VISIBLE.\n");
1698 else
1699 wprintf(L"- %u heaps are HOST_VISIBLE, total %s.\n", deviceLocalHeapCount, SizeToStr(hostVisibleHeapSumSize).c_str());
1700
1701 if(deviceLocalHeapCount < heapCount && hostVisibleHeapCount < heapCount)
1702 {
1703 if(deviceLocalAndHostVisibleHeapCount == 0)
1704 wprintf(L"- No heaps are DEVICE_LOCAL and HOST_VISIBLE.\n");
1705 if(deviceLocalAndHostVisibleHeapCount == heapCount)
1706 wprintf(L"- All heaps are DEVICE_LOCAL and HOST_VISIBLE.\n");
1707 else
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001708 wprintf(L"- %u heaps are DEVICE_LOCAL and HOST_VISIBLE, total %s.\n", deviceLocalAndHostVisibleHeapCount, SizeToStr(deviceLocalAndHostVisibleHeapSumSize).c_str());
Adam Sawickiafd50562021-02-26 11:59:58 +01001709 }
1710
1711 if(hostVisibleNotHostCoherentTypeCount == 0)
1712 wprintf(L"- No types are HOST_VISIBLE but not HOST_COHERENT.\n");
1713 else
1714 wprintf(L"- %u types are HOST_VISIBLE but not HOST_COHERENT.\n", hostVisibleNotHostCoherentTypeCount);
1715
1716 if(notDeviceLocalNotHostVisibleTypeCount == 0)
1717 wprintf(L"- No types are not DEVICE_LOCAL and not HOST_VISIBLE.\n");
1718 else
1719 wprintf(L"- %u types are not DEVICE_LOCAL and not HOST_VISIBLE.\n", notDeviceLocalNotHostVisibleTypeCount);
1720
1721 if(amdSpecificTypeCount == 0)
1722 wprintf(L"- No types are AMD-specific DEVICE_COHERENT or DEVICE_UNCACHED.\n");
1723 else
1724 wprintf(L"- %u types are AMD-specific DEVICE_COHERENT or DEVICE_UNCACHED.\n", amdSpecificTypeCount);
1725
1726 if(lazilyAllocatedTypeCount == 0)
1727 wprintf(L"- No types are LAZILY_ALLOCATED.\n");
1728 else
1729 wprintf(L"- %u types are LAZILY_ALLOCATED.\n", lazilyAllocatedTypeCount);
1730
1731 if(props->vendorID == VENDOR_ID_AMD &&
1732 props->deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU &&
1733 deviceLocalAndHostVisibleHeapSumSize > 256llu * 1024 * 1024)
1734 {
1735 wprintf(L"- AMD Smart Access Memory (SAM) is enabled!\n");
1736 }
1737
1738 if(deviceLocalHeapCount < heapCount)
1739 {
1740 const uint32_t nonDeviceLocalTypeBits = ~deviceLocalTypeBits & allTypeBits;
1741
1742 if(CanCreateVertexBuffer(nonDeviceLocalTypeBits))
1743 wprintf(L"- A buffer with VERTEX_BUFFER usage can be created in some non-DEVICE_LOCAL type.\n");
1744 else
1745 wprintf(L"- A buffer with VERTEX_BUFFER usage cannot be created in some non-DEVICE_LOCAL type.\n");
1746
1747 if(CanCreateOptimalSampledImage(nonDeviceLocalTypeBits))
1748 wprintf(L"- An image with OPTIMAL tiling and SAMPLED usage can be created in some non-DEVICE_LOCAL type.\n");
1749 else
1750 wprintf(L"- An image with OPTIMAL tiling and SAMPLED usage cannot be created in some non-DEVICE_LOCAL type.\n");
1751 }
1752
1753 //wprintf(L"\n");
Adam Sawickie8a85442020-03-06 14:48:30 +01001754}
1755
Adam Sawickie6e498f2017-06-16 17:21:31 +02001756static void InitializeApplication()
1757{
Adam Sawickie6e498f2017-06-16 17:21:31 +02001758 // Create VkSurfaceKHR.
1759 VkWin32SurfaceCreateInfoKHR surfaceInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR };
1760 surfaceInfo.hinstance = g_hAppInstance;
1761 surfaceInfo.hwnd = g_hWnd;
Adam Sawicki1f84f622019-07-02 13:40:01 +02001762 VkResult result = vkCreateWin32SurfaceKHR(g_hVulkanInstance, &surfaceInfo, g_Allocs, &g_hSurface);
Adam Sawickie6e498f2017-06-16 17:21:31 +02001763 assert(result == VK_SUCCESS);
1764
Adam Sawickie73e9882020-03-20 18:05:42 +01001765 // Query for device extensions
Adam Sawicki50882502020-02-07 16:51:31 +01001766
1767 uint32_t physicalDeviceExtensionPropertyCount = 0;
1768 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(g_hPhysicalDevice, nullptr, &physicalDeviceExtensionPropertyCount, nullptr) );
1769 std::vector<VkExtensionProperties> physicalDeviceExtensionProperties{physicalDeviceExtensionPropertyCount};
1770 if(physicalDeviceExtensionPropertyCount)
1771 {
1772 ERR_GUARD_VULKAN( vkEnumerateDeviceExtensionProperties(
1773 g_hPhysicalDevice,
1774 nullptr,
1775 &physicalDeviceExtensionPropertyCount,
1776 physicalDeviceExtensionProperties.data()) );
1777 }
1778
1779 for(uint32_t i = 0; i < physicalDeviceExtensionPropertyCount; ++i)
1780 {
1781 if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001782 {
1783 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1784 {
1785 VK_KHR_get_memory_requirements2_enabled = true;
1786 }
1787 }
Adam Sawicki50882502020-02-07 16:51:31 +01001788 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001789 {
1790 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1791 {
1792 VK_KHR_dedicated_allocation_enabled = true;
1793 }
1794 }
Adam Sawicki50882502020-02-07 16:51:31 +01001795 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BIND_MEMORY_2_EXTENSION_NAME) == 0)
Adam Sawickia4f2eb92020-03-06 14:39:42 +01001796 {
1797 if(GetVulkanApiVersion() == VK_API_VERSION_1_0)
1798 {
1799 VK_KHR_bind_memory2_enabled = true;
1800 }
1801 }
Adam Sawicki50882502020-02-07 16:51:31 +01001802 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0)
1803 VK_EXT_memory_budget_enabled = true;
1804 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME) == 0)
1805 VK_AMD_device_coherent_memory_enabled = true;
Adam Sawickie73e9882020-03-20 18:05:42 +01001806 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0)
1807 {
1808 if(GetVulkanApiVersion() < VK_API_VERSION_1_2)
1809 {
1810 VK_KHR_buffer_device_address_enabled = true;
1811 }
1812 }
Adam Sawickif2012052021-01-11 18:04:42 +01001813 else if(strcmp(physicalDeviceExtensionProperties[i].extensionName, VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME) == 0)
1814 VK_EXT_memory_priority_enabled = true;
Adam Sawicki50882502020-02-07 16:51:31 +01001815 }
1816
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001817 if(GetVulkanApiVersion() >= VK_API_VERSION_1_2)
1818 VK_KHR_buffer_device_address_enabled = true; // Promoted to core Vulkan 1.2.
Adam Sawickie73e9882020-03-20 18:05:42 +01001819
Adam Sawickie6e498f2017-06-16 17:21:31 +02001820 // Query for features
1821
Adam Sawickiafd50562021-02-26 11:59:58 +01001822#if VMA_VULKAN_VERSION >= 1001000
1823 VkPhysicalDeviceProperties2 physicalDeviceProperties2 = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 };
1824
1825#if VMA_VULKAN_VERSION >= 1002000
1826 // Vulkan spec says structure VkPhysicalDeviceVulkan11Properties is "Provided by VK_VERSION_1_2" - is this a mistake? Assuming not...
1827 VkPhysicalDeviceVulkan11Properties physicalDeviceVulkan11Properties = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES };
1828 VkPhysicalDeviceVulkan12Properties physicalDeviceVulkan12Properties = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES };
1829 PnextChainPushFront(&physicalDeviceProperties2, &physicalDeviceVulkan11Properties);
1830 PnextChainPushFront(&physicalDeviceProperties2, &physicalDeviceVulkan12Properties);
1831#endif
1832
1833 vkGetPhysicalDeviceProperties2(g_hPhysicalDevice, &physicalDeviceProperties2);
1834
1835 PrintPhysicalDeviceProperties(physicalDeviceProperties2.properties);
1836#if VMA_VULKAN_VERSION >= 1002000
1837 PrintPhysicalDeviceVulkan11Properties(physicalDeviceVulkan11Properties);
1838 PrintPhysicalDeviceVulkan12Properties(physicalDeviceVulkan12Properties);
1839#endif
1840
1841#else // #if VMA_VULKAN_VERSION >= 1001000
Adam Sawickie6e498f2017-06-16 17:21:31 +02001842 VkPhysicalDeviceProperties physicalDeviceProperties = {};
1843 vkGetPhysicalDeviceProperties(g_hPhysicalDevice, &physicalDeviceProperties);
Adam Sawickie8a85442020-03-06 14:48:30 +01001844 PrintPhysicalDeviceProperties(physicalDeviceProperties);
1845
Adam Sawickiafd50562021-02-26 11:59:58 +01001846#endif // #if VMA_VULKAN_VERSION >= 1001000
1847
1848 wprintf(L"\n");
1849
Adam Sawicki50882502020-02-07 16:51:31 +01001850 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
Adam Sawickie73e9882020-03-20 18:05:42 +01001851
Adam Sawicki50882502020-02-07 16:51:31 +01001852 VkPhysicalDeviceCoherentMemoryFeaturesAMD physicalDeviceCoherentMemoryFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COHERENT_MEMORY_FEATURES_AMD };
1853 if(VK_AMD_device_coherent_memory_enabled)
1854 {
Adam Sawickie73e9882020-03-20 18:05:42 +01001855 PnextChainPushFront(&physicalDeviceFeatures, &physicalDeviceCoherentMemoryFeatures);
Adam Sawicki50882502020-02-07 16:51:31 +01001856 }
Adam Sawickie73e9882020-03-20 18:05:42 +01001857
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001858 VkPhysicalDeviceBufferDeviceAddressFeaturesKHR physicalDeviceBufferDeviceAddressFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR };
1859 if(VK_KHR_buffer_device_address_enabled)
Adam Sawickie73e9882020-03-20 18:05:42 +01001860 {
1861 PnextChainPushFront(&physicalDeviceFeatures, &physicalDeviceBufferDeviceAddressFeatures);
1862 }
1863
Adam Sawickif2012052021-01-11 18:04:42 +01001864 VkPhysicalDeviceMemoryPriorityFeaturesEXT physicalDeviceMemoryPriorityFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PRIORITY_FEATURES_EXT };
1865 if(VK_EXT_memory_priority_enabled)
1866 {
1867 PnextChainPushFront(&physicalDeviceFeatures, &physicalDeviceMemoryPriorityFeatures);
1868 }
1869
Adam Sawicki50882502020-02-07 16:51:31 +01001870 vkGetPhysicalDeviceFeatures2(g_hPhysicalDevice, &physicalDeviceFeatures);
Adam Sawicki51fa9662018-10-03 13:44:29 +02001871
Adam Sawicki50882502020-02-07 16:51:31 +01001872 g_SparseBindingEnabled = physicalDeviceFeatures.features.sparseBinding != 0;
1873
1874 // The extension is supported as fake with no real support for this feature? Don't use it.
1875 if(VK_AMD_device_coherent_memory_enabled && !physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory)
1876 VK_AMD_device_coherent_memory_enabled = false;
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001877 if(VK_KHR_buffer_device_address_enabled && !physicalDeviceBufferDeviceAddressFeatures.bufferDeviceAddress)
1878 VK_KHR_buffer_device_address_enabled = false;
Adam Sawickif2012052021-01-11 18:04:42 +01001879 if(VK_EXT_memory_priority_enabled && !physicalDeviceMemoryPriorityFeatures.memoryPriority)
1880 VK_EXT_memory_priority_enabled = false;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001881
1882 // Find queue family index
1883
1884 uint32_t queueFamilyCount = 0;
1885 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, nullptr);
1886 assert(queueFamilyCount > 0);
1887 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
1888 vkGetPhysicalDeviceQueueFamilyProperties(g_hPhysicalDevice, &queueFamilyCount, queueFamilies.data());
1889 for(uint32_t i = 0;
1890 (i < queueFamilyCount) &&
Adam Sawicki51fa9662018-10-03 13:44:29 +02001891 (g_GraphicsQueueFamilyIndex == UINT_MAX ||
1892 g_PresentQueueFamilyIndex == UINT_MAX ||
1893 (g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex == UINT_MAX));
Adam Sawickie6e498f2017-06-16 17:21:31 +02001894 ++i)
1895 {
1896 if(queueFamilies[i].queueCount > 0)
1897 {
Adam Sawickida6c1942018-12-05 17:34:34 +01001898 const uint32_t flagsForGraphicsQueue = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001899 if((g_GraphicsQueueFamilyIndex != 0) &&
Adam Sawickida6c1942018-12-05 17:34:34 +01001900 ((queueFamilies[i].queueFlags & flagsForGraphicsQueue) == flagsForGraphicsQueue))
Adam Sawickie6e498f2017-06-16 17:21:31 +02001901 {
1902 g_GraphicsQueueFamilyIndex = i;
1903 }
1904
1905 VkBool32 surfaceSupported = 0;
1906 VkResult res = vkGetPhysicalDeviceSurfaceSupportKHR(g_hPhysicalDevice, i, g_hSurface, &surfaceSupported);
1907 if((res >= 0) && (surfaceSupported == VK_TRUE))
1908 {
1909 g_PresentQueueFamilyIndex = i;
1910 }
Adam Sawicki51fa9662018-10-03 13:44:29 +02001911
1912 if(g_SparseBindingEnabled &&
1913 g_SparseBindingQueueFamilyIndex == UINT32_MAX &&
1914 (queueFamilies[i].queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) != 0)
1915 {
1916 g_SparseBindingQueueFamilyIndex = i;
1917 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001918 }
1919 }
1920 assert(g_GraphicsQueueFamilyIndex != UINT_MAX);
1921
Adam Sawicki51fa9662018-10-03 13:44:29 +02001922 g_SparseBindingEnabled = g_SparseBindingEnabled && g_SparseBindingQueueFamilyIndex != UINT32_MAX;
1923
Adam Sawickie6e498f2017-06-16 17:21:31 +02001924 // Create logical device
1925
1926 const float queuePriority = 1.f;
1927
Adam Sawicki51fa9662018-10-03 13:44:29 +02001928 VkDeviceQueueCreateInfo queueCreateInfo[3] = {};
1929 uint32_t queueCount = 1;
1930 queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1931 queueCreateInfo[0].queueFamilyIndex = g_GraphicsQueueFamilyIndex;
1932 queueCreateInfo[0].queueCount = 1;
1933 queueCreateInfo[0].pQueuePriorities = &queuePriority;
1934
1935 if(g_PresentQueueFamilyIndex != g_GraphicsQueueFamilyIndex)
1936 {
1937
1938 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1939 queueCreateInfo[queueCount].queueFamilyIndex = g_PresentQueueFamilyIndex;
1940 queueCreateInfo[queueCount].queueCount = 1;
1941 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1942 ++queueCount;
1943 }
1944
1945 if(g_SparseBindingEnabled &&
1946 g_SparseBindingQueueFamilyIndex != g_GraphicsQueueFamilyIndex &&
1947 g_SparseBindingQueueFamilyIndex != g_PresentQueueFamilyIndex)
1948 {
1949
1950 queueCreateInfo[queueCount].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
1951 queueCreateInfo[queueCount].queueFamilyIndex = g_SparseBindingQueueFamilyIndex;
1952 queueCreateInfo[queueCount].queueCount = 1;
1953 queueCreateInfo[queueCount].pQueuePriorities = &queuePriority;
1954 ++queueCount;
1955 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001956
Adam Sawickie6e498f2017-06-16 17:21:31 +02001957 std::vector<const char*> enabledDeviceExtensions;
1958 enabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
Adam Sawicki50882502020-02-07 16:51:31 +01001959 if(VK_KHR_get_memory_requirements2_enabled)
1960 enabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME);
1961 if(VK_KHR_dedicated_allocation_enabled)
1962 enabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME);
1963 if(VK_KHR_bind_memory2_enabled)
1964 enabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME);
1965 if(VK_EXT_memory_budget_enabled)
1966 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
1967 if(VK_AMD_device_coherent_memory_enabled)
1968 enabledDeviceExtensions.push_back(VK_AMD_DEVICE_COHERENT_MEMORY_EXTENSION_NAME);
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001969 if(VK_KHR_buffer_device_address_enabled && GetVulkanApiVersion() < VK_API_VERSION_1_2)
Adam Sawickie73e9882020-03-20 18:05:42 +01001970 enabledDeviceExtensions.push_back(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME);
Adam Sawickif2012052021-01-11 18:04:42 +01001971 if(VK_EXT_memory_priority_enabled)
1972 enabledDeviceExtensions.push_back(VK_EXT_MEMORY_PRIORITY_EXTENSION_NAME);
Adam Sawicki50882502020-02-07 16:51:31 +01001973
1974 VkPhysicalDeviceFeatures2 deviceFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
1975 deviceFeatures.features.samplerAnisotropy = VK_TRUE;
1976 deviceFeatures.features.sparseBinding = g_SparseBindingEnabled ? VK_TRUE : VK_FALSE;
1977
1978 if(VK_AMD_device_coherent_memory_enabled)
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001979 {
Adam Sawicki50882502020-02-07 16:51:31 +01001980 physicalDeviceCoherentMemoryFeatures.deviceCoherentMemory = VK_TRUE;
Adam Sawickie73e9882020-03-20 18:05:42 +01001981 PnextChainPushBack(&deviceFeatures, &physicalDeviceCoherentMemoryFeatures);
1982 }
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001983 if(VK_KHR_buffer_device_address_enabled)
Adam Sawickie73e9882020-03-20 18:05:42 +01001984 {
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01001985 physicalDeviceBufferDeviceAddressFeatures = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BUFFER_DEVICE_ADDRESS_FEATURES_KHR };
Adam Sawickie73e9882020-03-20 18:05:42 +01001986 physicalDeviceBufferDeviceAddressFeatures.bufferDeviceAddress = VK_TRUE;
1987 PnextChainPushBack(&deviceFeatures, &physicalDeviceBufferDeviceAddressFeatures);
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001988 }
Adam Sawickif2012052021-01-11 18:04:42 +01001989 if(VK_EXT_memory_priority_enabled)
1990 {
1991 PnextChainPushBack(&deviceFeatures, &physicalDeviceMemoryPriorityFeatures);
1992 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02001993
1994 VkDeviceCreateInfo deviceCreateInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
Adam Sawicki50882502020-02-07 16:51:31 +01001995 deviceCreateInfo.pNext = &deviceFeatures;
Adam Sawickie6e498f2017-06-16 17:21:31 +02001996 deviceCreateInfo.enabledLayerCount = 0;
1997 deviceCreateInfo.ppEnabledLayerNames = nullptr;
1998 deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledDeviceExtensions.size();
Adam Sawicki6cc5e852018-03-13 16:37:54 +01001999 deviceCreateInfo.ppEnabledExtensionNames = !enabledDeviceExtensions.empty() ? enabledDeviceExtensions.data() : nullptr;
Adam Sawicki51fa9662018-10-03 13:44:29 +02002000 deviceCreateInfo.queueCreateInfoCount = queueCount;
2001 deviceCreateInfo.pQueueCreateInfos = queueCreateInfo;
Adam Sawickie6e498f2017-06-16 17:21:31 +02002002
Adam Sawicki1f84f622019-07-02 13:40:01 +02002003 ERR_GUARD_VULKAN( vkCreateDevice(g_hPhysicalDevice, &deviceCreateInfo, g_Allocs, &g_hDevice) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02002004
Adam Sawickie73e9882020-03-20 18:05:42 +01002005 // Fetch pointers to extension functions
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01002006 if(VK_KHR_buffer_device_address_enabled)
Adam Sawickie73e9882020-03-20 18:05:42 +01002007 {
2008 if(GetVulkanApiVersion() >= VK_API_VERSION_1_2)
2009 {
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01002010 g_vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressEXT)vkGetDeviceProcAddr(g_hDevice, "vkGetBufferDeviceAddress");
Adam Sawickie73e9882020-03-20 18:05:42 +01002011 }
2012 else if(VK_KHR_buffer_device_address_enabled)
2013 {
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01002014 g_vkGetBufferDeviceAddressKHR = (PFN_vkGetBufferDeviceAddressEXT)vkGetDeviceProcAddr(g_hDevice, "vkGetBufferDeviceAddressKHR");
Adam Sawickie73e9882020-03-20 18:05:42 +01002015 }
Adam Sawicki0a3c6b52021-03-02 16:48:32 +01002016 assert(g_vkGetBufferDeviceAddressKHR != nullptr);
Adam Sawickie73e9882020-03-20 18:05:42 +01002017 }
2018
Adam Sawickie6e498f2017-06-16 17:21:31 +02002019 // Create memory allocator
2020
2021 VmaAllocatorCreateInfo allocatorInfo = {};
Adam Sawicki50882502020-02-07 16:51:31 +01002022 SetAllocatorCreateInfo(allocatorInfo);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002023 ERR_GUARD_VULKAN( vmaCreateAllocator(&allocatorInfo, &g_hAllocator) );
2024
Adam Sawickiafd50562021-02-26 11:59:58 +01002025 PrintMemoryTypes();
2026 wprintf(L"\n");
2027 PrintMemoryConclusions();
2028 wprintf(L"\n");
Adam Sawickia4f2eb92020-03-06 14:39:42 +01002029 PrintEnabledFeatures();
Adam Sawickiafd50562021-02-26 11:59:58 +01002030 wprintf(L"\n");
Adam Sawickia4f2eb92020-03-06 14:39:42 +01002031
Adam Sawicki51fa9662018-10-03 13:44:29 +02002032 // Retrieve queues (don't need to be destroyed).
Adam Sawickie6e498f2017-06-16 17:21:31 +02002033
2034 vkGetDeviceQueue(g_hDevice, g_GraphicsQueueFamilyIndex, 0, &g_hGraphicsQueue);
2035 vkGetDeviceQueue(g_hDevice, g_PresentQueueFamilyIndex, 0, &g_hPresentQueue);
2036 assert(g_hGraphicsQueue);
2037 assert(g_hPresentQueue);
2038
Adam Sawicki51fa9662018-10-03 13:44:29 +02002039 if(g_SparseBindingEnabled)
2040 {
2041 vkGetDeviceQueue(g_hDevice, g_SparseBindingQueueFamilyIndex, 0, &g_hSparseBindingQueue);
2042 assert(g_hSparseBindingQueue);
2043 }
2044
Adam Sawickie6e498f2017-06-16 17:21:31 +02002045 // Create command pool
2046
2047 VkCommandPoolCreateInfo commandPoolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO };
2048 commandPoolInfo.queueFamilyIndex = g_GraphicsQueueFamilyIndex;
2049 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Adam Sawicki1f84f622019-07-02 13:40:01 +02002050 ERR_GUARD_VULKAN( vkCreateCommandPool(g_hDevice, &commandPoolInfo, g_Allocs, &g_hCommandPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02002051
2052 VkCommandBufferAllocateInfo commandBufferInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO };
2053 commandBufferInfo.commandPool = g_hCommandPool;
2054 commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
2055 commandBufferInfo.commandBufferCount = COMMAND_BUFFER_COUNT;
2056 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, g_MainCommandBuffers) );
2057
2058 VkFenceCreateInfo fenceInfo = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO };
2059 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
2060 for(size_t i = 0; i < COMMAND_BUFFER_COUNT; ++i)
2061 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002062 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_MainCommandBufferExecutedFances[i]) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02002063 }
2064
Adam Sawicki1f84f622019-07-02 13:40:01 +02002065 ERR_GUARD_VULKAN( vkCreateFence(g_hDevice, &fenceInfo, g_Allocs, &g_ImmediateFence) );
Adam Sawicki51fa9662018-10-03 13:44:29 +02002066
Adam Sawickie6e498f2017-06-16 17:21:31 +02002067 commandBufferInfo.commandBufferCount = 1;
2068 ERR_GUARD_VULKAN( vkAllocateCommandBuffers(g_hDevice, &commandBufferInfo, &g_hTemporaryCommandBuffer) );
2069
2070 // Create texture sampler
2071
2072 VkSamplerCreateInfo samplerInfo = { VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO };
2073 samplerInfo.magFilter = VK_FILTER_LINEAR;
2074 samplerInfo.minFilter = VK_FILTER_LINEAR;
2075 samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
2076 samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
2077 samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
2078 samplerInfo.anisotropyEnable = VK_TRUE;
2079 samplerInfo.maxAnisotropy = 16;
2080 samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
2081 samplerInfo.unnormalizedCoordinates = VK_FALSE;
2082 samplerInfo.compareEnable = VK_FALSE;
2083 samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
2084 samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
2085 samplerInfo.mipLodBias = 0.f;
2086 samplerInfo.minLod = 0.f;
2087 samplerInfo.maxLod = FLT_MAX;
Adam Sawicki1f84f622019-07-02 13:40:01 +02002088 ERR_GUARD_VULKAN( vkCreateSampler(g_hDevice, &samplerInfo, g_Allocs, &g_hSampler) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02002089
2090 CreateTexture(128, 128);
2091 CreateMesh();
2092
2093 VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
2094 samplerLayoutBinding.binding = 1;
2095 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
2096 samplerLayoutBinding.descriptorCount = 1;
2097 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
2098
2099 VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO };
2100 descriptorSetLayoutInfo.bindingCount = 1;
2101 descriptorSetLayoutInfo.pBindings = &samplerLayoutBinding;
Adam Sawicki1f84f622019-07-02 13:40:01 +02002102 ERR_GUARD_VULKAN( vkCreateDescriptorSetLayout(g_hDevice, &descriptorSetLayoutInfo, g_Allocs, &g_hDescriptorSetLayout) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02002103
2104 // Create descriptor pool
2105
2106 VkDescriptorPoolSize descriptorPoolSizes[2];
2107 ZeroMemory(descriptorPoolSizes, sizeof(descriptorPoolSizes));
2108 descriptorPoolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
2109 descriptorPoolSizes[0].descriptorCount = 1;
2110 descriptorPoolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
2111 descriptorPoolSizes[1].descriptorCount = 1;
2112
2113 VkDescriptorPoolCreateInfo descriptorPoolInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO };
2114 descriptorPoolInfo.poolSizeCount = (uint32_t)_countof(descriptorPoolSizes);
2115 descriptorPoolInfo.pPoolSizes = descriptorPoolSizes;
2116 descriptorPoolInfo.maxSets = 1;
Adam Sawicki1f84f622019-07-02 13:40:01 +02002117 ERR_GUARD_VULKAN( vkCreateDescriptorPool(g_hDevice, &descriptorPoolInfo, g_Allocs, &g_hDescriptorPool) );
Adam Sawickie6e498f2017-06-16 17:21:31 +02002118
2119 // Create descriptor set layout
2120
2121 VkDescriptorSetLayout descriptorSetLayouts[] = { g_hDescriptorSetLayout };
2122 VkDescriptorSetAllocateInfo descriptorSetInfo = { VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO };
2123 descriptorSetInfo.descriptorPool = g_hDescriptorPool;
2124 descriptorSetInfo.descriptorSetCount = 1;
2125 descriptorSetInfo.pSetLayouts = descriptorSetLayouts;
2126 ERR_GUARD_VULKAN( vkAllocateDescriptorSets(g_hDevice, &descriptorSetInfo, &g_hDescriptorSet) );
2127
2128 VkDescriptorImageInfo descriptorImageInfo = {};
2129 descriptorImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
2130 descriptorImageInfo.imageView = g_hTextureImageView;
2131 descriptorImageInfo.sampler = g_hSampler;
2132
2133 VkWriteDescriptorSet writeDescriptorSet = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET };
2134 writeDescriptorSet.dstSet = g_hDescriptorSet;
2135 writeDescriptorSet.dstBinding = 1;
2136 writeDescriptorSet.dstArrayElement = 0;
2137 writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
2138 writeDescriptorSet.descriptorCount = 1;
2139 writeDescriptorSet.pImageInfo = &descriptorImageInfo;
2140
2141 vkUpdateDescriptorSets(g_hDevice, 1, &writeDescriptorSet, 0, nullptr);
2142
2143 CreateSwapchain();
2144}
2145
2146static void FinalizeApplication()
2147{
2148 vkDeviceWaitIdle(g_hDevice);
2149
2150 DestroySwapchain(true);
2151
2152 if(g_hDescriptorPool != VK_NULL_HANDLE)
2153 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002154 vkDestroyDescriptorPool(g_hDevice, g_hDescriptorPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002155 g_hDescriptorPool = VK_NULL_HANDLE;
2156 }
2157
2158 if(g_hDescriptorSetLayout != VK_NULL_HANDLE)
2159 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002160 vkDestroyDescriptorSetLayout(g_hDevice, g_hDescriptorSetLayout, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002161 g_hDescriptorSetLayout = VK_NULL_HANDLE;
2162 }
2163
2164 if(g_hTextureImageView != VK_NULL_HANDLE)
2165 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002166 vkDestroyImageView(g_hDevice, g_hTextureImageView, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002167 g_hTextureImageView = VK_NULL_HANDLE;
2168 }
2169 if(g_hTextureImage != VK_NULL_HANDLE)
2170 {
Adam Sawicki819860e2017-07-04 14:30:38 +02002171 vmaDestroyImage(g_hAllocator, g_hTextureImage, g_hTextureImageAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002172 g_hTextureImage = VK_NULL_HANDLE;
2173 }
2174
2175 if(g_hIndexBuffer != VK_NULL_HANDLE)
2176 {
Adam Sawicki819860e2017-07-04 14:30:38 +02002177 vmaDestroyBuffer(g_hAllocator, g_hIndexBuffer, g_hIndexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002178 g_hIndexBuffer = VK_NULL_HANDLE;
2179 }
2180 if(g_hVertexBuffer != VK_NULL_HANDLE)
2181 {
Adam Sawicki819860e2017-07-04 14:30:38 +02002182 vmaDestroyBuffer(g_hAllocator, g_hVertexBuffer, g_hVertexBufferAlloc);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002183 g_hVertexBuffer = VK_NULL_HANDLE;
2184 }
2185
2186 if(g_hSampler != VK_NULL_HANDLE)
2187 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002188 vkDestroySampler(g_hDevice, g_hSampler, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002189 g_hSampler = VK_NULL_HANDLE;
2190 }
2191
Adam Sawicki51fa9662018-10-03 13:44:29 +02002192 if(g_ImmediateFence)
2193 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002194 vkDestroyFence(g_hDevice, g_ImmediateFence, g_Allocs);
Adam Sawicki51fa9662018-10-03 13:44:29 +02002195 g_ImmediateFence = VK_NULL_HANDLE;
2196 }
2197
Adam Sawickie6e498f2017-06-16 17:21:31 +02002198 for(size_t i = COMMAND_BUFFER_COUNT; i--; )
2199 {
2200 if(g_MainCommandBufferExecutedFances[i] != VK_NULL_HANDLE)
2201 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002202 vkDestroyFence(g_hDevice, g_MainCommandBufferExecutedFances[i], g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002203 g_MainCommandBufferExecutedFances[i] = VK_NULL_HANDLE;
2204 }
2205 }
2206 if(g_MainCommandBuffers[0] != VK_NULL_HANDLE)
2207 {
2208 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, COMMAND_BUFFER_COUNT, g_MainCommandBuffers);
2209 ZeroMemory(g_MainCommandBuffers, sizeof(g_MainCommandBuffers));
2210 }
2211 if(g_hTemporaryCommandBuffer != VK_NULL_HANDLE)
2212 {
2213 vkFreeCommandBuffers(g_hDevice, g_hCommandPool, 1, &g_hTemporaryCommandBuffer);
2214 g_hTemporaryCommandBuffer = VK_NULL_HANDLE;
2215 }
2216
2217 if(g_hCommandPool != VK_NULL_HANDLE)
2218 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002219 vkDestroyCommandPool(g_hDevice, g_hCommandPool, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002220 g_hCommandPool = VK_NULL_HANDLE;
2221 }
2222
2223 if(g_hAllocator != VK_NULL_HANDLE)
2224 {
2225 vmaDestroyAllocator(g_hAllocator);
2226 g_hAllocator = nullptr;
2227 }
2228
2229 if(g_hDevice != VK_NULL_HANDLE)
2230 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002231 vkDestroyDevice(g_hDevice, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002232 g_hDevice = nullptr;
2233 }
2234
Adam Sawickie6e498f2017-06-16 17:21:31 +02002235 if(g_hSurface != VK_NULL_HANDLE)
2236 {
Adam Sawicki1f84f622019-07-02 13:40:01 +02002237 vkDestroySurfaceKHR(g_hVulkanInstance, g_hSurface, g_Allocs);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002238 g_hSurface = VK_NULL_HANDLE;
2239 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02002240}
2241
2242static void PrintAllocatorStats()
2243{
2244#if VMA_STATS_STRING_ENABLED
2245 char* statsString = nullptr;
2246 vmaBuildStatsString(g_hAllocator, &statsString, true);
2247 printf("%s\n", statsString);
2248 vmaFreeStatsString(g_hAllocator, statsString);
2249#endif
2250}
2251
2252static void RecreateSwapChain()
2253{
2254 vkDeviceWaitIdle(g_hDevice);
2255 DestroySwapchain(false);
2256 CreateSwapchain();
2257}
2258
2259static void DrawFrame()
2260{
2261 // Begin main command buffer
2262 size_t cmdBufIndex = (g_NextCommandBufferIndex++) % COMMAND_BUFFER_COUNT;
2263 VkCommandBuffer hCommandBuffer = g_MainCommandBuffers[cmdBufIndex];
2264 VkFence hCommandBufferExecutedFence = g_MainCommandBufferExecutedFances[cmdBufIndex];
2265
2266 ERR_GUARD_VULKAN( vkWaitForFences(g_hDevice, 1, &hCommandBufferExecutedFence, VK_TRUE, UINT64_MAX) );
2267 ERR_GUARD_VULKAN( vkResetFences(g_hDevice, 1, &hCommandBufferExecutedFence) );
2268
2269 VkCommandBufferBeginInfo commandBufferBeginInfo = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO };
2270 commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
2271 ERR_GUARD_VULKAN( vkBeginCommandBuffer(hCommandBuffer, &commandBufferBeginInfo) );
2272
2273 // Acquire swapchain image
2274 uint32_t imageIndex = 0;
2275 VkResult res = vkAcquireNextImageKHR(g_hDevice, g_hSwapchain, UINT64_MAX, g_hImageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
2276 if(res == VK_ERROR_OUT_OF_DATE_KHR)
2277 {
2278 RecreateSwapChain();
2279 return;
2280 }
2281 else if(res < 0)
2282 {
2283 ERR_GUARD_VULKAN(res);
2284 }
2285
2286 // Record geometry pass
2287
2288 VkClearValue clearValues[2];
2289 ZeroMemory(clearValues, sizeof(clearValues));
2290 clearValues[0].color.float32[0] = 0.25f;
2291 clearValues[0].color.float32[1] = 0.25f;
2292 clearValues[0].color.float32[2] = 0.5f;
2293 clearValues[0].color.float32[3] = 1.0f;
2294 clearValues[1].depthStencil.depth = 1.0f;
2295
2296 VkRenderPassBeginInfo renderPassBeginInfo = { VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO };
2297 renderPassBeginInfo.renderPass = g_hRenderPass;
2298 renderPassBeginInfo.framebuffer = g_Framebuffers[imageIndex];
2299 renderPassBeginInfo.renderArea.offset.x = 0;
2300 renderPassBeginInfo.renderArea.offset.y = 0;
2301 renderPassBeginInfo.renderArea.extent = g_Extent;
2302 renderPassBeginInfo.clearValueCount = (uint32_t)_countof(clearValues);
2303 renderPassBeginInfo.pClearValues = clearValues;
2304 vkCmdBeginRenderPass(hCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
2305
2306 vkCmdBindPipeline(
2307 hCommandBuffer,
2308 VK_PIPELINE_BIND_POINT_GRAPHICS,
2309 g_hPipeline);
2310
Adam Sawicki82c3f332018-06-11 15:27:33 +02002311 mat4 view = mat4::LookAt(
2312 vec3(0.f, 0.f, 0.f),
2313 vec3(0.f, -2.f, 4.f),
2314 vec3(0.f, 1.f, 0.f));
2315 mat4 proj = mat4::Perspective(
Adam Sawickie6e498f2017-06-16 17:21:31 +02002316 1.0471975511966f, // 60 degrees
2317 (float)g_Extent.width / (float)g_Extent.height,
2318 0.1f,
Adam Sawicki82c3f332018-06-11 15:27:33 +02002319 1000.f);
2320 mat4 viewProj = view * proj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02002321
2322 vkCmdBindDescriptorSets(
2323 hCommandBuffer,
2324 VK_PIPELINE_BIND_POINT_GRAPHICS,
2325 g_hPipelineLayout,
2326 0,
2327 1,
2328 &g_hDescriptorSet,
2329 0,
2330 nullptr);
2331
Adam Sawicki82c3f332018-06-11 15:27:33 +02002332 float rotationAngle = (float)GetTickCount() * 0.001f * (float)PI * 0.2f;
2333 mat4 model = mat4::RotationY(rotationAngle);
Adam Sawickie6e498f2017-06-16 17:21:31 +02002334
2335 UniformBufferObject ubo = {};
Adam Sawicki82c3f332018-06-11 15:27:33 +02002336 ubo.ModelViewProj = model * viewProj;
Adam Sawickie6e498f2017-06-16 17:21:31 +02002337 vkCmdPushConstants(hCommandBuffer, g_hPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(UniformBufferObject), &ubo);
2338
2339 VkBuffer vertexBuffers[] = { g_hVertexBuffer };
2340 VkDeviceSize offsets[] = { 0 };
2341 vkCmdBindVertexBuffers(hCommandBuffer, 0, 1, vertexBuffers, offsets);
2342
2343 vkCmdBindIndexBuffer(hCommandBuffer, g_hIndexBuffer, 0, VK_INDEX_TYPE_UINT16);
2344
2345 vkCmdDrawIndexed(hCommandBuffer, g_IndexCount, 1, 0, 0, 0);
2346
2347 vkCmdEndRenderPass(hCommandBuffer);
2348
2349 vkEndCommandBuffer(hCommandBuffer);
2350
2351 // Submit command buffer
2352
2353 VkSemaphore submitWaitSemaphores[] = { g_hImageAvailableSemaphore };
2354 VkPipelineStageFlags submitWaitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
2355 VkSemaphore submitSignalSemaphores[] = { g_hRenderFinishedSemaphore };
2356 VkSubmitInfo submitInfo = { VK_STRUCTURE_TYPE_SUBMIT_INFO };
2357 submitInfo.waitSemaphoreCount = 1;
2358 submitInfo.pWaitSemaphores = submitWaitSemaphores;
2359 submitInfo.pWaitDstStageMask = submitWaitStages;
2360 submitInfo.commandBufferCount = 1;
2361 submitInfo.pCommandBuffers = &hCommandBuffer;
2362 submitInfo.signalSemaphoreCount = _countof(submitSignalSemaphores);
2363 submitInfo.pSignalSemaphores = submitSignalSemaphores;
2364 ERR_GUARD_VULKAN( vkQueueSubmit(g_hGraphicsQueue, 1, &submitInfo, hCommandBufferExecutedFence) );
2365
2366 VkSemaphore presentWaitSemaphores[] = { g_hRenderFinishedSemaphore };
2367
2368 VkSwapchainKHR swapchains[] = { g_hSwapchain };
2369 VkPresentInfoKHR presentInfo = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
2370 presentInfo.waitSemaphoreCount = _countof(presentWaitSemaphores);
2371 presentInfo.pWaitSemaphores = presentWaitSemaphores;
2372 presentInfo.swapchainCount = 1;
2373 presentInfo.pSwapchains = swapchains;
2374 presentInfo.pImageIndices = &imageIndex;
2375 presentInfo.pResults = nullptr;
2376 res = vkQueuePresentKHR(g_hPresentQueue, &presentInfo);
2377 if(res == VK_ERROR_OUT_OF_DATE_KHR)
2378 {
2379 RecreateSwapChain();
2380 }
2381 else
2382 ERR_GUARD_VULKAN(res);
2383}
2384
2385static void HandlePossibleSizeChange()
2386{
2387 RECT clientRect;
2388 GetClientRect(g_hWnd, &clientRect);
2389 LONG newSizeX = clientRect.right - clientRect.left;
2390 LONG newSizeY = clientRect.bottom - clientRect.top;
2391 if((newSizeX > 0) &&
2392 (newSizeY > 0) &&
2393 ((newSizeX != g_SizeX) || (newSizeY != g_SizeY)))
2394 {
2395 g_SizeX = newSizeX;
2396 g_SizeY = newSizeY;
2397
2398 RecreateSwapChain();
2399 }
2400}
2401
Adam Sawickia75a61b2021-03-11 15:15:38 +01002402#define CATCH_PRINT_ERROR(extraCatchCode) \
2403 catch(const std::exception& ex) \
2404 { \
2405 fwprintf(stderr, L"ERROR: %hs\n", ex.what()); \
2406 extraCatchCode \
2407 } \
2408 catch(...) \
2409 { \
2410 fwprintf(stderr, L"UNKNOWN ERROR.\n"); \
2411 extraCatchCode \
2412 }
2413
Adam Sawickie6e498f2017-06-16 17:21:31 +02002414static LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
2415{
2416 switch(msg)
2417 {
2418 case WM_CREATE:
2419 // This is intentionally assigned here because we are now inside CreateWindow, before it returns.
2420 g_hWnd = hWnd;
Adam Sawickia75a61b2021-03-11 15:15:38 +01002421 try
2422 {
2423 InitializeApplication();
2424 }
2425 CATCH_PRINT_ERROR(return -1;)
Adam Sawickiafd50562021-02-26 11:59:58 +01002426 //PrintAllocatorStats();
Adam Sawickie6e498f2017-06-16 17:21:31 +02002427 return 0;
2428
2429 case WM_DESTROY:
Adam Sawickia75a61b2021-03-11 15:15:38 +01002430 try
2431 {
2432 FinalizeApplication();
2433 }
2434 CATCH_PRINT_ERROR(;)
Adam Sawickie6e498f2017-06-16 17:21:31 +02002435 PostQuitMessage(0);
2436 return 0;
2437
2438 // This prevents app from freezing when left Alt is pressed
2439 // (which normally enters modal menu loop).
2440 case WM_SYSKEYDOWN:
2441 case WM_SYSKEYUP:
2442 return 0;
2443
2444 case WM_SIZE:
2445 if((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED))
Adam Sawickia75a61b2021-03-11 15:15:38 +01002446 {
2447 try
2448 {
2449 HandlePossibleSizeChange();
2450 }
2451 CATCH_PRINT_ERROR(DestroyWindow(hWnd);)
2452 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02002453 return 0;
2454
2455 case WM_EXITSIZEMOVE:
Adam Sawickia75a61b2021-03-11 15:15:38 +01002456 try
2457 {
2458 HandlePossibleSizeChange();
2459 }
2460 CATCH_PRINT_ERROR(DestroyWindow(hWnd);)
Adam Sawickie6e498f2017-06-16 17:21:31 +02002461 return 0;
2462
2463 case WM_KEYDOWN:
Adam Sawickib8333fb2018-03-13 16:15:53 +01002464 switch(wParam)
2465 {
2466 case VK_ESCAPE:
Adam Sawickie6e498f2017-06-16 17:21:31 +02002467 PostMessage(hWnd, WM_CLOSE, 0, 0);
Adam Sawickib8333fb2018-03-13 16:15:53 +01002468 break;
2469 case 'T':
Adam Sawickia7d77692018-10-03 16:15:27 +02002470 try
2471 {
2472 Test();
2473 }
Adam Sawickia75a61b2021-03-11 15:15:38 +01002474 CATCH_PRINT_ERROR(;)
Adam Sawickib8333fb2018-03-13 16:15:53 +01002475 break;
Adam Sawickida6c1942018-12-05 17:34:34 +01002476 case 'S':
2477 try
2478 {
2479 if(g_SparseBindingEnabled)
2480 {
Adam Sawickia75a61b2021-03-11 15:15:38 +01002481 try
2482 {
2483 TestSparseBinding();
2484 }
2485 CATCH_PRINT_ERROR(;)
Adam Sawickida6c1942018-12-05 17:34:34 +01002486 }
2487 else
2488 {
2489 printf("Sparse binding not supported.\n");
2490 }
2491 }
2492 catch(const std::exception& ex)
2493 {
2494 printf("ERROR: %s\n", ex.what());
2495 }
2496 break;
Adam Sawickib8333fb2018-03-13 16:15:53 +01002497 }
Adam Sawickie6e498f2017-06-16 17:21:31 +02002498 return 0;
2499
2500 default:
2501 break;
2502 }
2503
2504 return DefWindowProc(hWnd, msg, wParam, lParam);
2505}
2506
Adam Sawickia75a61b2021-03-11 15:15:38 +01002507static void PrintLogo()
Adam Sawickie6e498f2017-06-16 17:21:31 +02002508{
Adam Sawickia75a61b2021-03-11 15:15:38 +01002509 wprintf(L"%s\n", APP_TITLE_W);
2510}
Adam Sawickie6e498f2017-06-16 17:21:31 +02002511
Adam Sawickia75a61b2021-03-11 15:15:38 +01002512static void PrintHelp()
2513{
2514 wprintf(
2515 L"Command line syntax:\n"
2516 L"-h, --Help Print this information\n"
2517 L"-l, --List Print list of GPUs\n"
2518 L"-g S, --GPU S Select GPU with name containing S\n"
2519 L"-i N, --GPUIndex N Select GPU index N\n"
2520 );
2521}
2522
2523int MainWindow()
2524{
Adam Sawickie6e498f2017-06-16 17:21:31 +02002525 WNDCLASSEX wndClassDesc = { sizeof(WNDCLASSEX) };
2526 wndClassDesc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS;
2527 wndClassDesc.hbrBackground = NULL;
2528 wndClassDesc.hCursor = LoadCursor(NULL, IDC_CROSS);
2529 wndClassDesc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
2530 wndClassDesc.hInstance = g_hAppInstance;
2531 wndClassDesc.lpfnWndProc = WndProc;
2532 wndClassDesc.lpszClassName = WINDOW_CLASS_NAME;
2533
2534 const ATOM hWndClass = RegisterClassEx(&wndClassDesc);
2535 assert(hWndClass);
2536
2537 const DWORD style = WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
2538 const DWORD exStyle = 0;
2539
2540 RECT rect = { 0, 0, g_SizeX, g_SizeY };
2541 AdjustWindowRectEx(&rect, style, FALSE, exStyle);
2542
Adam Sawicki86ccd632017-07-04 14:57:53 +02002543 CreateWindowEx(
Adam Sawickie6e498f2017-06-16 17:21:31 +02002544 exStyle, WINDOW_CLASS_NAME, APP_TITLE_W, style,
2545 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
2546 NULL, NULL, g_hAppInstance, NULL);
2547
2548 MSG msg;
2549 for(;;)
2550 {
2551 if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
2552 {
2553 if(msg.message == WM_QUIT)
2554 break;
2555 TranslateMessage(&msg);
2556 DispatchMessage(&msg);
2557 }
2558 if(g_hDevice != VK_NULL_HANDLE)
2559 DrawFrame();
2560 }
2561
Adam Sawickia75a61b2021-03-11 15:15:38 +01002562 return (int)msg.wParam;;
Adam Sawickie6e498f2017-06-16 17:21:31 +02002563}
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02002564
Adam Sawickia75a61b2021-03-11 15:15:38 +01002565int Main2(int argc, wchar_t** argv)
2566{
2567 PrintLogo();
2568
2569 if(!g_CommandLineParameters.Parse(argc, argv))
2570 {
2571 wprintf(L"ERROR: Invalid command line syntax.\n");
2572 PrintHelp();
2573 return (int)ExitCode::CommandLineError;
2574 }
2575
2576 if(g_CommandLineParameters.m_Help)
2577 {
2578 PrintHelp();
2579 return (int)ExitCode::Help;
2580 }
2581
2582 VulkanUsage vulkanUsage;
2583 vulkanUsage.Init();
2584
2585 if(g_CommandLineParameters.m_List)
2586 {
2587 vulkanUsage.PrintPhysicalDeviceList();
2588 return (int)ExitCode::GPUList;
2589 }
2590
2591 g_hPhysicalDevice = vulkanUsage.SelectPhysicalDevice(g_CommandLineParameters.m_GPUSelection);
2592 TEST(g_hPhysicalDevice);
2593
2594 return MainWindow();
2595}
2596
2597int wmain(int argc, wchar_t** argv)
2598{
2599 try
2600 {
2601 return Main2(argc, argv);
2602 TEST(g_CpuAllocCount.load() == 0);
2603 }
2604 CATCH_PRINT_ERROR(return (int)ExitCode::RuntimeError;)
2605}
2606
Adam Sawickif1a793c2018-03-13 15:42:22 +01002607#else // #ifdef _WIN32
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02002608
Adam Sawickif1a793c2018-03-13 15:42:22 +01002609#include "VmaUsage.h"
Adam Sawicki59a3e7e2017-08-21 15:47:30 +02002610
2611int main()
2612{
2613}
2614
Adam Sawickif1a793c2018-03-13 15:42:22 +01002615#endif // #ifdef _WIN32