vulkan_application.cc 6.8 KB
Newer Older
M
Michael Goderbauer 已提交
1
// Copyright 2013 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "vulkan_application.h"
6 7 8 9

#include <utility>
#include <vector>

10 11 12
#include "vulkan_device.h"
#include "vulkan_proc_table.h"
#include "vulkan_utilities.h"
13 14 15 16

namespace vulkan {

VulkanApplication::VulkanApplication(
17
    VulkanProcTable& p_vk,  // NOLINT
18 19 20
    const std::string& application_name,
    std::vector<std::string> enabled_extensions,
    uint32_t application_version,
21 22 23 24 25 26
    uint32_t api_version,
    bool enable_validation_layers)
    : vk(p_vk),
      api_version_(api_version),
      valid_(false),
      enable_validation_layers_(enable_validation_layers) {
27
  // Check if we want to enable debugging.
28 29
  std::vector<VkExtensionProperties> supported_extensions =
      GetSupportedInstanceExtensions(vk);
30
  bool enable_instance_debugging =
31
      enable_validation_layers_ &&
32 33
      ExtensionSupported(supported_extensions,
                         VulkanDebugReport::DebugExtensionName());
34 35 36 37 38 39

  // Configure extensions.

  if (enable_instance_debugging) {
    enabled_extensions.emplace_back(VulkanDebugReport::DebugExtensionName());
  }
40 41 42
#if OS_FUCHSIA
  if (ExtensionSupported(supported_extensions,
                         VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) {
43 44 45 46 47
    // VK_KHR_get_physical_device_properties2 is a dependency of the memory
    // capabilities extension, so the validation layers require that it be
    // enabled.
    enabled_extensions.emplace_back(
        VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
48 49 50 51
    enabled_extensions.emplace_back(
        VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
  }
#endif
52 53 54 55 56 57 58 59 60

  const char* extensions[enabled_extensions.size()];

  for (size_t i = 0; i < enabled_extensions.size(); i++) {
    extensions[i] = enabled_extensions[i].c_str();
  }

  // Configure layers.

61 62
  const std::vector<std::string> enabled_layers =
      InstanceLayersToEnable(vk, enable_validation_layers_);
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

  const char* layers[enabled_layers.size()];

  for (size_t i = 0; i < enabled_layers.size(); i++) {
    layers[i] = enabled_layers[i].c_str();
  }

  // Configure init structs.

  const VkApplicationInfo info = {
      .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
      .pNext = nullptr,
      .pApplicationName = application_name.c_str(),
      .applicationVersion = application_version,
      .pEngineName = "FlutterEngine",
      .engineVersion = VK_MAKE_VERSION(1, 0, 0),
      .apiVersion = api_version_,
  };

  const VkInstanceCreateInfo create_info = {
      .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
      .pNext = nullptr,
      .flags = 0,
      .pApplicationInfo = &info,
      .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
      .ppEnabledLayerNames = layers,
      .enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()),
      .ppEnabledExtensionNames = extensions,
  };

  // Perform initialization.

  VkInstance instance = VK_NULL_HANDLE;

  if (VK_CALL_LOG_ERROR(vk.CreateInstance(&create_info, nullptr, &instance)) !=
      VK_SUCCESS) {
99
    FML_DLOG(INFO) << "Could not create application instance.";
100 101 102
    return;
  }

103
  // Now that we have an instance, set up instance proc table entries.
104
  if (!vk.SetupInstanceProcAddresses(instance)) {
105
    FML_DLOG(INFO) << "Could not set up instance proc addresses.";
106 107 108 109
    return;
  }

  instance_ = {instance, [this](VkInstance i) {
110
                 FML_DLOG(INFO) << "Destroying Vulkan instance";
111 112 113 114 115 116
                 vk.DestroyInstance(i, nullptr);
               }};

  if (enable_instance_debugging) {
    auto debug_report = std::make_unique<VulkanDebugReport>(vk, instance_);
    if (!debug_report->IsValid()) {
117
      FML_DLOG(INFO) << "Vulkan debugging was enabled but could not be set up "
118
                        "for this instance.";
119 120
    } else {
      debug_report_ = std::move(debug_report);
121
      FML_DLOG(INFO) << "Debug reporting is enabled.";
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
    }
  }

  valid_ = true;
}

VulkanApplication::~VulkanApplication() = default;

bool VulkanApplication::IsValid() const {
  return valid_;
}

uint32_t VulkanApplication::GetAPIVersion() const {
  return api_version_;
}

138
const VulkanHandle<VkInstance>& VulkanApplication::GetInstance() const {
139 140 141
  return instance_;
}

142 143 144 145
void VulkanApplication::ReleaseInstanceOwnership() {
  instance_.ReleaseOwnership();
}

146 147 148 149 150 151 152 153
std::vector<VkPhysicalDevice> VulkanApplication::GetPhysicalDevices() const {
  if (!IsValid()) {
    return {};
  }

  uint32_t device_count = 0;
  if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices(instance_, &device_count,
                                                    nullptr)) != VK_SUCCESS) {
154
    FML_DLOG(INFO) << "Could not enumerate physical device.";
155 156 157 158 159
    return {};
  }

  if (device_count == 0) {
    // No available devices.
160
    FML_DLOG(INFO) << "No physical devices found.";
161 162 163 164 165 166 167 168 169
    return {};
  }

  std::vector<VkPhysicalDevice> physical_devices;

  physical_devices.resize(device_count);

  if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices(
          instance_, &device_count, physical_devices.data())) != VK_SUCCESS) {
170
    FML_DLOG(INFO) << "Could not enumerate physical device.";
171 172 173 174 175 176 177 178 179
    return {};
  }

  return physical_devices;
}

std::unique_ptr<VulkanDevice>
VulkanApplication::AcquireFirstCompatibleLogicalDevice() const {
  for (auto device_handle : GetPhysicalDevices()) {
180 181
    auto logical_device = std::make_unique<VulkanDevice>(
        vk, device_handle, enable_validation_layers_);
182 183 184 185
    if (logical_device->IsValid()) {
      return logical_device;
    }
  }
186
  FML_DLOG(INFO) << "Could not acquire compatible logical device.";
187 188 189
  return nullptr;
}

190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
std::vector<VkExtensionProperties>
VulkanApplication::GetSupportedInstanceExtensions(
    const VulkanProcTable& vk) const {
  if (!vk.EnumerateInstanceExtensionProperties) {
    return std::vector<VkExtensionProperties>();
  }

  uint32_t count = 0;
  if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties(
          nullptr, &count, nullptr)) != VK_SUCCESS) {
    return std::vector<VkExtensionProperties>();
  }

  if (count == 0) {
    return std::vector<VkExtensionProperties>();
  }

  std::vector<VkExtensionProperties> properties;
  properties.resize(count);
  if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties(
          nullptr, &count, properties.data())) != VK_SUCCESS) {
    return std::vector<VkExtensionProperties>();
  }

  return properties;
}

bool VulkanApplication::ExtensionSupported(
    const std::vector<VkExtensionProperties>& supported_instance_extensions,
    std::string extension_name) {
  uint32_t count = supported_instance_extensions.size();
  for (size_t i = 0; i < count; i++) {
    if (strncmp(supported_instance_extensions[i].extensionName,
                extension_name.c_str(), extension_name.size()) == 0) {
      return true;
    }
  }

  return false;
}

231
}  // namespace vulkan