12f18b292ff155af7df35930474857b507dbf18feTony Barbour/* 22f18b292ff155af7df35930474857b507dbf18feTony Barbour * Copyright (C) 2016 Google, Inc. 32f18b292ff155af7df35930474857b507dbf18feTony Barbour * 443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Licensed under the Apache License, Version 2.0 (the "License"); 543b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * you may not use this file except in compliance with the License. 643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * You may obtain a copy of the License at 72f18b292ff155af7df35930474857b507dbf18feTony Barbour * 843b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * http://www.apache.org/licenses/LICENSE-2.0 92f18b292ff155af7df35930474857b507dbf18feTony Barbour * 1043b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Unless required by applicable law or agreed to in writing, software 1143b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * distributed under the License is distributed on an "AS IS" BASIS, 1243b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1343b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * See the License for the specific language governing permissions and 1443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * limitations under the License. 152f18b292ff155af7df35930474857b507dbf18feTony Barbour */ 162f18b292ff155af7df35930474857b507dbf18feTony Barbour 172f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <cassert> 182f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <array> 192f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <iostream> 202f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <string> 212f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <sstream> 222f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <set> 232f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Helpers.h" 242f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Shell.h" 252f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Game.h" 262f18b292ff155af7df35930474857b507dbf18feTony Barbour 272f18b292ff155af7df35930474857b507dbf18feTony BarbourShell::Shell(Game &game) 28bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski : game_(game), settings_(game.settings()), ctx_(), game_tick_(1.0f / settings_.ticks_per_second), game_time_(game_tick_) { 292f18b292ff155af7df35930474857b507dbf18feTony Barbour // require generic WSI extensions 302f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_extensions_.push_back(VK_KHR_SURFACE_EXTENSION_NAME); 312f18b292ff155af7df35930474857b507dbf18feTony Barbour device_extensions_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 322f18b292ff155af7df35930474857b507dbf18feTony Barbour 332f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.validate) { 342f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_extensions_.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); 352f18b292ff155af7df35930474857b507dbf18feTony Barbour } 362f18b292ff155af7df35930474857b507dbf18feTony Barbour} 372f18b292ff155af7df35930474857b507dbf18feTony Barbour 38bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::log(LogPriority priority, const char *msg) { 392f18b292ff155af7df35930474857b507dbf18feTony Barbour std::ostream &st = (priority >= LOG_ERR) ? std::cerr : std::cout; 402f18b292ff155af7df35930474857b507dbf18feTony Barbour st << msg << "\n"; 412f18b292ff155af7df35930474857b507dbf18feTony Barbour} 422f18b292ff155af7df35930474857b507dbf18feTony Barbour 43bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::init_vk() { 442f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::init_dispatch_table_top(load_vk()); 452f18b292ff155af7df35930474857b507dbf18feTony Barbour 462f18b292ff155af7df35930474857b507dbf18feTony Barbour init_instance(); 472f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::init_dispatch_table_middle(ctx_.instance, false); 482f18b292ff155af7df35930474857b507dbf18feTony Barbour 492f18b292ff155af7df35930474857b507dbf18feTony Barbour init_debug_report(); 502f18b292ff155af7df35930474857b507dbf18feTony Barbour init_physical_dev(); 512f18b292ff155af7df35930474857b507dbf18feTony Barbour} 522f18b292ff155af7df35930474857b507dbf18feTony Barbour 53bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::cleanup_vk() { 54cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (settings_.validate) vk::DestroyDebugReportCallbackEXT(ctx_.instance, ctx_.debug_report, nullptr); 552f18b292ff155af7df35930474857b507dbf18feTony Barbour 562f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroyInstance(ctx_.instance, nullptr); 572f18b292ff155af7df35930474857b507dbf18feTony Barbour} 582f18b292ff155af7df35930474857b507dbf18feTony Barbour 59bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool Shell::debug_report_callback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT obj_type, uint64_t object, 60bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski size_t location, int32_t msg_code, const char *layer_prefix, const char *msg) { 612f18b292ff155af7df35930474857b507dbf18feTony Barbour LogPriority prio = LOG_WARN; 622f18b292ff155af7df35930474857b507dbf18feTony Barbour if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) 632f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_ERR; 642f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) 652f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_WARN; 662f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) 672f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_INFO; 682f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) 692f18b292ff155af7df35930474857b507dbf18feTony Barbour prio = LOG_DEBUG; 702f18b292ff155af7df35930474857b507dbf18feTony Barbour 712f18b292ff155af7df35930474857b507dbf18feTony Barbour std::stringstream ss; 722f18b292ff155af7df35930474857b507dbf18feTony Barbour ss << layer_prefix << ": " << msg; 732f18b292ff155af7df35930474857b507dbf18feTony Barbour 742f18b292ff155af7df35930474857b507dbf18feTony Barbour log(prio, ss.str().c_str()); 752f18b292ff155af7df35930474857b507dbf18feTony Barbour 762f18b292ff155af7df35930474857b507dbf18feTony Barbour return false; 772f18b292ff155af7df35930474857b507dbf18feTony Barbour} 782f18b292ff155af7df35930474857b507dbf18feTony Barbour 79bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::assert_all_instance_layers() const { 802f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate instance layer 812f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkLayerProperties> layers; 822f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::enumerate(layers); 832f18b292ff155af7df35930474857b507dbf18feTony Barbour 842f18b292ff155af7df35930474857b507dbf18feTony Barbour std::set<std::string> layer_names; 85cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski for (const auto &layer : layers) layer_names.insert(layer.layerName); 862f18b292ff155af7df35930474857b507dbf18feTony Barbour 872f18b292ff155af7df35930474857b507dbf18feTony Barbour // all listed instance layers are required 882f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &name : instance_layers_) { 892f18b292ff155af7df35930474857b507dbf18feTony Barbour if (layer_names.find(name) == layer_names.end()) { 902f18b292ff155af7df35930474857b507dbf18feTony Barbour std::stringstream ss; 912f18b292ff155af7df35930474857b507dbf18feTony Barbour ss << "instance layer " << name << " is missing"; 922f18b292ff155af7df35930474857b507dbf18feTony Barbour throw std::runtime_error(ss.str()); 932f18b292ff155af7df35930474857b507dbf18feTony Barbour } 942f18b292ff155af7df35930474857b507dbf18feTony Barbour } 952f18b292ff155af7df35930474857b507dbf18feTony Barbour} 962f18b292ff155af7df35930474857b507dbf18feTony Barbour 97bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::assert_all_instance_extensions() const { 982f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate instance extensions 992f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkExtensionProperties> exts; 1002f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::enumerate(nullptr, exts); 1012f18b292ff155af7df35930474857b507dbf18feTony Barbour 1022f18b292ff155af7df35930474857b507dbf18feTony Barbour std::set<std::string> ext_names; 103cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski for (const auto &ext : exts) ext_names.insert(ext.extensionName); 1042f18b292ff155af7df35930474857b507dbf18feTony Barbour 1052f18b292ff155af7df35930474857b507dbf18feTony Barbour // all listed instance extensions are required 1062f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &name : instance_extensions_) { 1072f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ext_names.find(name) == ext_names.end()) { 1082f18b292ff155af7df35930474857b507dbf18feTony Barbour std::stringstream ss; 1092f18b292ff155af7df35930474857b507dbf18feTony Barbour ss << "instance extension " << name << " is missing"; 1102f18b292ff155af7df35930474857b507dbf18feTony Barbour throw std::runtime_error(ss.str()); 1112f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1122f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1132f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1142f18b292ff155af7df35930474857b507dbf18feTony Barbour 115bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskibool Shell::has_all_device_extensions(VkPhysicalDevice phy) const { 1162f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate device extensions 1172f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkExtensionProperties> exts; 1182f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::enumerate(phy, nullptr, exts); 1192f18b292ff155af7df35930474857b507dbf18feTony Barbour 1202f18b292ff155af7df35930474857b507dbf18feTony Barbour std::set<std::string> ext_names; 121cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski for (const auto &ext : exts) ext_names.insert(ext.extensionName); 1222f18b292ff155af7df35930474857b507dbf18feTony Barbour 1232f18b292ff155af7df35930474857b507dbf18feTony Barbour // all listed device extensions are required 1242f18b292ff155af7df35930474857b507dbf18feTony Barbour for (const auto &name : device_extensions_) { 125cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (ext_names.find(name) == ext_names.end()) return false; 1262f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1272f18b292ff155af7df35930474857b507dbf18feTony Barbour 1282f18b292ff155af7df35930474857b507dbf18feTony Barbour return true; 1292f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1302f18b292ff155af7df35930474857b507dbf18feTony Barbour 131bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::init_instance() { 1322f18b292ff155af7df35930474857b507dbf18feTony Barbour assert_all_instance_layers(); 1332f18b292ff155af7df35930474857b507dbf18feTony Barbour assert_all_instance_extensions(); 1342f18b292ff155af7df35930474857b507dbf18feTony Barbour 1352f18b292ff155af7df35930474857b507dbf18feTony Barbour VkApplicationInfo app_info = {}; 1362f18b292ff155af7df35930474857b507dbf18feTony Barbour app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 1372f18b292ff155af7df35930474857b507dbf18feTony Barbour app_info.pApplicationName = settings_.name.c_str(); 1382f18b292ff155af7df35930474857b507dbf18feTony Barbour app_info.applicationVersion = 0; 139d3995c987ba7e47700ceb54535880e782c6b04c1Jon Ashburn app_info.apiVersion = VK_API_VERSION_1_0; 1402f18b292ff155af7df35930474857b507dbf18feTony Barbour 1412f18b292ff155af7df35930474857b507dbf18feTony Barbour VkInstanceCreateInfo instance_info = {}; 1422f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 1432f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.pApplicationInfo = &app_info; 1442f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.enabledLayerCount = static_cast<uint32_t>(instance_layers_.size()); 1452f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.ppEnabledLayerNames = instance_layers_.data(); 1462f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.enabledExtensionCount = static_cast<uint32_t>(instance_extensions_.size()); 1472f18b292ff155af7df35930474857b507dbf18feTony Barbour instance_info.ppEnabledExtensionNames = instance_extensions_.data(); 1482f18b292ff155af7df35930474857b507dbf18feTony Barbour 1492f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateInstance(&instance_info, nullptr, &ctx_.instance)); 1502f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1512f18b292ff155af7df35930474857b507dbf18feTony Barbour 152bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::init_debug_report() { 153cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (!settings_.validate) return; 1542f18b292ff155af7df35930474857b507dbf18feTony Barbour 1552f18b292ff155af7df35930474857b507dbf18feTony Barbour VkDebugReportCallbackCreateInfoEXT debug_report_info = {}; 1562f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 1572f18b292ff155af7df35930474857b507dbf18feTony Barbour 158bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski debug_report_info.flags = 159bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | VK_DEBUG_REPORT_ERROR_BIT_EXT; 1602f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.validate_verbose) { 161bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski debug_report_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT | VK_DEBUG_REPORT_DEBUG_BIT_EXT; 1622f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1632f18b292ff155af7df35930474857b507dbf18feTony Barbour 1642f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.pfnCallback = debug_report_callback; 1652f18b292ff155af7df35930474857b507dbf18feTony Barbour debug_report_info.pUserData = reinterpret_cast<void *>(this); 1662f18b292ff155af7df35930474857b507dbf18feTony Barbour 167bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski vk::assert_success(vk::CreateDebugReportCallbackEXT(ctx_.instance, &debug_report_info, nullptr, &ctx_.debug_report)); 1682f18b292ff155af7df35930474857b507dbf18feTony Barbour} 1692f18b292ff155af7df35930474857b507dbf18feTony Barbour 170bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::init_physical_dev() { 1712f18b292ff155af7df35930474857b507dbf18feTony Barbour // enumerate physical devices 1722f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkPhysicalDevice> phys; 1732f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::enumerate(ctx_.instance, phys)); 1742f18b292ff155af7df35930474857b507dbf18feTony Barbour 1752f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.physical_dev = VK_NULL_HANDLE; 1762f18b292ff155af7df35930474857b507dbf18feTony Barbour for (auto phy : phys) { 177cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (!has_all_device_extensions(phy)) continue; 1782f18b292ff155af7df35930474857b507dbf18feTony Barbour 1792f18b292ff155af7df35930474857b507dbf18feTony Barbour // get queue properties 1802f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkQueueFamilyProperties> queues; 1812f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::get(phy, queues); 1822f18b292ff155af7df35930474857b507dbf18feTony Barbour 1832f18b292ff155af7df35930474857b507dbf18feTony Barbour int game_queue_family = -1, present_queue_family = -1; 1842f18b292ff155af7df35930474857b507dbf18feTony Barbour for (uint32_t i = 0; i < queues.size(); i++) { 1852f18b292ff155af7df35930474857b507dbf18feTony Barbour const VkQueueFamilyProperties &q = queues[i]; 1862f18b292ff155af7df35930474857b507dbf18feTony Barbour 1872f18b292ff155af7df35930474857b507dbf18feTony Barbour // requires only GRAPHICS for game queues 1882f18b292ff155af7df35930474857b507dbf18feTony Barbour const VkFlags game_queue_flags = VK_QUEUE_GRAPHICS_BIT; 189cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (game_queue_family < 0 && (q.queueFlags & game_queue_flags) == game_queue_flags) game_queue_family = i; 1902f18b292ff155af7df35930474857b507dbf18feTony Barbour 1912f18b292ff155af7df35930474857b507dbf18feTony Barbour // present queue must support the surface 192cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (present_queue_family < 0 && can_present(phy, i)) present_queue_family = i; 1932f18b292ff155af7df35930474857b507dbf18feTony Barbour 194cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (game_queue_family >= 0 && present_queue_family >= 0) break; 1952f18b292ff155af7df35930474857b507dbf18feTony Barbour } 1962f18b292ff155af7df35930474857b507dbf18feTony Barbour 1972f18b292ff155af7df35930474857b507dbf18feTony Barbour if (game_queue_family >= 0 && present_queue_family >= 0) { 1982f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.physical_dev = phy; 1992f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.game_queue_family = game_queue_family; 2002f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.present_queue_family = present_queue_family; 2012f18b292ff155af7df35930474857b507dbf18feTony Barbour break; 2022f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2032f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2042f18b292ff155af7df35930474857b507dbf18feTony Barbour 205cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (ctx_.physical_dev == VK_NULL_HANDLE) throw std::runtime_error("failed to find any capable Vulkan physical device"); 2062f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2072f18b292ff155af7df35930474857b507dbf18feTony Barbour 208bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::create_context() { 2092f18b292ff155af7df35930474857b507dbf18feTony Barbour create_dev(); 2102f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::init_dispatch_table_bottom(ctx_.instance, ctx_.dev); 2112f18b292ff155af7df35930474857b507dbf18feTony Barbour 2122f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::GetDeviceQueue(ctx_.dev, ctx_.game_queue_family, 0, &ctx_.game_queue); 2132f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::GetDeviceQueue(ctx_.dev, ctx_.present_queue_family, 0, &ctx_.present_queue); 2142f18b292ff155af7df35930474857b507dbf18feTony Barbour 2152f18b292ff155af7df35930474857b507dbf18feTony Barbour create_back_buffers(); 2162f18b292ff155af7df35930474857b507dbf18feTony Barbour 2172f18b292ff155af7df35930474857b507dbf18feTony Barbour // initialize ctx_.{surface,format} before attach_shell 2182f18b292ff155af7df35930474857b507dbf18feTony Barbour create_swapchain(); 2192f18b292ff155af7df35930474857b507dbf18feTony Barbour 2202f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.attach_shell(*this); 2212f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2222f18b292ff155af7df35930474857b507dbf18feTony Barbour 223bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::destroy_context() { 224cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (ctx_.dev == VK_NULL_HANDLE) return; 2252f18b292ff155af7df35930474857b507dbf18feTony Barbour 2262f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DeviceWaitIdle(ctx_.dev); 2272f18b292ff155af7df35930474857b507dbf18feTony Barbour 2282f18b292ff155af7df35930474857b507dbf18feTony Barbour destroy_swapchain(); 2292f18b292ff155af7df35930474857b507dbf18feTony Barbour 2302f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.detach_shell(); 2312f18b292ff155af7df35930474857b507dbf18feTony Barbour 2322f18b292ff155af7df35930474857b507dbf18feTony Barbour destroy_back_buffers(); 2332f18b292ff155af7df35930474857b507dbf18feTony Barbour 2342f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.game_queue = VK_NULL_HANDLE; 2352f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.present_queue = VK_NULL_HANDLE; 2362f18b292ff155af7df35930474857b507dbf18feTony Barbour 2372f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroyDevice(ctx_.dev, nullptr); 2382f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.dev = VK_NULL_HANDLE; 2392f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2402f18b292ff155af7df35930474857b507dbf18feTony Barbour 241bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::create_dev() { 2422f18b292ff155af7df35930474857b507dbf18feTony Barbour VkDeviceCreateInfo dev_info = {}; 2432f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 2442f18b292ff155af7df35930474857b507dbf18feTony Barbour 2452f18b292ff155af7df35930474857b507dbf18feTony Barbour const std::vector<float> queue_priorities(settings_.queue_count, 0.0f); 2462f18b292ff155af7df35930474857b507dbf18feTony Barbour std::array<VkDeviceQueueCreateInfo, 2> queue_info = {}; 2472f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 2482f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].queueFamilyIndex = ctx_.game_queue_family; 2492f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].queueCount = settings_.queue_count; 2502f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[0].pQueuePriorities = queue_priorities.data(); 2512f18b292ff155af7df35930474857b507dbf18feTony Barbour 2522f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.game_queue_family != ctx_.present_queue_family) { 2532f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 2542f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].queueFamilyIndex = ctx_.present_queue_family; 2552f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].queueCount = 1; 2562f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_info[1].pQueuePriorities = queue_priorities.data(); 2572f18b292ff155af7df35930474857b507dbf18feTony Barbour 2582f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.queueCreateInfoCount = 2; 2592f18b292ff155af7df35930474857b507dbf18feTony Barbour } else { 2602f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.queueCreateInfoCount = 1; 2612f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2622f18b292ff155af7df35930474857b507dbf18feTony Barbour 2632f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.pQueueCreateInfos = queue_info.data(); 2642f18b292ff155af7df35930474857b507dbf18feTony Barbour 2652f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions_.size()); 2662f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.ppEnabledExtensionNames = device_extensions_.data(); 2672f18b292ff155af7df35930474857b507dbf18feTony Barbour 2682f18b292ff155af7df35930474857b507dbf18feTony Barbour // disable all features 2692f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPhysicalDeviceFeatures features = {}; 2702f18b292ff155af7df35930474857b507dbf18feTony Barbour dev_info.pEnabledFeatures = &features; 2712f18b292ff155af7df35930474857b507dbf18feTony Barbour 2722f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateDevice(ctx_.physical_dev, &dev_info, nullptr, &ctx_.dev)); 2732f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2742f18b292ff155af7df35930474857b507dbf18feTony Barbour 275bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::create_back_buffers() { 2762f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSemaphoreCreateInfo sem_info = {}; 2772f18b292ff155af7df35930474857b507dbf18feTony Barbour sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 2782f18b292ff155af7df35930474857b507dbf18feTony Barbour 2792f18b292ff155af7df35930474857b507dbf18feTony Barbour VkFenceCreateInfo fence_info = {}; 2802f18b292ff155af7df35930474857b507dbf18feTony Barbour fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 2812f18b292ff155af7df35930474857b507dbf18feTony Barbour fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; 2822f18b292ff155af7df35930474857b507dbf18feTony Barbour 2832f18b292ff155af7df35930474857b507dbf18feTony Barbour // BackBuffer is used to track which swapchain image and its associated 2842f18b292ff155af7df35930474857b507dbf18feTony Barbour // sync primitives are busy. Having more BackBuffer's than swapchain 2852f18b292ff155af7df35930474857b507dbf18feTony Barbour // images may allows us to replace CPU wait on present_fence by GPU wait 2862f18b292ff155af7df35930474857b507dbf18feTony Barbour // on acquire_semaphore. 2872f18b292ff155af7df35930474857b507dbf18feTony Barbour const int count = settings_.back_buffer_count + 1; 2882f18b292ff155af7df35930474857b507dbf18feTony Barbour for (int i = 0; i < count; i++) { 2892f18b292ff155af7df35930474857b507dbf18feTony Barbour BackBuffer buf = {}; 2902f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateSemaphore(ctx_.dev, &sem_info, nullptr, &buf.acquire_semaphore)); 2912f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateSemaphore(ctx_.dev, &sem_info, nullptr, &buf.render_semaphore)); 2922f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateFence(ctx_.dev, &fence_info, nullptr, &buf.present_fence)); 2932f18b292ff155af7df35930474857b507dbf18feTony Barbour 2942f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.push(buf); 2952f18b292ff155af7df35930474857b507dbf18feTony Barbour } 2962f18b292ff155af7df35930474857b507dbf18feTony Barbour} 2972f18b292ff155af7df35930474857b507dbf18feTony Barbour 298bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::destroy_back_buffers() { 2992f18b292ff155af7df35930474857b507dbf18feTony Barbour while (!ctx_.back_buffers.empty()) { 3002f18b292ff155af7df35930474857b507dbf18feTony Barbour const auto &buf = ctx_.back_buffers.front(); 3012f18b292ff155af7df35930474857b507dbf18feTony Barbour 3022f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySemaphore(ctx_.dev, buf.acquire_semaphore, nullptr); 3032f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySemaphore(ctx_.dev, buf.render_semaphore, nullptr); 3042f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroyFence(ctx_.dev, buf.present_fence, nullptr); 3052f18b292ff155af7df35930474857b507dbf18feTony Barbour 3062f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.pop(); 3072f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3082f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3092f18b292ff155af7df35930474857b507dbf18feTony Barbour 310bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::create_swapchain() { 3112f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.surface = create_surface(ctx_.instance); 3122f18b292ff155af7df35930474857b507dbf18feTony Barbour 3132f18b292ff155af7df35930474857b507dbf18feTony Barbour VkBool32 supported; 314bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski vk::assert_success( 315bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski vk::GetPhysicalDeviceSurfaceSupportKHR(ctx_.physical_dev, ctx_.present_queue_family, ctx_.surface, &supported)); 3162f18b292ff155af7df35930474857b507dbf18feTony Barbour // this should be guaranteed by the platform-specific can_present call 3172f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(supported); 3182f18b292ff155af7df35930474857b507dbf18feTony Barbour 3192f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkSurfaceFormatKHR> formats; 3202f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::get(ctx_.physical_dev, ctx_.surface, formats); 3212f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.format = formats[0]; 3222f18b292ff155af7df35930474857b507dbf18feTony Barbour 3232f18b292ff155af7df35930474857b507dbf18feTony Barbour // defer to resize_swapchain() 3242f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.swapchain = VK_NULL_HANDLE; 325bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski ctx_.extent.width = (uint32_t)-1; 326bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski ctx_.extent.height = (uint32_t)-1; 3272f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3282f18b292ff155af7df35930474857b507dbf18feTony Barbour 329bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::destroy_swapchain() { 3302f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.swapchain != VK_NULL_HANDLE) { 3312f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.detach_swapchain(); 3322f18b292ff155af7df35930474857b507dbf18feTony Barbour 3332f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySwapchainKHR(ctx_.dev, ctx_.swapchain, nullptr); 3342f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.swapchain = VK_NULL_HANDLE; 3352f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3362f18b292ff155af7df35930474857b507dbf18feTony Barbour 3372f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySurfaceKHR(ctx_.instance, ctx_.surface, nullptr); 3382f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.surface = VK_NULL_HANDLE; 3392f18b292ff155af7df35930474857b507dbf18feTony Barbour} 3402f18b292ff155af7df35930474857b507dbf18feTony Barbour 341bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::resize_swapchain(uint32_t width_hint, uint32_t height_hint) { 3422f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSurfaceCapabilitiesKHR caps; 343bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski vk::assert_success(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(ctx_.physical_dev, ctx_.surface, &caps)); 3442f18b292ff155af7df35930474857b507dbf18feTony Barbour 3452f18b292ff155af7df35930474857b507dbf18feTony Barbour VkExtent2D extent = caps.currentExtent; 3462f18b292ff155af7df35930474857b507dbf18feTony Barbour // use the hints 347bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski if (extent.width == (uint32_t)-1) { 3482f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.width = width_hint; 3492f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.height = height_hint; 3502f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3512f18b292ff155af7df35930474857b507dbf18feTony Barbour // clamp width; to protect us from broken hints? 3522f18b292ff155af7df35930474857b507dbf18feTony Barbour if (extent.width < caps.minImageExtent.width) 3532f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.width = caps.minImageExtent.width; 3542f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (extent.width > caps.maxImageExtent.width) 3552f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.width = caps.maxImageExtent.width; 3562f18b292ff155af7df35930474857b507dbf18feTony Barbour // clamp height 3572f18b292ff155af7df35930474857b507dbf18feTony Barbour if (extent.height < caps.minImageExtent.height) 3582f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.height = caps.minImageExtent.height; 3592f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (extent.height > caps.maxImageExtent.height) 3602f18b292ff155af7df35930474857b507dbf18feTony Barbour extent.height = caps.maxImageExtent.height; 3612f18b292ff155af7df35930474857b507dbf18feTony Barbour 362cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (ctx_.extent.width == extent.width && ctx_.extent.height == extent.height) return; 3632f18b292ff155af7df35930474857b507dbf18feTony Barbour 3642f18b292ff155af7df35930474857b507dbf18feTony Barbour uint32_t image_count = settings_.back_buffer_count; 3652f18b292ff155af7df35930474857b507dbf18feTony Barbour if (image_count < caps.minImageCount) 3662f18b292ff155af7df35930474857b507dbf18feTony Barbour image_count = caps.minImageCount; 3672f18b292ff155af7df35930474857b507dbf18feTony Barbour else if (image_count > caps.maxImageCount) 3682f18b292ff155af7df35930474857b507dbf18feTony Barbour image_count = caps.maxImageCount; 3692f18b292ff155af7df35930474857b507dbf18feTony Barbour 3702f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(caps.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); 3712f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(caps.supportedTransforms & caps.currentTransform); 372bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski assert(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); 373bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski VkCompositeAlphaFlagBitsKHR composite_alpha = (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) 374bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR 375bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 3762f18b292ff155af7df35930474857b507dbf18feTony Barbour 3772f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<VkPresentModeKHR> modes; 3782f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::get(ctx_.physical_dev, ctx_.surface, modes); 3792f18b292ff155af7df35930474857b507dbf18feTony Barbour 3802f18b292ff155af7df35930474857b507dbf18feTony Barbour // FIFO is the only mode universally supported 3812f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; 3822f18b292ff155af7df35930474857b507dbf18feTony Barbour for (auto m : modes) { 383bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski if ((settings_.vsync && m == VK_PRESENT_MODE_MAILBOX_KHR) || (!settings_.vsync && m == VK_PRESENT_MODE_IMMEDIATE_KHR)) { 3842f18b292ff155af7df35930474857b507dbf18feTony Barbour mode = m; 3852f18b292ff155af7df35930474857b507dbf18feTony Barbour break; 3862f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3872f18b292ff155af7df35930474857b507dbf18feTony Barbour } 3882f18b292ff155af7df35930474857b507dbf18feTony Barbour 3892f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSwapchainCreateInfoKHR swapchain_info = {}; 3902f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 3912f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.surface = ctx_.surface; 3922f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.minImageCount = image_count; 3932f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageFormat = ctx_.format.format; 3942f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageColorSpace = ctx_.format.colorSpace; 3952f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageExtent = extent; 3962f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageArrayLayers = 1; 3972f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 3982f18b292ff155af7df35930474857b507dbf18feTony Barbour 3992f18b292ff155af7df35930474857b507dbf18feTony Barbour std::vector<uint32_t> queue_families(1, ctx_.game_queue_family); 4002f18b292ff155af7df35930474857b507dbf18feTony Barbour if (ctx_.game_queue_family != ctx_.present_queue_family) { 4012f18b292ff155af7df35930474857b507dbf18feTony Barbour queue_families.push_back(ctx_.present_queue_family); 4022f18b292ff155af7df35930474857b507dbf18feTony Barbour 4032f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; 4042f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.queueFamilyIndexCount = (uint32_t)queue_families.size(); 4052f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.pQueueFamilyIndices = queue_families.data(); 4062f18b292ff155af7df35930474857b507dbf18feTony Barbour } else { 4072f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 4082f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4092f18b292ff155af7df35930474857b507dbf18feTony Barbour 410bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski swapchain_info.preTransform = caps.currentTransform; 411bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski ; 4122f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.compositeAlpha = composite_alpha; 4132f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.presentMode = mode; 4142f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.clipped = true; 4152f18b292ff155af7df35930474857b507dbf18feTony Barbour swapchain_info.oldSwapchain = ctx_.swapchain; 4162f18b292ff155af7df35930474857b507dbf18feTony Barbour 4172f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::CreateSwapchainKHR(ctx_.dev, &swapchain_info, nullptr, &ctx_.swapchain)); 4182f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.extent = extent; 4192f18b292ff155af7df35930474857b507dbf18feTony Barbour 4202f18b292ff155af7df35930474857b507dbf18feTony Barbour // destroy the old swapchain 4212f18b292ff155af7df35930474857b507dbf18feTony Barbour if (swapchain_info.oldSwapchain != VK_NULL_HANDLE) { 4222f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.detach_swapchain(); 4232f18b292ff155af7df35930474857b507dbf18feTony Barbour 4242f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DeviceWaitIdle(ctx_.dev); 4252f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::DestroySwapchainKHR(ctx_.dev, swapchain_info.oldSwapchain, nullptr); 4262f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4272f18b292ff155af7df35930474857b507dbf18feTony Barbour 4282f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.attach_swapchain(); 4292f18b292ff155af7df35930474857b507dbf18feTony Barbour} 4302f18b292ff155af7df35930474857b507dbf18feTony Barbour 431bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::add_game_time(float time) { 4322f18b292ff155af7df35930474857b507dbf18feTony Barbour int max_ticks = 3; 4332f18b292ff155af7df35930474857b507dbf18feTony Barbour 434cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (!settings_.no_tick) game_time_ += time; 4352f18b292ff155af7df35930474857b507dbf18feTony Barbour 4362f18b292ff155af7df35930474857b507dbf18feTony Barbour while (game_time_ >= game_tick_ && max_ticks--) { 4372f18b292ff155af7df35930474857b507dbf18feTony Barbour game_.on_tick(); 4382f18b292ff155af7df35930474857b507dbf18feTony Barbour game_time_ -= game_tick_; 4392f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4402f18b292ff155af7df35930474857b507dbf18feTony Barbour} 4412f18b292ff155af7df35930474857b507dbf18feTony Barbour 442bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::acquire_back_buffer() { 4432f18b292ff155af7df35930474857b507dbf18feTony Barbour // acquire just once when not presenting 444cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (settings_.no_present && ctx_.acquired_back_buffer.acquire_semaphore != VK_NULL_HANDLE) return; 4452f18b292ff155af7df35930474857b507dbf18feTony Barbour 4462f18b292ff155af7df35930474857b507dbf18feTony Barbour auto &buf = ctx_.back_buffers.front(); 4472f18b292ff155af7df35930474857b507dbf18feTony Barbour 4482f18b292ff155af7df35930474857b507dbf18feTony Barbour // wait until acquire and render semaphores are waited/unsignaled 449bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski vk::assert_success(vk::WaitForFences(ctx_.dev, 1, &buf.present_fence, true, UINT64_MAX)); 4502f18b292ff155af7df35930474857b507dbf18feTony Barbour // reset the fence 4512f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::ResetFences(ctx_.dev, 1, &buf.present_fence)); 4522f18b292ff155af7df35930474857b507dbf18feTony Barbour 453bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski vk::assert_success( 454bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski vk::AcquireNextImageKHR(ctx_.dev, ctx_.swapchain, UINT64_MAX, buf.acquire_semaphore, VK_NULL_HANDLE, &buf.image_index)); 4552f18b292ff155af7df35930474857b507dbf18feTony Barbour 4562f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.acquired_back_buffer = buf; 4572f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.pop(); 4582f18b292ff155af7df35930474857b507dbf18feTony Barbour} 4592f18b292ff155af7df35930474857b507dbf18feTony Barbour 460bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::present_back_buffer() { 4612f18b292ff155af7df35930474857b507dbf18feTony Barbour const auto &buf = ctx_.acquired_back_buffer; 4622f18b292ff155af7df35930474857b507dbf18feTony Barbour 463cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (!settings_.no_render) game_.on_frame(game_time_ / game_tick_); 4642f18b292ff155af7df35930474857b507dbf18feTony Barbour 4652f18b292ff155af7df35930474857b507dbf18feTony Barbour if (settings_.no_present) { 4662f18b292ff155af7df35930474857b507dbf18feTony Barbour fake_present(); 4672f18b292ff155af7df35930474857b507dbf18feTony Barbour return; 4682f18b292ff155af7df35930474857b507dbf18feTony Barbour } 4692f18b292ff155af7df35930474857b507dbf18feTony Barbour 4702f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPresentInfoKHR present_info = {}; 4712f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 4722f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.waitSemaphoreCount = 1; 473bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinski present_info.pWaitSemaphores = (settings_.no_render) ? &buf.acquire_semaphore : &buf.render_semaphore; 4742f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.swapchainCount = 1; 4752f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.pSwapchains = &ctx_.swapchain; 4762f18b292ff155af7df35930474857b507dbf18feTony Barbour present_info.pImageIndices = &buf.image_index; 4772f18b292ff155af7df35930474857b507dbf18feTony Barbour 4782f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::QueuePresentKHR(ctx_.present_queue, &present_info)); 4792f18b292ff155af7df35930474857b507dbf18feTony Barbour 4802f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::QueueSubmit(ctx_.present_queue, 0, nullptr, buf.present_fence)); 4812f18b292ff155af7df35930474857b507dbf18feTony Barbour ctx_.back_buffers.push(buf); 4822f18b292ff155af7df35930474857b507dbf18feTony Barbour} 4832f18b292ff155af7df35930474857b507dbf18feTony Barbour 484bc9caa57c5583dfdf05198e78b78a7cb361da16cMark Lobodzinskivoid Shell::fake_present() { 4852f18b292ff155af7df35930474857b507dbf18feTony Barbour const auto &buf = ctx_.acquired_back_buffer; 4862f18b292ff155af7df35930474857b507dbf18feTony Barbour 4872f18b292ff155af7df35930474857b507dbf18feTony Barbour assert(settings_.no_present); 4882f18b292ff155af7df35930474857b507dbf18feTony Barbour 4892f18b292ff155af7df35930474857b507dbf18feTony Barbour // wait render semaphore and signal acquire semaphore 4902f18b292ff155af7df35930474857b507dbf18feTony Barbour if (!settings_.no_render) { 4912f18b292ff155af7df35930474857b507dbf18feTony Barbour VkPipelineStageFlags stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 4922f18b292ff155af7df35930474857b507dbf18feTony Barbour VkSubmitInfo submit_info = {}; 4932f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 4942f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.waitSemaphoreCount = 1; 4952f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.pWaitSemaphores = &buf.render_semaphore; 4962f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.pWaitDstStageMask = &stage; 4972f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.signalSemaphoreCount = 1; 4982f18b292ff155af7df35930474857b507dbf18feTony Barbour submit_info.pSignalSemaphores = &buf.acquire_semaphore; 4992f18b292ff155af7df35930474857b507dbf18feTony Barbour vk::assert_success(vk::QueueSubmit(ctx_.game_queue, 1, &submit_info, VK_NULL_HANDLE)); 5002f18b292ff155af7df35930474857b507dbf18feTony Barbour } 5012f18b292ff155af7df35930474857b507dbf18feTony Barbour 5022f18b292ff155af7df35930474857b507dbf18feTony Barbour // push the buffer back just once for Shell::cleanup_vk 503cc7c305c82f6443c324165edb7af59f60fc87eebMark Lobodzinski if (buf.acquire_semaphore != ctx_.back_buffers.back().acquire_semaphore) ctx_.back_buffers.push(buf); 5042f18b292ff155af7df35930474857b507dbf18feTony Barbour} 505