• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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