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