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
14namespace vulkan {
15
16VulkanApplication::VulkanApplication(
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,
33 VulkanDebugReport::DebugExtensionName());
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
128VulkanApplication::~VulkanApplication() = default;
129
130bool VulkanApplication::IsValid() const {
131 return valid_;
132}
133
134uint32_t VulkanApplication::GetAPIVersion() const {
135 return api_version_;
136}
137
138const VulkanHandle<VkInstance>& VulkanApplication::GetInstance() const {
139 return instance_;
140}
141
142void VulkanApplication::ReleaseInstanceOwnership() {
143 instance_.ReleaseOwnership();
144}
145
146std::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
177std::unique_ptr<VulkanDevice>
178VulkanApplication::AcquireFirstCompatibleLogicalDevice() const {
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
190std::vector<VkExtensionProperties>
191VulkanApplication::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
217bool 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
232