12f18b292ff155af7df35930474857b507dbf18feTony Barbour/* 22f18b292ff155af7df35930474857b507dbf18feTony Barbour * Copyright (C) 2016 Google, Inc. 32f18b292ff155af7df35930474857b507dbf18feTony Barbour * 42f18b292ff155af7df35930474857b507dbf18feTony Barbour * Permission is hereby granted, free of charge, to any person obtaining a 52f18b292ff155af7df35930474857b507dbf18feTony Barbour * copy of this software and associated documentation files (the "Software"), 62f18b292ff155af7df35930474857b507dbf18feTony Barbour * to deal in the Software without restriction, including without limitation 72f18b292ff155af7df35930474857b507dbf18feTony Barbour * the rights to use, copy, modify, merge, publish, distribute, sublicense, 82f18b292ff155af7df35930474857b507dbf18feTony Barbour * and/or sell copies of the Software, and to permit persons to whom the 92f18b292ff155af7df35930474857b507dbf18feTony Barbour * Software is furnished to do so, subject to the following conditions: 102f18b292ff155af7df35930474857b507dbf18feTony Barbour * 112f18b292ff155af7df35930474857b507dbf18feTony Barbour * The above copyright notice and this permission notice shall be included 122f18b292ff155af7df35930474857b507dbf18feTony Barbour * in all copies or substantial portions of the Software. 132f18b292ff155af7df35930474857b507dbf18feTony Barbour * 142f18b292ff155af7df35930474857b507dbf18feTony Barbour * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 152f18b292ff155af7df35930474857b507dbf18feTony Barbour * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 162f18b292ff155af7df35930474857b507dbf18feTony Barbour * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 172f18b292ff155af7df35930474857b507dbf18feTony Barbour * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 182f18b292ff155af7df35930474857b507dbf18feTony Barbour * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 192f18b292ff155af7df35930474857b507dbf18feTony Barbour * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 202f18b292ff155af7df35930474857b507dbf18feTony Barbour * DEALINGS IN THE SOFTWARE. 212f18b292ff155af7df35930474857b507dbf18feTony Barbour */ 222f18b292ff155af7df35930474857b507dbf18feTony Barbour 232f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <cassert> 242f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <array> 252f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <iostream> 262f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <string> 272f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <sstream> 282f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <set> 292f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Helpers.h" 302f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Shell.h" 312f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Game.h" 322f18b292ff155af7df35930474857b507dbf18feTony Barbour 332f18b292ff155af7df35930474857b507dbf18feTony BarbourShell::Shell(Game &game) 342f18b292ff155af7df35930474857b507dbf18feTony Barbour : game_(game), settings_(game.settings()), ctx_(), 352f18b292ff155af7df35930474857b507dbf18feTony Barbour game_tick_(1.0f / settings_.ticks_per_second), game_time_(game_tick_) 362f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 372f18b292ff155af7df35930474857b507dbf18feTony Barbour // require generic WSI extensions 382f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_extensions_.push_back(VK_KHR_SURFACE_EXTENSION_NAME); 392f18b292ff155af7df35930474857b507dbf18feTony Barbour device_extensions_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 402f18b292ff155af7df35930474857b507dbf18feTony Barbour 412f18b292ff155af7df35930474857b507dbf18feTony Barbour // require "standard" validation layers 422f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.validate) { 432f18b292ff155af7df35930474857b507dbf18feTony Barbour device_layers_.push_back("VK_LAYER_LUNARG_standard_validation"); 442f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_layers_.push_back("VK_LAYER_LUNARG_standard_validation"); 452f18b292ff155af7df35930474857b507dbf18feTony Barbour 462f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_extensions_.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); 472f18b292ff155af7df35930474857b507dbf18feTony Barbour } 482f18b292ff155af7df35930474857b507dbf18feTony Barbour} 492f18b292ff155af7df35930474857b507dbf18feTony Barbour 502f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::log(LogPriority priority, const char *msg) 512f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 522f18b292ff155af7df35930474857b507dbf18feTony Barbour std::ostream &st = (priority >= LOG_ERR) ? std::cerr : std::cout; 532f18b292ff155af7df35930474857b507dbf18feTony Barbour st << msg << "\n"; 542f18b292ff155af7df35930474857b507dbf18feTony Barbour} 552f18b292ff155af7df35930474857b507dbf18feTony Barbour 562f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::init_vk() 572f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 582f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::init_dispatch_table_top(load_vk()); 592f18b292ff155af7df35930474857b507dbf18feTony Barbour 602f18b292ff155af7df35930474857b507dbf18feTony Barbour init_instance(); 612f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::init_dispatch_table_middle(ctx_.instance, false); 622f18b292ff155af7df35930474857b507dbf18feTony Barbour 632f18b292ff155af7df35930474857b507dbf18feTony Barbour init_debug_report(); 642f18b292ff155af7df35930474857b507dbf18feTony Barbour init_physical_dev(); 652f18b292ff155af7df35930474857b507dbf18feTony Barbour} 662f18b292ff155af7df35930474857b507dbf18feTony Barbour 672f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::cleanup_vk() 682f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 692f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.validate) 702f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroyDebugReportCallbackEXT(ctx_.instance, ctx_.debug_report, nullptr); 712f18b292ff155af7df35930474857b507dbf18feTony Barbour 722f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroyInstance(ctx_.instance, nullptr); 732f18b292ff155af7df35930474857b507dbf18feTony Barbour} 742f18b292ff155af7df35930474857b507dbf18feTony Barbour 752f18b292ff155af7df35930474857b507dbf18feTony Barbourbool Shell::debug_report_callback(VkDebugReportFlagsEXT flags, 762f18b292ff155af7df35930474857b507dbf18feTony Barbour VkDebugReportObjectTypeEXT obj_type, 772f18b292ff155af7df35930474857b507dbf18feTony Barbour uint64_t object, 782f18b292ff155af7df35930474857b507dbf18feTony Barbour size_t location, 792f18b292ff155af7df35930474857b507dbf18feTony Barbour int32_t msg_code, 802f18b292ff155af7df35930474857b507dbf18feTony Barbour const char *layer_prefix, 812f18b292ff155af7df35930474857b507dbf18feTony Barbour const char *msg) 822f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 832f18b292ff155af7df35930474857b507dbf18feTony Barbour LogPriority prio = LOG_WARN; 842f18b292ff155af7df35930474857b507dbf18feTony Barbour if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) 852f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_ERR; 862f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) 872f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_WARN; 882f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) 892f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_INFO; 902f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) 912f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_DEBUG; 922f18b292ff155af7df35930474857b507dbf18feTony Barbour 932f18b292ff155af7df35930474857b507dbf18feTony Barbour std::stringstream ss; 942f18b292ff155af7df35930474857b507dbf18feTony Barbour ss << layer_prefix << ": " << msg; 952f18b292ff155af7df35930474857b507dbf18feTony Barbour 962f18b292ff155af7df35930474857b507dbf18feTony Barbour log(prio, ss.str().c_str()); 972f18b292ff155af7df35930474857b507dbf18feTony Barbour 982f18b292ff155af7df35930474857b507dbf18feTony Barbour return false; 992f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1002f18b292ff155af7df35930474857b507dbf18feTony Barbour 1012f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::assert_all_instance_layers() const 1022f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 1032f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate instance layer 1042f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkLayerProperties> layers; 1052f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::enumerate(layers); 1062f18b292ff155af7df35930474857b507dbf18feTony Barbour 1072f18b292ff155af7df35930474857b507dbf18feTony Barbour std::set<std::string> layer_names; 1082f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &layer : layers) 1092f18b292ff155af7df35930474857b507dbf18feTony Barbour layer_names.insert(layer.layerName); 1102f18b292ff155af7df35930474857b507dbf18feTony Barbour 1112f18b292ff155af7df35930474857b507dbf18feTony Barbour // all listed instance layers are required 1122f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &name : instance_layers_) { 1132f18b292ff155af7df35930474857b507dbf18feTony Barbour if (layer_names.find(name) == layer_names.end()) { 1142f18b292ff155af7df35930474857b507dbf18feTony Barbour std::stringstream ss; 1152f18b292ff155af7df35930474857b507dbf18feTony Barbour ss << "instance layer " << name << " is missing"; 1162f18b292ff155af7df35930474857b507dbf18feTony Barbour throw std::runtime_error(ss.str()); 1172f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1182f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1192f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1202f18b292ff155af7df35930474857b507dbf18feTony Barbour 1212f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::assert_all_instance_extensions() const 1222f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 1232f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate instance extensions 1242f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkExtensionProperties> exts; 1252f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::enumerate(nullptr, exts); 1262f18b292ff155af7df35930474857b507dbf18feTony Barbour 1272f18b292ff155af7df35930474857b507dbf18feTony Barbour std::set<std::string> ext_names; 1282f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &ext : exts) 1292f18b292ff155af7df35930474857b507dbf18feTony Barbour ext_names.insert(ext.extensionName); 1302f18b292ff155af7df35930474857b507dbf18feTony Barbour 1312f18b292ff155af7df35930474857b507dbf18feTony Barbour // all listed instance extensions are required 1322f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &name : instance_extensions_) { 1332f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ext_names.find(name) == ext_names.end()) { 1342f18b292ff155af7df35930474857b507dbf18feTony Barbour std::stringstream ss; 1352f18b292ff155af7df35930474857b507dbf18feTony Barbour ss << "instance extension " << name << " is missing"; 1362f18b292ff155af7df35930474857b507dbf18feTony Barbour throw std::runtime_error(ss.str()); 1372f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1382f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1392f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1402f18b292ff155af7df35930474857b507dbf18feTony Barbour 1412f18b292ff155af7df35930474857b507dbf18feTony Barbourbool Shell::has_all_device_layers(VkPhysicalDevice phy) const 1422f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 1432f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate device layers 1442f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkLayerProperties> layers; 1452f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::enumerate(phy, layers); 1462f18b292ff155af7df35930474857b507dbf18feTony Barbour 1472f18b292ff155af7df35930474857b507dbf18feTony Barbour std::set<std::string> layer_names; 1482f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &layer : layers) 1492f18b292ff155af7df35930474857b507dbf18feTony Barbour layer_names.insert(layer.layerName); 1502f18b292ff155af7df35930474857b507dbf18feTony Barbour 1512f18b292ff155af7df35930474857b507dbf18feTony Barbour // all listed device layers are required 1522f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &name : device_layers_) { 1532f18b292ff155af7df35930474857b507dbf18feTony Barbour if (layer_names.find(name) == layer_names.end()) 1542f18b292ff155af7df35930474857b507dbf18feTony Barbour return false; 1552f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1562f18b292ff155af7df35930474857b507dbf18feTony Barbour 1572f18b292ff155af7df35930474857b507dbf18feTony Barbour return true; 1582f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1592f18b292ff155af7df35930474857b507dbf18feTony Barbour 1602f18b292ff155af7df35930474857b507dbf18feTony Barbourbool Shell::has_all_device_extensions(VkPhysicalDevice phy) const 1612f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 1622f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate device extensions 1632f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkExtensionProperties> exts; 1642f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::enumerate(phy, nullptr, exts); 1652f18b292ff155af7df35930474857b507dbf18feTony Barbour 1662f18b292ff155af7df35930474857b507dbf18feTony Barbour std::set<std::string> ext_names; 1672f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &ext : exts) 1682f18b292ff155af7df35930474857b507dbf18feTony Barbour ext_names.insert(ext.extensionName); 1692f18b292ff155af7df35930474857b507dbf18feTony Barbour 1702f18b292ff155af7df35930474857b507dbf18feTony Barbour // all listed device extensions are required 1712f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &name : device_extensions_) { 1722f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ext_names.find(name) == ext_names.end()) 1732f18b292ff155af7df35930474857b507dbf18feTony Barbour return false; 1742f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1752f18b292ff155af7df35930474857b507dbf18feTony Barbour 1762f18b292ff155af7df35930474857b507dbf18feTony Barbour return true; 1772f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1782f18b292ff155af7df35930474857b507dbf18feTony Barbour 1792f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::init_instance() 1802f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 1812f18b292ff155af7df35930474857b507dbf18feTony Barbour assert_all_instance_layers(); 1822f18b292ff155af7df35930474857b507dbf18feTony Barbour assert_all_instance_extensions(); 1832f18b292ff155af7df35930474857b507dbf18feTony Barbour 1842f18b292ff155af7df35930474857b507dbf18feTony Barbour VkApplicationInfo app_info = {}; 1852f18b292ff155af7df35930474857b507dbf18feTony Barbour app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 1862f18b292ff155af7df35930474857b507dbf18feTony Barbour app_info.pApplicationName = settings_.name.c_str(); 1872f18b292ff155af7df35930474857b507dbf18feTony Barbour app_info.applicationVersion = 0; 188d3995c987ba7e47700ceb54535880e782c6b04c1Jon Ashburn app_info.apiVersion = VK_API_VERSION_1_0; 1892f18b292ff155af7df35930474857b507dbf18feTony Barbour 1902f18b292ff155af7df35930474857b507dbf18feTony Barbour VkInstanceCreateInfo instance_info = {}; 1912f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 1922f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.pApplicationInfo = &app_info; 1932f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.enabledLayerCount = static_cast<uint32_t>(instance_layers_.size()); 1942f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.ppEnabledLayerNames = instance_layers_.data(); 1952f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.enabledExtensionCount = static_cast<uint32_t>(instance_extensions_.size()); 1962f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.ppEnabledExtensionNames = instance_extensions_.data(); 1972f18b292ff155af7df35930474857b507dbf18feTony Barbour 1982f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateInstance(&instance_info, nullptr, &ctx_.instance)); 1992f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2002f18b292ff155af7df35930474857b507dbf18feTony Barbour 2012f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::init_debug_report() 2022f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 2032f18b292ff155af7df35930474857b507dbf18feTony Barbour if (!settings_.validate) 2042f18b292ff155af7df35930474857b507dbf18feTony Barbour return; 2052f18b292ff155af7df35930474857b507dbf18feTony Barbour 2062f18b292ff155af7df35930474857b507dbf18feTony Barbour VkDebugReportCallbackCreateInfoEXT debug_report_info = {}; 2072f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 2082f18b292ff155af7df35930474857b507dbf18feTony Barbour 2092f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT | 2102f18b292ff155af7df35930474857b507dbf18feTony Barbour VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | 2112f18b292ff155af7df35930474857b507dbf18feTony Barbour VK_DEBUG_REPORT_ERROR_BIT_EXT; 2122f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.validate_verbose) { 2132f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT | 2142f18b292ff155af7df35930474857b507dbf18feTony Barbour VK_DEBUG_REPORT_DEBUG_BIT_EXT; 2152f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2162f18b292ff155af7df35930474857b507dbf18feTony Barbour 2172f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.pfnCallback = debug_report_callback; 2182f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.pUserData = reinterpret_cast<void *>(this); 2192f18b292ff155af7df35930474857b507dbf18feTony Barbour 2202f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateDebugReportCallbackEXT(ctx_.instance, 2212f18b292ff155af7df35930474857b507dbf18feTony Barbour &debug_report_info, nullptr, &ctx_.debug_report)); 2222f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2232f18b292ff155af7df35930474857b507dbf18feTony Barbour 2242f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::init_physical_dev() 2252f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 2262f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate physical devices 2272f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkPhysicalDevice> phys; 2282f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::enumerate(ctx_.instance, phys)); 2292f18b292ff155af7df35930474857b507dbf18feTony Barbour 2302f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.physical_dev = VK_NULL_HANDLE; 2312f18b292ff155af7df35930474857b507dbf18feTony Barbour for (auto phy : phys) { 2322f18b292ff155af7df35930474857b507dbf18feTony Barbour if (!has_all_device_layers(phy) || !has_all_device_extensions(phy)) 2332f18b292ff155af7df35930474857b507dbf18feTony Barbour continue; 2342f18b292ff155af7df35930474857b507dbf18feTony Barbour 2352f18b292ff155af7df35930474857b507dbf18feTony Barbour // get queue properties 2362f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkQueueFamilyProperties> queues; 2372f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::get(phy, queues); 2382f18b292ff155af7df35930474857b507dbf18feTony Barbour 2392f18b292ff155af7df35930474857b507dbf18feTony Barbour int game_queue_family = -1, present_queue_family = -1; 2402f18b292ff155af7df35930474857b507dbf18feTony Barbour for (uint32_t i = 0; i < queues.size(); i++) { 2412f18b292ff155af7df35930474857b507dbf18feTony Barbour const VkQueueFamilyProperties &q = queues[i]; 2422f18b292ff155af7df35930474857b507dbf18feTony Barbour 2432f18b292ff155af7df35930474857b507dbf18feTony Barbour // requires only GRAPHICS for game queues 2442f18b292ff155af7df35930474857b507dbf18feTony Barbour const VkFlags game_queue_flags = VK_QUEUE_GRAPHICS_BIT; 2452f18b292ff155af7df35930474857b507dbf18feTony Barbour if (game_queue_family < 0 && 2462f18b292ff155af7df35930474857b507dbf18feTony Barbour (q.queueFlags & game_queue_flags) == game_queue_flags) 2472f18b292ff155af7df35930474857b507dbf18feTony Barbour game_queue_family = i; 2482f18b292ff155af7df35930474857b507dbf18feTony Barbour 2492f18b292ff155af7df35930474857b507dbf18feTony Barbour // present queue must support the surface 2502f18b292ff155af7df35930474857b507dbf18feTony Barbour if (present_queue_family < 0 && can_present(phy, i)) 2512f18b292ff155af7df35930474857b507dbf18feTony Barbour present_queue_family = i; 2522f18b292ff155af7df35930474857b507dbf18feTony Barbour 2532f18b292ff155af7df35930474857b507dbf18feTony Barbour if (game_queue_family >= 0 && present_queue_family >= 0) 2542f18b292ff155af7df35930474857b507dbf18feTony Barbour break; 2552f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2562f18b292ff155af7df35930474857b507dbf18feTony Barbour 2572f18b292ff155af7df35930474857b507dbf18feTony Barbour if (game_queue_family >= 0 && present_queue_family >= 0) { 2582f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.physical_dev = phy; 2592f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.game_queue_family = game_queue_family; 2602f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.present_queue_family = present_queue_family; 2612f18b292ff155af7df35930474857b507dbf18feTony Barbour break; 2622f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2632f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2642f18b292ff155af7df35930474857b507dbf18feTony Barbour 2652f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.physical_dev == VK_NULL_HANDLE) 2662f18b292ff155af7df35930474857b507dbf18feTony Barbour throw std::runtime_error("failed to find any capable Vulkan physical device"); 2672f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2682f18b292ff155af7df35930474857b507dbf18feTony Barbour 2692f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::create_context() 2702f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 2712f18b292ff155af7df35930474857b507dbf18feTony Barbour create_dev(); 2722f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::init_dispatch_table_bottom(ctx_.instance, ctx_.dev); 2732f18b292ff155af7df35930474857b507dbf18feTony Barbour 2742f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::GetDeviceQueue(ctx_.dev, ctx_.game_queue_family, 0, &ctx_.game_queue); 2752f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::GetDeviceQueue(ctx_.dev, ctx_.present_queue_family, 0, &ctx_.present_queue); 2762f18b292ff155af7df35930474857b507dbf18feTony Barbour 2772f18b292ff155af7df35930474857b507dbf18feTony Barbour create_back_buffers(); 2782f18b292ff155af7df35930474857b507dbf18feTony Barbour 2792f18b292ff155af7df35930474857b507dbf18feTony Barbour // initialize ctx_.{surface,format} before attach_shell 2802f18b292ff155af7df35930474857b507dbf18feTony Barbour create_swapchain(); 2812f18b292ff155af7df35930474857b507dbf18feTony Barbour 2822f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.attach_shell(*this); 2832f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2842f18b292ff155af7df35930474857b507dbf18feTony Barbour 2852f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::destroy_context() 2862f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 2872f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.dev == VK_NULL_HANDLE) 2882f18b292ff155af7df35930474857b507dbf18feTony Barbour return; 2892f18b292ff155af7df35930474857b507dbf18feTony Barbour 2902f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DeviceWaitIdle(ctx_.dev); 2912f18b292ff155af7df35930474857b507dbf18feTony Barbour 2922f18b292ff155af7df35930474857b507dbf18feTony Barbour destroy_swapchain(); 2932f18b292ff155af7df35930474857b507dbf18feTony Barbour 2942f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.detach_shell(); 2952f18b292ff155af7df35930474857b507dbf18feTony Barbour 2962f18b292ff155af7df35930474857b507dbf18feTony Barbour destroy_back_buffers(); 2972f18b292ff155af7df35930474857b507dbf18feTony Barbour 2982f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.game_queue = VK_NULL_HANDLE; 2992f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.present_queue = VK_NULL_HANDLE; 3002f18b292ff155af7df35930474857b507dbf18feTony Barbour 3012f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroyDevice(ctx_.dev, nullptr); 3022f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.dev = VK_NULL_HANDLE; 3032f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3042f18b292ff155af7df35930474857b507dbf18feTony Barbour 3052f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::create_dev() 3062f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 3072f18b292ff155af7df35930474857b507dbf18feTony Barbour VkDeviceCreateInfo dev_info = {}; 3082f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 3092f18b292ff155af7df35930474857b507dbf18feTony Barbour 3102f18b292ff155af7df35930474857b507dbf18feTony Barbour const std::vector<float> queue_priorities(settings_.queue_count, 0.0f); 3112f18b292ff155af7df35930474857b507dbf18feTony Barbour std::array<VkDeviceQueueCreateInfo, 2> queue_info = {}; 3122f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 3132f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].queueFamilyIndex = ctx_.game_queue_family; 3142f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].queueCount = settings_.queue_count; 3152f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].pQueuePriorities = queue_priorities.data(); 3162f18b292ff155af7df35930474857b507dbf18feTony Barbour 3172f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.game_queue_family != ctx_.present_queue_family) { 3182f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 3192f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].queueFamilyIndex = ctx_.present_queue_family; 3202f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].queueCount = 1; 3212f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].pQueuePriorities = queue_priorities.data(); 3222f18b292ff155af7df35930474857b507dbf18feTony Barbour 3232f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.queueCreateInfoCount = 2; 3242f18b292ff155af7df35930474857b507dbf18feTony Barbour } else { 3252f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.queueCreateInfoCount = 1; 3262f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3272f18b292ff155af7df35930474857b507dbf18feTony Barbour 3282f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.pQueueCreateInfos = queue_info.data(); 3292f18b292ff155af7df35930474857b507dbf18feTony Barbour 3302f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.enabledLayerCount = static_cast<uint32_t>(device_layers_.size()); 3312f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.ppEnabledLayerNames = device_layers_.data(); 3322f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions_.size()); 3332f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.ppEnabledExtensionNames = device_extensions_.data(); 3342f18b292ff155af7df35930474857b507dbf18feTony Barbour 3352f18b292ff155af7df35930474857b507dbf18feTony Barbour // disable all features 3362f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPhysicalDeviceFeatures features = {}; 3372f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.pEnabledFeatures = &features; 3382f18b292ff155af7df35930474857b507dbf18feTony Barbour 3392f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateDevice(ctx_.physical_dev, &dev_info, nullptr, &ctx_.dev)); 3402f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3412f18b292ff155af7df35930474857b507dbf18feTony Barbour 3422f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::create_back_buffers() 3432f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 3442f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSemaphoreCreateInfo sem_info = {}; 3452f18b292ff155af7df35930474857b507dbf18feTony Barbour sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 3462f18b292ff155af7df35930474857b507dbf18feTony Barbour 3472f18b292ff155af7df35930474857b507dbf18feTony Barbour VkFenceCreateInfo fence_info = {}; 3482f18b292ff155af7df35930474857b507dbf18feTony Barbour fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 3492f18b292ff155af7df35930474857b507dbf18feTony Barbour fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; 3502f18b292ff155af7df35930474857b507dbf18feTony Barbour 3512f18b292ff155af7df35930474857b507dbf18feTony Barbour // BackBuffer is used to track which swapchain image and its associated 3522f18b292ff155af7df35930474857b507dbf18feTony Barbour // sync primitives are busy. Having more BackBuffer's than swapchain 3532f18b292ff155af7df35930474857b507dbf18feTony Barbour // images may allows us to replace CPU wait on present_fence by GPU wait 3542f18b292ff155af7df35930474857b507dbf18feTony Barbour // on acquire_semaphore. 3552f18b292ff155af7df35930474857b507dbf18feTony Barbour const int count = settings_.back_buffer_count + 1; 3562f18b292ff155af7df35930474857b507dbf18feTony Barbour for (int i = 0; i < count; i++) { 3572f18b292ff155af7df35930474857b507dbf18feTony Barbour BackBuffer buf = {}; 3582f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateSemaphore(ctx_.dev, &sem_info, nullptr, &buf.acquire_semaphore)); 3592f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateSemaphore(ctx_.dev, &sem_info, nullptr, &buf.render_semaphore)); 3602f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateFence(ctx_.dev, &fence_info, nullptr, &buf.present_fence)); 3612f18b292ff155af7df35930474857b507dbf18feTony Barbour 3622f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.push(buf); 3632f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3642f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3652f18b292ff155af7df35930474857b507dbf18feTony Barbour 3662f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::destroy_back_buffers() 3672f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 3682f18b292ff155af7df35930474857b507dbf18feTony Barbour while (!ctx_.back_buffers.empty()) { 3692f18b292ff155af7df35930474857b507dbf18feTony Barbour const auto &buf = ctx_.back_buffers.front(); 3702f18b292ff155af7df35930474857b507dbf18feTony Barbour 3712f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySemaphore(ctx_.dev, buf.acquire_semaphore, nullptr); 3722f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySemaphore(ctx_.dev, buf.render_semaphore, nullptr); 3732f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroyFence(ctx_.dev, buf.present_fence, nullptr); 3742f18b292ff155af7df35930474857b507dbf18feTony Barbour 3752f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.pop(); 3762f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3772f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3782f18b292ff155af7df35930474857b507dbf18feTony Barbour 3792f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::create_swapchain() 3802f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 3812f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.surface = create_surface(ctx_.instance); 3822f18b292ff155af7df35930474857b507dbf18feTony Barbour 3832f18b292ff155af7df35930474857b507dbf18feTony Barbour VkBool32 supported; 3842f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::GetPhysicalDeviceSurfaceSupportKHR(ctx_.physical_dev, 3852f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.present_queue_family, ctx_.surface, &supported)); 3862f18b292ff155af7df35930474857b507dbf18feTony Barbour // this should be guaranteed by the platform-specific can_present call 3872f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(supported); 3882f18b292ff155af7df35930474857b507dbf18feTony Barbour 3892f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkSurfaceFormatKHR> formats; 3902f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::get(ctx_.physical_dev, ctx_.surface, formats); 3912f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.format = formats[0]; 3922f18b292ff155af7df35930474857b507dbf18feTony Barbour 3932f18b292ff155af7df35930474857b507dbf18feTony Barbour // defer to resize_swapchain() 3942f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.swapchain = VK_NULL_HANDLE; 3952f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.extent.width = (uint32_t) -1; 3962f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.extent.height = (uint32_t) -1; 3972f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3982f18b292ff155af7df35930474857b507dbf18feTony Barbour 3992f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::destroy_swapchain() 4002f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 4012f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.swapchain != VK_NULL_HANDLE) { 4022f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.detach_swapchain(); 4032f18b292ff155af7df35930474857b507dbf18feTony Barbour 4042f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySwapchainKHR(ctx_.dev, ctx_.swapchain, nullptr); 4052f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.swapchain = VK_NULL_HANDLE; 4062f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4072f18b292ff155af7df35930474857b507dbf18feTony Barbour 4082f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySurfaceKHR(ctx_.instance, ctx_.surface, nullptr); 4092f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.surface = VK_NULL_HANDLE; 4102f18b292ff155af7df35930474857b507dbf18feTony Barbour} 4112f18b292ff155af7df35930474857b507dbf18feTony Barbour 4122f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::resize_swapchain(uint32_t width_hint, uint32_t height_hint) 4132f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 4142f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSurfaceCapabilitiesKHR caps; 4152f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(ctx_.physical_dev, 4162f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.surface, &caps)); 4172f18b292ff155af7df35930474857b507dbf18feTony Barbour 4182f18b292ff155af7df35930474857b507dbf18feTony Barbour VkExtent2D extent = caps.currentExtent; 4192f18b292ff155af7df35930474857b507dbf18feTony Barbour // use the hints 4202f18b292ff155af7df35930474857b507dbf18feTony Barbour if (extent.width == (uint32_t) -1) { 4212f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.width = width_hint; 4222f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.height = height_hint; 4232f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4242f18b292ff155af7df35930474857b507dbf18feTony Barbour // clamp width; to protect us from broken hints? 4252f18b292ff155af7df35930474857b507dbf18feTony Barbour if (extent.width < caps.minImageExtent.width) 4262f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.width = caps.minImageExtent.width; 4272f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (extent.width > caps.maxImageExtent.width) 4282f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.width = caps.maxImageExtent.width; 4292f18b292ff155af7df35930474857b507dbf18feTony Barbour // clamp height 4302f18b292ff155af7df35930474857b507dbf18feTony Barbour if (extent.height < caps.minImageExtent.height) 4312f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.height = caps.minImageExtent.height; 4322f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (extent.height > caps.maxImageExtent.height) 4332f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.height = caps.maxImageExtent.height; 4342f18b292ff155af7df35930474857b507dbf18feTony Barbour 4352f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.extent.width == extent.width && ctx_.extent.height == extent.height) 4362f18b292ff155af7df35930474857b507dbf18feTony Barbour return; 4372f18b292ff155af7df35930474857b507dbf18feTony Barbour 4382f18b292ff155af7df35930474857b507dbf18feTony Barbour uint32_t image_count = settings_.back_buffer_count; 4392f18b292ff155af7df35930474857b507dbf18feTony Barbour if (image_count < caps.minImageCount) 4402f18b292ff155af7df35930474857b507dbf18feTony Barbour image_count = caps.minImageCount; 4412f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (image_count > caps.maxImageCount) 4422f18b292ff155af7df35930474857b507dbf18feTony Barbour image_count = caps.maxImageCount; 4432f18b292ff155af7df35930474857b507dbf18feTony Barbour 4442f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(caps.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); 4452f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(caps.supportedTransforms & caps.currentTransform); 4462f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | 4472f18b292ff155af7df35930474857b507dbf18feTony Barbour VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); 4482f18b292ff155af7df35930474857b507dbf18feTony Barbour VkCompositeAlphaFlagBitsKHR composite_alpha = 4492f18b292ff155af7df35930474857b507dbf18feTony Barbour (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ? 4502f18b292ff155af7df35930474857b507dbf18feTony Barbour VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 4512f18b292ff155af7df35930474857b507dbf18feTony Barbour 4522f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkPresentModeKHR> modes; 4532f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::get(ctx_.physical_dev, ctx_.surface, modes); 4542f18b292ff155af7df35930474857b507dbf18feTony Barbour 4552f18b292ff155af7df35930474857b507dbf18feTony Barbour // FIFO is the only mode universally supported 4562f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; 4572f18b292ff155af7df35930474857b507dbf18feTony Barbour for (auto m : modes) { 4582f18b292ff155af7df35930474857b507dbf18feTony Barbour if ((settings_.vsync && m == VK_PRESENT_MODE_MAILBOX_KHR) || 4592f18b292ff155af7df35930474857b507dbf18feTony Barbour (!settings_.vsync && m == VK_PRESENT_MODE_IMMEDIATE_KHR)) { 4602f18b292ff155af7df35930474857b507dbf18feTony Barbour mode = m; 4612f18b292ff155af7df35930474857b507dbf18feTony Barbour break; 4622f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4632f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4642f18b292ff155af7df35930474857b507dbf18feTony Barbour 4652f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSwapchainCreateInfoKHR swapchain_info = {}; 4662f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 4672f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.surface = ctx_.surface; 4682f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.minImageCount = image_count; 4692f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageFormat = ctx_.format.format; 4702f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageColorSpace = ctx_.format.colorSpace; 4712f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageExtent = extent; 4722f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageArrayLayers = 1; 4732f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 4742f18b292ff155af7df35930474857b507dbf18feTony Barbour 4752f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<uint32_t> queue_families(1, ctx_.game_queue_family); 4762f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.game_queue_family != ctx_.present_queue_family) { 4772f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_families.push_back(ctx_.present_queue_family); 4782f18b292ff155af7df35930474857b507dbf18feTony Barbour 4792f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; 4802f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.queueFamilyIndexCount = (uint32_t)queue_families.size(); 4812f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.pQueueFamilyIndices = queue_families.data(); 4822f18b292ff155af7df35930474857b507dbf18feTony Barbour } else { 4832f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 4842f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4852f18b292ff155af7df35930474857b507dbf18feTony Barbour 4862f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.preTransform = caps.currentTransform;; 4872f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.compositeAlpha = composite_alpha; 4882f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.presentMode = mode; 4892f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.clipped = true; 4902f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.oldSwapchain = ctx_.swapchain; 4912f18b292ff155af7df35930474857b507dbf18feTony Barbour 4922f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateSwapchainKHR(ctx_.dev, &swapchain_info, nullptr, &ctx_.swapchain)); 4932f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.extent = extent; 4942f18b292ff155af7df35930474857b507dbf18feTony Barbour 4952f18b292ff155af7df35930474857b507dbf18feTony Barbour // destroy the old swapchain 4962f18b292ff155af7df35930474857b507dbf18feTony Barbour if (swapchain_info.oldSwapchain != VK_NULL_HANDLE) { 4972f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.detach_swapchain(); 4982f18b292ff155af7df35930474857b507dbf18feTony Barbour 4992f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DeviceWaitIdle(ctx_.dev); 5002f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySwapchainKHR(ctx_.dev, swapchain_info.oldSwapchain, nullptr); 5012f18b292ff155af7df35930474857b507dbf18feTony Barbour } 5022f18b292ff155af7df35930474857b507dbf18feTony Barbour 5032f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.attach_swapchain(); 5042f18b292ff155af7df35930474857b507dbf18feTony Barbour} 5052f18b292ff155af7df35930474857b507dbf18feTony Barbour 5062f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::add_game_time(float time) 5072f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 5082f18b292ff155af7df35930474857b507dbf18feTony Barbour int max_ticks = 3; 5092f18b292ff155af7df35930474857b507dbf18feTony Barbour 5102f18b292ff155af7df35930474857b507dbf18feTony Barbour if (!settings_.no_tick) 5112f18b292ff155af7df35930474857b507dbf18feTony Barbour game_time_ += time; 5122f18b292ff155af7df35930474857b507dbf18feTony Barbour 5132f18b292ff155af7df35930474857b507dbf18feTony Barbour while (game_time_ >= game_tick_ && max_ticks--) { 5142f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.on_tick(); 5152f18b292ff155af7df35930474857b507dbf18feTony Barbour game_time_ -= game_tick_; 5162f18b292ff155af7df35930474857b507dbf18feTony Barbour } 5172f18b292ff155af7df35930474857b507dbf18feTony Barbour} 5182f18b292ff155af7df35930474857b507dbf18feTony Barbour 5192f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::acquire_back_buffer() 5202f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 5212f18b292ff155af7df35930474857b507dbf18feTony Barbour // acquire just once when not presenting 5222f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.no_present && 5232f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.acquired_back_buffer.acquire_semaphore != VK_NULL_HANDLE) 5242f18b292ff155af7df35930474857b507dbf18feTony Barbour return; 5252f18b292ff155af7df35930474857b507dbf18feTony Barbour 5262f18b292ff155af7df35930474857b507dbf18feTony Barbour auto &buf = ctx_.back_buffers.front(); 5272f18b292ff155af7df35930474857b507dbf18feTony Barbour 5282f18b292ff155af7df35930474857b507dbf18feTony Barbour // wait until acquire and render semaphores are waited/unsignaled 5292f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::WaitForFences(ctx_.dev, 1, &buf.present_fence, 5302f18b292ff155af7df35930474857b507dbf18feTony Barbour true, UINT64_MAX)); 5312f18b292ff155af7df35930474857b507dbf18feTony Barbour // reset the fence 5322f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::ResetFences(ctx_.dev, 1, &buf.present_fence)); 5332f18b292ff155af7df35930474857b507dbf18feTony Barbour 5342f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::AcquireNextImageKHR(ctx_.dev, ctx_.swapchain, 5352f18b292ff155af7df35930474857b507dbf18feTony Barbour UINT64_MAX, buf.acquire_semaphore, VK_NULL_HANDLE, 5362f18b292ff155af7df35930474857b507dbf18feTony Barbour &buf.image_index)); 5372f18b292ff155af7df35930474857b507dbf18feTony Barbour 5382f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.acquired_back_buffer = buf; 5392f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.pop(); 5402f18b292ff155af7df35930474857b507dbf18feTony Barbour} 5412f18b292ff155af7df35930474857b507dbf18feTony Barbour 5422f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::present_back_buffer() 5432f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 5442f18b292ff155af7df35930474857b507dbf18feTony Barbour const auto &buf = ctx_.acquired_back_buffer; 5452f18b292ff155af7df35930474857b507dbf18feTony Barbour 5462f18b292ff155af7df35930474857b507dbf18feTony Barbour if (!settings_.no_render) 5472f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.on_frame(game_time_ / game_tick_); 5482f18b292ff155af7df35930474857b507dbf18feTony Barbour 5492f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.no_present) { 5502f18b292ff155af7df35930474857b507dbf18feTony Barbour fake_present(); 5512f18b292ff155af7df35930474857b507dbf18feTony Barbour return; 5522f18b292ff155af7df35930474857b507dbf18feTony Barbour } 5532f18b292ff155af7df35930474857b507dbf18feTony Barbour 5542f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPresentInfoKHR present_info = {}; 5552f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 5562f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.waitSemaphoreCount = 1; 5572f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.pWaitSemaphores = (settings_.no_render) ? 5582f18b292ff155af7df35930474857b507dbf18feTony Barbour &buf.acquire_semaphore : &buf.render_semaphore; 5592f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.swapchainCount = 1; 5602f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.pSwapchains = &ctx_.swapchain; 5612f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.pImageIndices = &buf.image_index; 5622f18b292ff155af7df35930474857b507dbf18feTony Barbour 5632f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::QueuePresentKHR(ctx_.present_queue, &present_info)); 5642f18b292ff155af7df35930474857b507dbf18feTony Barbour 5652f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::QueueSubmit(ctx_.present_queue, 0, nullptr, buf.present_fence)); 5662f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.push(buf); 5672f18b292ff155af7df35930474857b507dbf18feTony Barbour} 5682f18b292ff155af7df35930474857b507dbf18feTony Barbour 5692f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Shell::fake_present() 5702f18b292ff155af7df35930474857b507dbf18feTony Barbour{ 5712f18b292ff155af7df35930474857b507dbf18feTony Barbour const auto &buf = ctx_.acquired_back_buffer; 5722f18b292ff155af7df35930474857b507dbf18feTony Barbour 5732f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(settings_.no_present); 5742f18b292ff155af7df35930474857b507dbf18feTony Barbour 5752f18b292ff155af7df35930474857b507dbf18feTony Barbour // wait render semaphore and signal acquire semaphore 5762f18b292ff155af7df35930474857b507dbf18feTony Barbour if (!settings_.no_render) { 5772f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPipelineStageFlags stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 5782f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSubmitInfo submit_info = {}; 5792f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 5802f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.waitSemaphoreCount = 1; 5812f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.pWaitSemaphores = &buf.render_semaphore; 5822f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.pWaitDstStageMask = &stage; 5832f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.signalSemaphoreCount = 1; 5842f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.pSignalSemaphores = &buf.acquire_semaphore; 5852f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::QueueSubmit(ctx_.game_queue, 1, &submit_info, VK_NULL_HANDLE)); 5862f18b292ff155af7df35930474857b507dbf18feTony Barbour } 5872f18b292ff155af7df35930474857b507dbf18feTony Barbour 5882f18b292ff155af7df35930474857b507dbf18feTony Barbour // push the buffer back just once for Shell::cleanup_vk 5892f18b292ff155af7df35930474857b507dbf18feTony Barbour if (buf.acquire_semaphore != ctx_.back_buffers.back().acquire_semaphore) 5902f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.push(buf); 5912f18b292ff155af7df35930474857b507dbf18feTony Barbour} 592