| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/graphics/examples/vkproto/common/instance.h" |
| |
| #include <iostream> |
| #include <memory> |
| #include <vector> |
| |
| #if USE_GLFW |
| #include <GLFW/glfw3.h> |
| #endif |
| #include "src/graphics/examples/vkproto/common/utils.h" |
| |
| #include <vulkan/vulkan.hpp> |
| |
| namespace { |
| |
| const std::vector<const char *> s_required_surface_props = { |
| VK_KHR_SURFACE_EXTENSION_NAME, |
| #ifdef __Fuchsia__ |
| VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME, |
| #endif |
| }; |
| |
| void PrintProps(const std::vector<const char *> &props, const char *msg) { |
| printf("%s\n", msg); |
| for (const auto &prop : props) { |
| printf("\t%s\n", prop); |
| } |
| printf("\n"); |
| } |
| |
| #if USE_GLFW |
| std::vector<const char *> GetSurfaceExtensionsGLFW() { |
| uint32_t num_extensions = 0; |
| |
| #if __linux__ |
| // Linux variant of glfwGetRequiredInstanceExtensions() isn't returning |
| // the required extensions. Special case until glfw is updated / fixed. |
| // https://fxbug.dev/42070404. |
| const char *glfw_extensions[] = {"VK_KHR_surface", "VK_KHR_xcb_surface"}; |
| num_extensions = 2; |
| #else |
| const char **glfw_extensions = glfwGetRequiredInstanceExtensions(&num_extensions); |
| #endif |
| |
| printf("\nGLFW Instance Extensions Required\n"); |
| for (int i = 0; i < num_extensions; ++i) { |
| printf("\t%s\n", glfw_extensions[i]); |
| } |
| printf("\n"); |
| |
| std::vector<const char *> extensions(glfw_extensions, glfw_extensions + num_extensions); |
| |
| return extensions; |
| } |
| #else |
| std::vector<const char *> GetSurfaceExtensionsPrivate() { |
| std::vector<const char *> extensions; |
| #ifdef __Fuchsia__ |
| const char *kMagmaLayer = "VK_LAYER_FUCHSIA_imagepipe_swapchain_fb"; |
| #else |
| const char *kMagmaLayer = nullptr; |
| #endif |
| |
| std::vector<const char *> required_props = s_required_surface_props; |
| |
| if (FindRequiredProperties(s_required_surface_props, vkp::INSTANCE_EXT_PROP, kMagmaLayer)) { |
| extensions.insert(extensions.end(), required_props.begin(), required_props.end()); |
| } |
| |
| return extensions; |
| } |
| #endif |
| |
| void AddRequiredSurfaceExtensions(std::vector<const char *> *extensions) { |
| std::vector<const char *> required_extensions; |
| #if USE_GLFW |
| required_extensions = GetSurfaceExtensionsGLFW(); |
| #else |
| required_extensions = GetSurfaceExtensionsPrivate(); |
| #endif |
| |
| if (!required_extensions.empty()) |
| extensions->insert(extensions->end(), required_extensions.begin(), required_extensions.end()); |
| } |
| |
| } // namespace |
| |
| namespace vkp { |
| |
| Instance::Instance(const vk::InstanceCreateInfo &instance_info, bool validation_layers_enabled, |
| bool swapchain_enabled, std::vector<const char *> extensions, |
| std::vector<const char *> layers, |
| vk::Optional<const vk::AllocationCallbacks> allocator) |
| : instance_info_(instance_info), |
| validation_layers_enabled_(validation_layers_enabled), |
| swapchain_enabled_(swapchain_enabled), |
| extensions_(std::move(extensions)), |
| layers_(std::move(layers)), |
| allocator_(allocator) {} |
| |
| Instance::Instance(Instance &&other) noexcept |
| : initialized_(other.initialized_), |
| instance_info_(other.instance_info_), |
| validation_layers_enabled_(other.validation_layers_enabled_), |
| swapchain_enabled_(other.swapchain_enabled_), |
| extensions_(std::move(other.extensions_)), |
| layers_(std::move(other.layers_)), |
| allocator_(other.allocator_) {} |
| |
| Instance::~Instance() { |
| if (initialized_) { |
| initialized_ = false; |
| } |
| } |
| |
| bool Instance::Init() { |
| RTN_IF_MSG(false, (initialized_ == true), "Already initialized.\n"); |
| |
| // Extensions |
| if (swapchain_enabled_) { |
| AddRequiredSurfaceExtensions(&extensions_); |
| } |
| |
| if (validation_layers_enabled_) { |
| extensions_.emplace_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| } |
| |
| // Require api version 1.1 if it hasn't been set. |
| vk::ApplicationInfo app_info; |
| app_info.apiVersion = VK_MAKE_VERSION(1, 1, 0); |
| if (instance_info_.pApplicationInfo == nullptr) { |
| instance_info_.pApplicationInfo = &app_info; |
| } else if (instance_info_.pApplicationInfo->apiVersion == 0) { |
| RTN_MSG(false, |
| "Must set vk::ApplicationInfo::apiVersion when customizing vk::ApplicationInfo.\n"); |
| } |
| |
| // Layers |
| #ifdef __Fuchsia__ |
| if (swapchain_enabled_) { |
| layers_.emplace_back("VK_LAYER_FUCHSIA_imagepipe_swapchain_fb"); |
| } |
| #endif |
| |
| if (validation_layers_enabled_) { |
| layers_.emplace_back("VK_LAYER_KHRONOS_validation"); |
| |
| validation_enables_.push_back(vk::ValidationFeatureEnableEXT::eSynchronizationValidation); |
| validation_features_.setEnabledValidationFeatures(validation_enables_); |
| validation_features_.pNext = instance_info_.pNext; |
| instance_info_.pNext = &validation_features_; |
| } |
| |
| if (!FindRequiredProperties(layers_, vkp::INSTANCE_LAYER_PROP)) |
| return false; |
| |
| if (instance_info_.ppEnabledLayerNames && instance_info_.enabledLayerCount) { |
| // Tack on custom layers. |
| std::copy(instance_info_.ppEnabledLayerNames, |
| instance_info_.ppEnabledLayerNames + instance_info_.enabledLayerCount, |
| std::back_inserter(layers_)); |
| } |
| instance_info_.enabledLayerCount = static_cast<uint32_t>(layers_.size()); |
| instance_info_.ppEnabledLayerNames = layers_.data(); |
| |
| if (instance_info_.ppEnabledExtensionNames && instance_info_.enabledExtensionCount) { |
| // Tack on custom extensions. |
| std::copy(instance_info_.ppEnabledExtensionNames, |
| instance_info_.ppEnabledExtensionNames + instance_info_.enabledExtensionCount, |
| std::back_inserter(extensions_)); |
| } |
| instance_info_.enabledExtensionCount = static_cast<uint32_t>(extensions_.size()); |
| instance_info_.ppEnabledExtensionNames = extensions_.data(); |
| |
| PrintProps(layers_, "Enabled Layers"); |
| PrintProps(extensions_, "Enabled Instance Extensions"); |
| |
| vk::Instance *instance = new vk::Instance; |
| vk::Result r_instance = vk::createInstance(&instance_info_, nullptr /* pAllocator */, instance); |
| RTN_IF_VKH_ERR(false, r_instance, "Failed to create instance\n"); |
| instance_.reset(instance, [](vk::Instance *instance) { |
| if (instance) { |
| instance->destroy(); |
| delete instance; |
| } |
| }); |
| |
| initialized_ = true; |
| return true; |
| } |
| |
| std::shared_ptr<vk::Instance> Instance::shared() { |
| RTN_IF_MSG(nullptr, !initialized_, "Instance hasn't been initialized"); |
| return instance_; |
| } |
| |
| const vk::Instance &Instance::get() const { return *instance_; } |
| |
| Instance::Builder::Builder() : allocator_(nullptr) {} |
| |
| Instance::Builder &Instance::Builder::set_allocator( |
| const vk::Optional<const vk::AllocationCallbacks> &v) { |
| allocator_ = v; |
| return *this; |
| } |
| |
| Instance::Builder &Instance::Builder::set_instance_info(const vk::InstanceCreateInfo &v) { |
| instance_info_ = v; |
| return *this; |
| } |
| |
| Instance::Builder &Instance::Builder::set_validation_layers_enabled(bool v) { |
| validation_layers_enabled_ = v; |
| return *this; |
| } |
| |
| Instance::Builder &Instance::Builder::set_swapchain_enabled(bool v) { |
| swapchain_enabled_ = v; |
| return *this; |
| } |
| |
| Instance::Builder &Instance::Builder::set_extensions(std::vector<const char *> v) { |
| extensions_ = std::move(v); |
| return *this; |
| } |
| |
| Instance::Builder &Instance::Builder::set_layers(std::vector<const char *> v) { |
| layers_ = std::move(v); |
| return *this; |
| } |
| |
| std::unique_ptr<Instance> Instance::Builder::Unique() const { |
| auto instance = std::make_unique<Instance>(instance_info_, validation_layers_enabled_, |
| swapchain_enabled_, extensions_, layers_, allocator_); |
| if (!instance->Init()) { |
| RTN_MSG(nullptr, "Failed to initialize Instance.\n") |
| } |
| return instance; |
| } |
| |
| std::shared_ptr<Instance> Instance::Builder::Shared() const { |
| auto instance = std::make_shared<Instance>(instance_info_, validation_layers_enabled_, |
| swapchain_enabled_, extensions_, layers_, allocator_); |
| if (!instance->Init()) { |
| RTN_MSG(nullptr, "Failed to initialize Instance.\n") |
| } |
| return instance; |
| } |
| |
| Instance Instance::Builder::Build() const { |
| vkp::Instance instance(instance_info_, validation_layers_enabled_, swapchain_enabled_, |
| extensions_, layers_, allocator_); |
| if (!instance.Init()) { |
| RTN_MSG(instance, "Failed to initialize Instance.\n") |
| } |
| return instance; |
| } |
| |
| } // namespace vkp |