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 "flutter/vulkan/vulkan_application.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "flutter/vulkan/vulkan_device.h"
11 #ifdef RS_ENABLE_VK
12 #include "flutter/vulkan/vulkan_hilog.h"
13 #endif
14 #include "flutter/vulkan/vulkan_proc_table.h"
15 #include "flutter/vulkan/vulkan_utilities.h"
16
17 namespace vulkan {
18
VulkanApplication(VulkanProcTable & p_vk,const std::string & application_name,std::vector<std::string> enabled_extensions,uint32_t application_version,uint32_t api_version)19 VulkanApplication::VulkanApplication(
20 VulkanProcTable& p_vk,
21 const std::string& application_name,
22 std::vector<std::string> enabled_extensions,
23 uint32_t application_version,
24 uint32_t api_version)
25 : vk(p_vk), api_version_(api_version), valid_(false) {
26 // Check if we want to enable debugging.
27 std::vector<VkExtensionProperties> supported_extensions =
28 GetSupportedInstanceExtensions(vk);
29 bool enable_instance_debugging =
30 IsDebuggingEnabled() &&
31 ExtensionSupported(supported_extensions,
32 VulkanDebugReport::DebugExtensionName());
33
34 // Configure extensions.
35
36 if (enable_instance_debugging) {
37 enabled_extensions.emplace_back(VulkanDebugReport::DebugExtensionName());
38 }
39 #if OS_FUCHSIA
40 if (ExtensionSupported(supported_extensions,
41 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) {
42 // VK_KHR_get_physical_device_properties2 is a dependency of the memory
43 // capabilities extension, so the validation layers require that it be
44 // enabled.
45 enabled_extensions.emplace_back(
46 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
47 enabled_extensions.emplace_back(
48 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME);
49 }
50 #endif
51
52 const char* extensions[enabled_extensions.size()];
53
54 for (size_t i = 0; i < enabled_extensions.size(); i++) {
55 extensions[i] = enabled_extensions[i].c_str();
56 }
57
58 // Configure layers.
59
60 const std::vector<std::string> enabled_layers = InstanceLayersToEnable(vk);
61
62 const char* layers[enabled_layers.size()];
63
64 for (size_t i = 0; i < enabled_layers.size(); i++) {
65 layers[i] = enabled_layers[i].c_str();
66 }
67
68 // Configure init structs.
69
70 #ifdef RS_ENABLE_VK
71 const VkApplicationInfo info = {
72 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
73 .pNext = nullptr,
74 .pApplicationName = application_name.c_str(),
75 .applicationVersion = application_version,
76 .pEngineName = "Rosen",
77 .engineVersion = VK_MAKE_VERSION(1, 0, 0),
78 .apiVersion = api_version_,
79 };
80 #else
81 const VkApplicationInfo info = {
82 .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
83 .pNext = nullptr,
84 .pApplicationName = application_name.c_str(),
85 .applicationVersion = application_version,
86 .pEngineName = "FlutterEngine",
87 .engineVersion = VK_MAKE_VERSION(1, 0, 0),
88 .apiVersion = api_version_,
89 };
90 #endif
91
92 const VkInstanceCreateInfo create_info = {
93 .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
94 .pNext = nullptr,
95 .flags = 0,
96 .pApplicationInfo = &info,
97 .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
98 .ppEnabledLayerNames = layers,
99 .enabledExtensionCount = static_cast<uint32_t>(enabled_extensions.size()),
100 .ppEnabledExtensionNames = extensions,
101 };
102
103 // Perform initialization.
104
105 VkInstance instance = VK_NULL_HANDLE;
106
107 if (VK_CALL_LOG_ERROR(vk.CreateInstance(&create_info, nullptr, &instance)) !=
108 VK_SUCCESS) {
109 #ifdef RS_ENABLE_VK
110 LOGE("Could not create application instance.");
111 #else
112 FML_DLOG(INFO) << "Could not create application instance.";
113 #endif
114 return;
115 }
116
117 // Now that we have an instance, setup instance proc table entries.
118 if (!vk.SetupInstanceProcAddresses(instance)) {
119 #ifdef RS_ENABLE_VK
120 LOGE("Could not setup instance proc addresses.");
121 #else
122 FML_DLOG(INFO) << "Could not setup instance proc addresses.";
123 #endif
124 return;
125 }
126
127 instance_ = {instance, [this](VkInstance i) {
128 #ifdef RS_ENABLE_VK
129 LOGE("Destroying Vulkan instance");
130 #else
131 FML_LOG(INFO) << "Destroying Vulkan instance";
132 #endif
133 vk.DestroyInstance(i, nullptr);
134 }};
135
136 if (enable_instance_debugging) {
137 auto debug_report = std::make_unique<VulkanDebugReport>(vk, instance_);
138 if (!debug_report->IsValid()) {
139 #ifdef RS_ENABLE_VK
140 LOGE("Vulkan debugging was enabled but could not be setup for this instance.");
141 #else
142 FML_LOG(INFO) << "Vulkan debugging was enabled but could not be setup "
143 "for this instance.";
144 #endif
145 } else {
146 debug_report_ = std::move(debug_report);
147 #ifdef RS_ENABLE_VK
148 LOGE("Debug reporting is enabled.");
149 #else
150 FML_DLOG(INFO) << "Debug reporting is enabled.";
151 #endif
152 }
153 }
154
155 valid_ = true;
156 }
157
158 VulkanApplication::~VulkanApplication() = default;
159
IsValid() const160 bool VulkanApplication::IsValid() const {
161 return valid_;
162 }
163
GetAPIVersion() const164 uint32_t VulkanApplication::GetAPIVersion() const {
165 return api_version_;
166 }
167
GetInstance() const168 const VulkanHandle<VkInstance>& VulkanApplication::GetInstance() const {
169 return instance_;
170 }
171
ReleaseInstanceOwnership()172 void VulkanApplication::ReleaseInstanceOwnership() {
173 instance_.ReleaseOwnership();
174 }
175
GetPhysicalDevices() const176 std::vector<VkPhysicalDevice> VulkanApplication::GetPhysicalDevices() const {
177 if (!IsValid()) {
178 return {};
179 }
180
181 uint32_t device_count = 0;
182 if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices(instance_, &device_count,
183 nullptr)) != VK_SUCCESS) {
184 #ifdef RS_ENABLE_VK
185 LOGE("Could not enumerate physical device.");
186 #else
187 FML_DLOG(INFO) << "Could not enumerate physical device.";
188 #endif
189 return {};
190 }
191
192 if (device_count == 0) {
193 // No available devices.
194 #ifdef RS_ENABLE_VK
195 LOGE("No physical devices found.");
196 #else
197 FML_DLOG(INFO) << "No physical devices found.";
198 #endif
199 return {};
200 }
201
202 std::vector<VkPhysicalDevice> physical_devices;
203
204 physical_devices.resize(device_count);
205
206 if (VK_CALL_LOG_ERROR(vk.EnumeratePhysicalDevices(
207 instance_, &device_count, physical_devices.data())) != VK_SUCCESS) {
208 #ifdef RS_ENABLE_VK
209 LOGE("Could not enumerate physical device.");
210 #else
211 FML_DLOG(INFO) << "Could not enumerate physical device.";
212 #endif
213 return {};
214 }
215
216 return physical_devices;
217 }
218
219 std::unique_ptr<VulkanDevice>
AcquireFirstCompatibleLogicalDevice() const220 VulkanApplication::AcquireFirstCompatibleLogicalDevice() const {
221 for (auto device_handle : GetPhysicalDevices()) {
222 auto logical_device = std::make_unique<VulkanDevice>(vk, device_handle);
223 if (logical_device->IsValid()) {
224 return logical_device;
225 }
226 }
227 #ifdef RS_ENABLE_VK
228 LOGE("Could not acquire compatible logical device.");
229 #else
230 FML_DLOG(INFO) << "Could not acquire compatible logical device.";
231 #endif
232 return nullptr;
233 }
234
235 std::vector<VkExtensionProperties>
GetSupportedInstanceExtensions(const VulkanProcTable & vk) const236 VulkanApplication::GetSupportedInstanceExtensions(
237 const VulkanProcTable& vk) const {
238 if (!vk.EnumerateInstanceExtensionProperties) {
239 return std::vector<VkExtensionProperties>();
240 }
241
242 uint32_t count = 0;
243 if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties(
244 nullptr, &count, nullptr)) != VK_SUCCESS) {
245 return std::vector<VkExtensionProperties>();
246 }
247
248 if (count == 0) {
249 return std::vector<VkExtensionProperties>();
250 }
251
252 std::vector<VkExtensionProperties> properties;
253 properties.resize(count);
254 if (VK_CALL_LOG_ERROR(vk.EnumerateInstanceExtensionProperties(
255 nullptr, &count, properties.data())) != VK_SUCCESS) {
256 return std::vector<VkExtensionProperties>();
257 }
258
259 return properties;
260 }
261
ExtensionSupported(const std::vector<VkExtensionProperties> & supported_instance_extensions,std::string extension_name)262 bool VulkanApplication::ExtensionSupported(
263 const std::vector<VkExtensionProperties>& supported_instance_extensions,
264 std::string extension_name) {
265 uint32_t count = supported_instance_extensions.size();
266 for (size_t i = 0; i < count; i++) {
267 if (strncmp(supported_instance_extensions[i].extensionName,
268 extension_name.c_str(), extension_name.size()) == 0) {
269 return true;
270 }
271 }
272
273 return false;
274 }
275
276 } // namespace vulkan
277