blob: 669359855d9c5f305810608d1af0ae37779b8674 [file] [log] [blame]
// Copyright 2017 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 "lib/escher/vk/vulkan_instance.h"
#include <set>
#include "lib/escher/impl/vulkan_utils.h"
#include "lib/fxl/logging.h"
namespace escher {
template <typename FuncT>
static FuncT GetInstanceProcAddr(vk::Instance inst, const char* func_name) {
FuncT func = reinterpret_cast<FuncT>(inst.getProcAddr(func_name));
FXL_CHECK(func) << "Could not find Vulkan Instance ProcAddr: " << func_name;
return func;
}
#define GET_INSTANCE_PROC_ADDR(XXX) \
XXX = GetInstanceProcAddr<PFN_vk##XXX>(instance, "vk" #XXX)
VulkanInstance::ProcAddrs::ProcAddrs(vk::Instance instance,
bool requires_surface) {
GET_INSTANCE_PROC_ADDR(CreateDebugReportCallbackEXT);
GET_INSTANCE_PROC_ADDR(DestroyDebugReportCallbackEXT);
if (requires_surface) {
GET_INSTANCE_PROC_ADDR(GetPhysicalDeviceSurfaceSupportKHR);
}
}
fxl::RefPtr<VulkanInstance> VulkanInstance::New(Params params) {
params.extension_names.insert(
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
#ifdef __Fuchsia__
// TODO(ES-143): It's quite possible that this would work on Linux if we
// uploaded a new Vulkan SDK to the cloud, but there are obstacles to doing
// this immediately, hence this workaround. Or, it may be the NVIDIA Vulkan
// driver itself.
params.extension_names.insert(
VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME);
#endif
FXL_DCHECK(ValidateLayers(params.layer_names));
FXL_DCHECK(ValidateExtensions(params.extension_names, params.layer_names));
// Gather names of layers/extensions to populate InstanceCreateInfo.
std::vector<const char *> layer_names;
for (auto &layer : params.layer_names) {
layer_names.push_back(layer.c_str());
}
std::vector<const char *> extension_names;
for (auto &extension : params.extension_names) {
extension_names.push_back(extension.c_str());
}
vk::InstanceCreateInfo info;
info.enabledLayerCount = layer_names.size();
info.ppEnabledLayerNames = layer_names.data();
info.enabledExtensionCount = extension_names.size();
info.ppEnabledExtensionNames = extension_names.data();
auto result = vk::createInstance(info);
if (result.result != vk::Result::eSuccess) {
FXL_LOG(WARNING) << "Could not create Vulkan Instance.";
return fxl::RefPtr<VulkanInstance>();
}
return fxl::AdoptRef(new VulkanInstance(result.value, std::move(params)));
}
VulkanInstance::VulkanInstance(vk::Instance instance, Params params)
: instance_(instance),
params_(std::move(params)),
proc_addrs_(instance_, params_.requires_surface) {}
VulkanInstance::~VulkanInstance() { instance_.destroy(); }
bool VulkanInstance::ValidateLayers(
const std::set<std::string> &required_layer_names) {
auto properties =
ESCHER_CHECKED_VK_RESULT(vk::enumerateInstanceLayerProperties());
for (auto &name : required_layer_names) {
auto found = std::find_if(properties.begin(), properties.end(),
[&name](vk::LayerProperties &layer) {
return !strncmp(layer.layerName, name.c_str(),
VK_MAX_EXTENSION_NAME_SIZE);
});
if (found == properties.end()) {
FXL_LOG(WARNING) << "Vulkan has no instance layer named: " << name;
return false;
}
}
return true;
}
// Helper for ValidateExtensions().
static bool ValidateExtension(
const std::string name,
const std::vector<vk::ExtensionProperties> &base_extensions,
const std::set<std::string> &required_layer_names) {
auto found =
std::find_if(base_extensions.begin(), base_extensions.end(),
[&name](const vk::ExtensionProperties &extension) {
return !strncmp(extension.extensionName, name.c_str(),
VK_MAX_EXTENSION_NAME_SIZE);
});
if (found != base_extensions.end())
return true;
// Didn't find the extension in the base list of extensions. Perhaps it is
// implemented in a layer.
for (auto &layer_name : required_layer_names) {
auto layer_extensions = ESCHER_CHECKED_VK_RESULT(
vk::enumerateInstanceExtensionProperties(layer_name));
FXL_LOG(INFO) << "Looking for Vulkan instance extension: " << name
<< " in layer: " << layer_name;
auto found =
std::find_if(layer_extensions.begin(), layer_extensions.end(),
[&name](vk::ExtensionProperties &extension) {
return !strncmp(extension.extensionName, name.c_str(),
VK_MAX_EXTENSION_NAME_SIZE);
});
if (found != layer_extensions.end())
return true;
}
return false;
}
bool VulkanInstance::ValidateExtensions(
const std::set<std::string> &required_extension_names,
const std::set<std::string> &required_layer_names) {
auto extensions =
ESCHER_CHECKED_VK_RESULT(vk::enumerateInstanceExtensionProperties());
for (auto &name : required_extension_names) {
if (!ValidateExtension(name, extensions, required_layer_names)) {
FXL_LOG(WARNING) << "Vulkan has no instance extension named: " << name;
return false;
}
}
return true;
}
}; // namespace escher