1 /* 2 * Copyright (C) 2016 Google, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <cassert> 18 #include <array> 19 #include <iostream> 20 #include <string> 21 #include <sstream> 22 #include <set> 23 #include "Helpers.h" 24 #include "Shell.h" 25 #include "Game.h" 26 27 Shell::Shell(Game &game) 28 : game_(game), settings_(game.settings()), ctx_(), 29 game_tick_(1.0f / settings_.ticks_per_second), game_time_(game_tick_) 30 { 31 // require generic WSI extensions 32 instance_extensions_.push_back(VK_KHR_SURFACE_EXTENSION_NAME); 33 device_extensions_.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); 34 35 // require "standard" validation layers 36 if (settings_.validate) { 37 instance_layers_.push_back("VK_LAYER_LUNARG_standard_validation"); 38 instance_extensions_.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); 39 } 40 } 41 42 void Shell::log(LogPriority priority, const char *msg) 43 { 44 std::ostream &st = (priority >= LOG_ERR) ? std::cerr : std::cout; 45 st << msg << "\n"; 46 } 47 48 void Shell::init_vk() 49 { 50 vk::init_dispatch_table_top(load_vk()); 51 52 init_instance(); 53 vk::init_dispatch_table_middle(ctx_.instance, false); 54 55 init_debug_report(); 56 init_physical_dev(); 57 } 58 59 void Shell::cleanup_vk() 60 { 61 if (settings_.validate) 62 vk::DestroyDebugReportCallbackEXT(ctx_.instance, ctx_.debug_report, nullptr); 63 64 vk::DestroyInstance(ctx_.instance, nullptr); 65 } 66 67 bool Shell::debug_report_callback(VkDebugReportFlagsEXT flags, 68 VkDebugReportObjectTypeEXT obj_type, 69 uint64_t object, 70 size_t location, 71 int32_t msg_code, 72 const char *layer_prefix, 73 const char *msg) 74 { 75 LogPriority prio = LOG_WARN; 76 if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT) 77 prio = LOG_ERR; 78 else if (flags & (VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)) 79 prio = LOG_WARN; 80 else if (flags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) 81 prio = LOG_INFO; 82 else if (flags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) 83 prio = LOG_DEBUG; 84 85 std::stringstream ss; 86 ss << layer_prefix << ": " << msg; 87 88 log(prio, ss.str().c_str()); 89 90 return false; 91 } 92 93 void Shell::assert_all_instance_layers() const 94 { 95 // enumerate instance layer 96 std::vector<VkLayerProperties> layers; 97 vk::enumerate(layers); 98 99 std::set<std::string> layer_names; 100 for (const auto &layer : layers) 101 layer_names.insert(layer.layerName); 102 103 // all listed instance layers are required 104 for (const auto &name : instance_layers_) { 105 if (layer_names.find(name) == layer_names.end()) { 106 std::stringstream ss; 107 ss << "instance layer " << name << " is missing"; 108 throw std::runtime_error(ss.str()); 109 } 110 } 111 } 112 113 void Shell::assert_all_instance_extensions() const 114 { 115 // enumerate instance extensions 116 std::vector<VkExtensionProperties> exts; 117 vk::enumerate(nullptr, exts); 118 119 std::set<std::string> ext_names; 120 for (const auto &ext : exts) 121 ext_names.insert(ext.extensionName); 122 123 // all listed instance extensions are required 124 for (const auto &name : instance_extensions_) { 125 if (ext_names.find(name) == ext_names.end()) { 126 std::stringstream ss; 127 ss << "instance extension " << name << " is missing"; 128 throw std::runtime_error(ss.str()); 129 } 130 } 131 } 132 133 bool Shell::has_all_device_extensions(VkPhysicalDevice phy) const 134 { 135 // enumerate device extensions 136 std::vector<VkExtensionProperties> exts; 137 vk::enumerate(phy, nullptr, exts); 138 139 std::set<std::string> ext_names; 140 for (const auto &ext : exts) 141 ext_names.insert(ext.extensionName); 142 143 // all listed device extensions are required 144 for (const auto &name : device_extensions_) { 145 if (ext_names.find(name) == ext_names.end()) 146 return false; 147 } 148 149 return true; 150 } 151 152 void Shell::init_instance() 153 { 154 assert_all_instance_layers(); 155 assert_all_instance_extensions(); 156 157 VkApplicationInfo app_info = {}; 158 app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 159 app_info.pApplicationName = settings_.name.c_str(); 160 app_info.applicationVersion = 0; 161 app_info.apiVersion = VK_API_VERSION_1_0; 162 163 VkInstanceCreateInfo instance_info = {}; 164 instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 165 instance_info.pApplicationInfo = &app_info; 166 instance_info.enabledLayerCount = static_cast<uint32_t>(instance_layers_.size()); 167 instance_info.ppEnabledLayerNames = instance_layers_.data(); 168 instance_info.enabledExtensionCount = static_cast<uint32_t>(instance_extensions_.size()); 169 instance_info.ppEnabledExtensionNames = instance_extensions_.data(); 170 171 vk::assert_success(vk::CreateInstance(&instance_info, nullptr, &ctx_.instance)); 172 } 173 174 void Shell::init_debug_report() 175 { 176 if (!settings_.validate) 177 return; 178 179 VkDebugReportCallbackCreateInfoEXT debug_report_info = {}; 180 debug_report_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; 181 182 debug_report_info.flags = VK_DEBUG_REPORT_WARNING_BIT_EXT | 183 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT | 184 VK_DEBUG_REPORT_ERROR_BIT_EXT; 185 if (settings_.validate_verbose) { 186 debug_report_info.flags = VK_DEBUG_REPORT_INFORMATION_BIT_EXT | 187 VK_DEBUG_REPORT_DEBUG_BIT_EXT; 188 } 189 190 debug_report_info.pfnCallback = debug_report_callback; 191 debug_report_info.pUserData = reinterpret_cast<void *>(this); 192 193 vk::assert_success(vk::CreateDebugReportCallbackEXT(ctx_.instance, 194 &debug_report_info, nullptr, &ctx_.debug_report)); 195 } 196 197 void Shell::init_physical_dev() 198 { 199 // enumerate physical devices 200 std::vector<VkPhysicalDevice> phys; 201 vk::assert_success(vk::enumerate(ctx_.instance, phys)); 202 203 ctx_.physical_dev = VK_NULL_HANDLE; 204 for (auto phy : phys) { 205 if (!has_all_device_extensions(phy)) 206 continue; 207 208 // get queue properties 209 std::vector<VkQueueFamilyProperties> queues; 210 vk::get(phy, queues); 211 212 int game_queue_family = -1, present_queue_family = -1; 213 for (uint32_t i = 0; i < queues.size(); i++) { 214 const VkQueueFamilyProperties &q = queues[i]; 215 216 // requires only GRAPHICS for game queues 217 const VkFlags game_queue_flags = VK_QUEUE_GRAPHICS_BIT; 218 if (game_queue_family < 0 && 219 (q.queueFlags & game_queue_flags) == game_queue_flags) 220 game_queue_family = i; 221 222 // present queue must support the surface 223 if (present_queue_family < 0 && can_present(phy, i)) 224 present_queue_family = i; 225 226 if (game_queue_family >= 0 && present_queue_family >= 0) 227 break; 228 } 229 230 if (game_queue_family >= 0 && present_queue_family >= 0) { 231 ctx_.physical_dev = phy; 232 ctx_.game_queue_family = game_queue_family; 233 ctx_.present_queue_family = present_queue_family; 234 break; 235 } 236 } 237 238 if (ctx_.physical_dev == VK_NULL_HANDLE) 239 throw std::runtime_error("failed to find any capable Vulkan physical device"); 240 } 241 242 void Shell::create_context() 243 { 244 create_dev(); 245 vk::init_dispatch_table_bottom(ctx_.instance, ctx_.dev); 246 247 vk::GetDeviceQueue(ctx_.dev, ctx_.game_queue_family, 0, &ctx_.game_queue); 248 vk::GetDeviceQueue(ctx_.dev, ctx_.present_queue_family, 0, &ctx_.present_queue); 249 250 create_back_buffers(); 251 252 // initialize ctx_.{surface,format} before attach_shell 253 create_swapchain(); 254 255 game_.attach_shell(*this); 256 } 257 258 void Shell::destroy_context() 259 { 260 if (ctx_.dev == VK_NULL_HANDLE) 261 return; 262 263 vk::DeviceWaitIdle(ctx_.dev); 264 265 destroy_swapchain(); 266 267 game_.detach_shell(); 268 269 destroy_back_buffers(); 270 271 ctx_.game_queue = VK_NULL_HANDLE; 272 ctx_.present_queue = VK_NULL_HANDLE; 273 274 vk::DestroyDevice(ctx_.dev, nullptr); 275 ctx_.dev = VK_NULL_HANDLE; 276 } 277 278 void Shell::create_dev() 279 { 280 VkDeviceCreateInfo dev_info = {}; 281 dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 282 283 const std::vector<float> queue_priorities(settings_.queue_count, 0.0f); 284 std::array<VkDeviceQueueCreateInfo, 2> queue_info = {}; 285 queue_info[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 286 queue_info[0].queueFamilyIndex = ctx_.game_queue_family; 287 queue_info[0].queueCount = settings_.queue_count; 288 queue_info[0].pQueuePriorities = queue_priorities.data(); 289 290 if (ctx_.game_queue_family != ctx_.present_queue_family) { 291 queue_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 292 queue_info[1].queueFamilyIndex = ctx_.present_queue_family; 293 queue_info[1].queueCount = 1; 294 queue_info[1].pQueuePriorities = queue_priorities.data(); 295 296 dev_info.queueCreateInfoCount = 2; 297 } else { 298 dev_info.queueCreateInfoCount = 1; 299 } 300 301 dev_info.pQueueCreateInfos = queue_info.data(); 302 303 dev_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions_.size()); 304 dev_info.ppEnabledExtensionNames = device_extensions_.data(); 305 306 // disable all features 307 VkPhysicalDeviceFeatures features = {}; 308 dev_info.pEnabledFeatures = &features; 309 310 vk::assert_success(vk::CreateDevice(ctx_.physical_dev, &dev_info, nullptr, &ctx_.dev)); 311 } 312 313 void Shell::create_back_buffers() 314 { 315 VkSemaphoreCreateInfo sem_info = {}; 316 sem_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 317 318 VkFenceCreateInfo fence_info = {}; 319 fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 320 fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; 321 322 // BackBuffer is used to track which swapchain image and its associated 323 // sync primitives are busy. Having more BackBuffer's than swapchain 324 // images may allows us to replace CPU wait on present_fence by GPU wait 325 // on acquire_semaphore. 326 const int count = settings_.back_buffer_count + 1; 327 for (int i = 0; i < count; i++) { 328 BackBuffer buf = {}; 329 vk::assert_success(vk::CreateSemaphore(ctx_.dev, &sem_info, nullptr, &buf.acquire_semaphore)); 330 vk::assert_success(vk::CreateSemaphore(ctx_.dev, &sem_info, nullptr, &buf.render_semaphore)); 331 vk::assert_success(vk::CreateFence(ctx_.dev, &fence_info, nullptr, &buf.present_fence)); 332 333 ctx_.back_buffers.push(buf); 334 } 335 } 336 337 void Shell::destroy_back_buffers() 338 { 339 while (!ctx_.back_buffers.empty()) { 340 const auto &buf = ctx_.back_buffers.front(); 341 342 vk::DestroySemaphore(ctx_.dev, buf.acquire_semaphore, nullptr); 343 vk::DestroySemaphore(ctx_.dev, buf.render_semaphore, nullptr); 344 vk::DestroyFence(ctx_.dev, buf.present_fence, nullptr); 345 346 ctx_.back_buffers.pop(); 347 } 348 } 349 350 void Shell::create_swapchain() 351 { 352 ctx_.surface = create_surface(ctx_.instance); 353 354 VkBool32 supported; 355 vk::assert_success(vk::GetPhysicalDeviceSurfaceSupportKHR(ctx_.physical_dev, 356 ctx_.present_queue_family, ctx_.surface, &supported)); 357 // this should be guaranteed by the platform-specific can_present call 358 assert(supported); 359 360 std::vector<VkSurfaceFormatKHR> formats; 361 vk::get(ctx_.physical_dev, ctx_.surface, formats); 362 ctx_.format = formats[0]; 363 364 // defer to resize_swapchain() 365 ctx_.swapchain = VK_NULL_HANDLE; 366 ctx_.extent.width = (uint32_t) -1; 367 ctx_.extent.height = (uint32_t) -1; 368 } 369 370 void Shell::destroy_swapchain() 371 { 372 if (ctx_.swapchain != VK_NULL_HANDLE) { 373 game_.detach_swapchain(); 374 375 vk::DestroySwapchainKHR(ctx_.dev, ctx_.swapchain, nullptr); 376 ctx_.swapchain = VK_NULL_HANDLE; 377 } 378 379 vk::DestroySurfaceKHR(ctx_.instance, ctx_.surface, nullptr); 380 ctx_.surface = VK_NULL_HANDLE; 381 } 382 383 void Shell::resize_swapchain(uint32_t width_hint, uint32_t height_hint) 384 { 385 VkSurfaceCapabilitiesKHR caps; 386 vk::assert_success(vk::GetPhysicalDeviceSurfaceCapabilitiesKHR(ctx_.physical_dev, 387 ctx_.surface, &caps)); 388 389 VkExtent2D extent = caps.currentExtent; 390 // use the hints 391 if (extent.width == (uint32_t) -1) { 392 extent.width = width_hint; 393 extent.height = height_hint; 394 } 395 // clamp width; to protect us from broken hints? 396 if (extent.width < caps.minImageExtent.width) 397 extent.width = caps.minImageExtent.width; 398 else if (extent.width > caps.maxImageExtent.width) 399 extent.width = caps.maxImageExtent.width; 400 // clamp height 401 if (extent.height < caps.minImageExtent.height) 402 extent.height = caps.minImageExtent.height; 403 else if (extent.height > caps.maxImageExtent.height) 404 extent.height = caps.maxImageExtent.height; 405 406 if (ctx_.extent.width == extent.width && ctx_.extent.height == extent.height) 407 return; 408 409 uint32_t image_count = settings_.back_buffer_count; 410 if (image_count < caps.minImageCount) 411 image_count = caps.minImageCount; 412 else if (image_count > caps.maxImageCount) 413 image_count = caps.maxImageCount; 414 415 assert(caps.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); 416 assert(caps.supportedTransforms & caps.currentTransform); 417 assert(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | 418 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); 419 VkCompositeAlphaFlagBitsKHR composite_alpha = 420 (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ? 421 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 422 423 std::vector<VkPresentModeKHR> modes; 424 vk::get(ctx_.physical_dev, ctx_.surface, modes); 425 426 // FIFO is the only mode universally supported 427 VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; 428 for (auto m : modes) { 429 if ((settings_.vsync && m == VK_PRESENT_MODE_MAILBOX_KHR) || 430 (!settings_.vsync && m == VK_PRESENT_MODE_IMMEDIATE_KHR)) { 431 mode = m; 432 break; 433 } 434 } 435 436 VkSwapchainCreateInfoKHR swapchain_info = {}; 437 swapchain_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 438 swapchain_info.surface = ctx_.surface; 439 swapchain_info.minImageCount = image_count; 440 swapchain_info.imageFormat = ctx_.format.format; 441 swapchain_info.imageColorSpace = ctx_.format.colorSpace; 442 swapchain_info.imageExtent = extent; 443 swapchain_info.imageArrayLayers = 1; 444 swapchain_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; 445 446 std::vector<uint32_t> queue_families(1, ctx_.game_queue_family); 447 if (ctx_.game_queue_family != ctx_.present_queue_family) { 448 queue_families.push_back(ctx_.present_queue_family); 449 450 swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; 451 swapchain_info.queueFamilyIndexCount = (uint32_t)queue_families.size(); 452 swapchain_info.pQueueFamilyIndices = queue_families.data(); 453 } else { 454 swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 455 } 456 457 swapchain_info.preTransform = caps.currentTransform;; 458 swapchain_info.compositeAlpha = composite_alpha; 459 swapchain_info.presentMode = mode; 460 swapchain_info.clipped = true; 461 swapchain_info.oldSwapchain = ctx_.swapchain; 462 463 vk::assert_success(vk::CreateSwapchainKHR(ctx_.dev, &swapchain_info, nullptr, &ctx_.swapchain)); 464 ctx_.extent = extent; 465 466 // destroy the old swapchain 467 if (swapchain_info.oldSwapchain != VK_NULL_HANDLE) { 468 game_.detach_swapchain(); 469 470 vk::DeviceWaitIdle(ctx_.dev); 471 vk::DestroySwapchainKHR(ctx_.dev, swapchain_info.oldSwapchain, nullptr); 472 } 473 474 game_.attach_swapchain(); 475 } 476 477 void Shell::add_game_time(float time) 478 { 479 int max_ticks = 3; 480 481 if (!settings_.no_tick) 482 game_time_ += time; 483 484 while (game_time_ >= game_tick_ && max_ticks--) { 485 game_.on_tick(); 486 game_time_ -= game_tick_; 487 } 488 } 489 490 void Shell::acquire_back_buffer() 491 { 492 // acquire just once when not presenting 493 if (settings_.no_present && 494 ctx_.acquired_back_buffer.acquire_semaphore != VK_NULL_HANDLE) 495 return; 496 497 auto &buf = ctx_.back_buffers.front(); 498 499 // wait until acquire and render semaphores are waited/unsignaled 500 vk::assert_success(vk::WaitForFences(ctx_.dev, 1, &buf.present_fence, 501 true, UINT64_MAX)); 502 // reset the fence 503 vk::assert_success(vk::ResetFences(ctx_.dev, 1, &buf.present_fence)); 504 505 vk::assert_success(vk::AcquireNextImageKHR(ctx_.dev, ctx_.swapchain, 506 UINT64_MAX, buf.acquire_semaphore, VK_NULL_HANDLE, 507 &buf.image_index)); 508 509 ctx_.acquired_back_buffer = buf; 510 ctx_.back_buffers.pop(); 511 } 512 513 void Shell::present_back_buffer() 514 { 515 const auto &buf = ctx_.acquired_back_buffer; 516 517 if (!settings_.no_render) 518 game_.on_frame(game_time_ / game_tick_); 519 520 if (settings_.no_present) { 521 fake_present(); 522 return; 523 } 524 525 VkPresentInfoKHR present_info = {}; 526 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 527 present_info.waitSemaphoreCount = 1; 528 present_info.pWaitSemaphores = (settings_.no_render) ? 529 &buf.acquire_semaphore : &buf.render_semaphore; 530 present_info.swapchainCount = 1; 531 present_info.pSwapchains = &ctx_.swapchain; 532 present_info.pImageIndices = &buf.image_index; 533 534 vk::assert_success(vk::QueuePresentKHR(ctx_.present_queue, &present_info)); 535 536 vk::assert_success(vk::QueueSubmit(ctx_.present_queue, 0, nullptr, buf.present_fence)); 537 ctx_.back_buffers.push(buf); 538 } 539 540 void Shell::fake_present() 541 { 542 const auto &buf = ctx_.acquired_back_buffer; 543 544 assert(settings_.no_present); 545 546 // wait render semaphore and signal acquire semaphore 547 if (!settings_.no_render) { 548 VkPipelineStageFlags stage = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 549 VkSubmitInfo submit_info = {}; 550 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 551 submit_info.waitSemaphoreCount = 1; 552 submit_info.pWaitSemaphores = &buf.render_semaphore; 553 submit_info.pWaitDstStageMask = &stage; 554 submit_info.signalSemaphoreCount = 1; 555 submit_info.pSignalSemaphores = &buf.acquire_semaphore; 556 vk::assert_success(vk::QueueSubmit(ctx_.game_queue, 1, &submit_info, VK_NULL_HANDLE)); 557 } 558 559 // push the buffer back just once for Shell::cleanup_vk 560 if (buf.acquire_semaphore != ctx_.back_buffers.back().acquire_semaphore) 561 ctx_.back_buffers.push(buf); 562 } 563