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 | |
16 | VulkanApplication::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 | |
128 | VulkanApplication::~VulkanApplication() = default; |
129 | |
130 | bool VulkanApplication::IsValid() const { |
131 | return valid_; |
132 | } |
133 | |
134 | uint32_t VulkanApplication::GetAPIVersion() const { |
135 | return api_version_; |
136 | } |
137 | |
138 | const VulkanHandle<VkInstance>& VulkanApplication::GetInstance() const { |
139 | return instance_; |
140 | } |
141 | |
142 | void VulkanApplication::ReleaseInstanceOwnership() { |
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> |
178 | VulkanApplication::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 | |
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 |
232 | |