Flutter Engine
vulkan_application.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "vulkan_application.h"
6 
7 #include <utility>
8 #include <vector>
9 
10 #include "vulkan_device.h"
11 #include "vulkan_proc_table.h"
12 #include "vulkan_utilities.h"
13 
14 namespace vulkan {
15 
17  VulkanProcTable& p_vk, // NOLINT
18  const std::string& application_name,
19  std::vector<std::string> enabled_extensions,
20  uint32_t application_version,
21  uint32_t api_version,
22  bool enable_validation_layers)
23  : vk(p_vk),
24  api_version_(api_version),
25  valid_(false),
26  enable_validation_layers_(enable_validation_layers) {
27  // Check if we want to enable debugging.
28  std::vector<VkExtensionProperties> supported_extensions =
29  GetSupportedInstanceExtensions(vk);
30  bool enable_instance_debugging =
31  enable_validation_layers_ &&
32  ExtensionSupported(supported_extensions,
34 
35  // Configure extensions.
36 
37  if (enable_instance_debugging) {
38  enabled_extensions.emplace_back(VulkanDebugReport::DebugExtensionName());
39  }
40 #if OS_FUCHSIA
41  if (ExtensionSupported(supported_extensions,
42  VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) {
43  // VK_KHR_get_physical_device_properties2 is a dependency of the memory
44  // capabilities extension, so the validation layers require that it be
45  // enabled.
46  enabled_extensions.emplace_back(
47  VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
48  enabled_extensions.emplace_back(
49  VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
50  }
51 #endif
52 
53  const char* extensions[enabled_extensions.size()];
54 
55  for (size_t i = 0; i < enabled_extensions.size(); i++) {
56  extensions[i] = enabled_extensions[i].c_str();
57  }
58 
59  // Configure layers.
60 
61  const std::vector<std::string> enabled_layers =
62  InstanceLayersToEnable(vk, enable_validation_layers_);
63 
64  const char* layers[enabled_layers.size()];
65 
66  for (size_t i = 0; i < enabled_layers.size(); i++) {
67  layers[i] = enabled_layers[i].c_str();
68  }
69 
70  // Configure init structs.
71 
72  const VkApplicationInfo info = {
73  .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
74  .pNext = nullptr,
75  .pApplicationName = application_name.c_str(),
76  .applicationVersion = application_version,
77  .pEngineName = "FlutterEngine",
78  .engineVersion = VK_MAKE_VERSION(1, 0, 0),
79  .apiVersion = api_version_,
80  };
81 
82  const VkInstanceCreateInfo create_info = {
83  .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
84  .pNext = nullptr,
85  .flags = 0,
86  .pApplicationInfo = &info,
87  .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
88  .ppEnabledLayerNames = layers,
89  .enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()),
90  .ppEnabledExtensionNames = extensions,
91  };
92 
93  // Perform initialization.
94 
95  VkInstance instance = VK_NULL_HANDLE;
96 
97  if (VK_CALL_LOG_ERROR(vk.CreateInstance(&create_info, nullptr, &instance)) !=
98  VK_SUCCESS) {
99  FML_DLOG(INFO) << "Could not create application instance.";
100  return;
101  }
102 
103  // Now that we have an instance, setup instance proc table entries.
104  if (!vk.SetupInstanceProcAddresses(instance)) {
105  FML_DLOG(INFO) << "Could not setup instance proc addresses.";
106  return;
107  }
108 
109  instance_ = {instance, [this](VkInstance i) {
110  FML_DLOG(INFO) << "Destroying Vulkan instance";
111  vk.DestroyInstance(i, nullptr);
112  }};
113 
114  if (enable_instance_debugging) {
115  auto debug_report = std::make_unique<VulkanDebugReport>(vk, instance_);
116  if (!debug_report->IsValid()) {
117  FML_DLOG(INFO) << "Vulkan debugging was enabled but could not be setup "
118  "for this instance.";
119  } else {
120  debug_report_ = std::move(debug_report);
121  FML_DLOG(INFO) << "Debug reporting is enabled.";
122  }
123  }
124 
125  valid_ = true;
126 }
127 
129 
131  return valid_;
132 }
133 
135  return api_version_;
136 }
137 
139  return instance_;
140 }
141 
143  instance_.ReleaseOwnership();
144 }
145 
146 std::vector<VkPhysicalDevice> VulkanApplication::GetPhysicalDevices() const {
147  if (!IsValid()) {
148  return {};
149  }
150 
151  uint32_t device_count = 0;
152  if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices(instance_, &device_count,
153  nullptr)) != VK_SUCCESS) {
154  FML_DLOG(INFO) << "Could not enumerate physical device.";
155  return {};
156  }
157 
158  if (device_count == 0) {
159  // No available devices.
160  FML_DLOG(INFO) << "No physical devices found.";
161  return {};
162  }
163 
164  std::vector<VkPhysicalDevice> physical_devices;
165 
166  physical_devices.resize(device_count);
167 
168  if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices(
169  instance_, &device_count, physical_devices.data())) != VK_SUCCESS) {
170  FML_DLOG(INFO) << "Could not enumerate physical device.";
171  return {};
172  }
173 
174  return physical_devices;
175 }
176 
177 std::unique_ptr<VulkanDevice>
179  for (auto device_handle : GetPhysicalDevices()) {
180  auto logical_device = std::make_unique<VulkanDevice>(
181  vk, device_handle, enable_validation_layers_);
182  if (logical_device->IsValid()) {
183  return logical_device;
184  }
185  }
186  FML_DLOG(INFO) << "Could not acquire compatible logical device.";
187  return nullptr;
188 }
189 
190 std::vector<VkExtensionProperties>
191 VulkanApplication::GetSupportedInstanceExtensions(
192  const VulkanProcTable& vk) const {
193  if (!vk.EnumerateInstanceExtensionProperties) {
194  return std::vector<VkExtensionProperties>();
195  }
196 
197  uint32_t count = 0;
198  if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties(
199  nullptr, &count, nullptr)) != VK_SUCCESS) {
200  return std::vector<VkExtensionProperties>();
201  }
202 
203  if (count == 0) {
204  return std::vector<VkExtensionProperties>();
205  }
206 
207  std::vector<VkExtensionProperties> properties;
208  properties.resize(count);
209  if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties(
210  nullptr, &count, properties.data())) != VK_SUCCESS) {
211  return std::vector<VkExtensionProperties>();
212  }
213 
214  return properties;
215 }
216 
217 bool VulkanApplication::ExtensionSupported(
218  const std::vector<VkExtensionProperties>& supported_instance_extensions,
219  std::string extension_name) {
220  uint32_t count = supported_instance_extensions.size();
221  for (size_t i = 0; i < count; i++) {
222  if (strncmp(supported_instance_extensions[i].extensionName,
223  extension_name.c_str(), extension_name.size()) == 0) {
224  return true;
225  }
226  }
227 
228  return false;
229 }
230 
231 } // namespace vulkan
bool SetupInstanceProcAddresses(const VulkanHandle< VkInstance > &instance)
VulkanApplication(VulkanProcTable &vk, const std::string &application_name, std::vector< std::string > enabled_extensions, uint32_t application_version=VK_MAKE_VERSION(1, 0, 0), uint32_t api_version=VK_MAKE_VERSION(1, 0, 0), bool enable_validation_layers=false)
std::unique_ptr< VulkanDevice > AcquireFirstCompatibleLogicalDevice() const
std::vector< std::string > InstanceLayersToEnable(const VulkanProcTable &vk, bool enable_validation_layers)
#define VK_CALL_LOG_ERROR(expression)
static std::string DebugExtensionName()
#define FML_DLOG(severity)
Definition: logging.h:85
const VulkanHandle< VkInstance > & GetInstance() const