• 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_device.h"
6 
7 #include <limits>
8 #include <map>
9 #include <vector>
10 
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_surface.h"
16 #include "flutter/vulkan/vulkan_utilities.h"
17 #include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
18 
19 namespace vulkan {
20 
21 constexpr auto kVulkanInvalidGraphicsQueueIndex =
22     std::numeric_limits<uint32_t>::max();
23 
24 #ifdef RS_ENABLE_VK
FindQueueIndex(const std::vector<VkQueueFamilyProperties> & properties,VkQueueFlagBits flagBits)25 static uint32_t FindQueueIndex(const std::vector<VkQueueFamilyProperties>& properties, VkQueueFlagBits flagBits) {
26   for (uint32_t i = 0, count = static_cast<uint32_t>(properties.size()); i < count; i++) {
27     if (properties[i].queueFlags & flagBits) {
28       return i;
29     }
30   }
31   return kVulkanInvalidGraphicsQueueIndex;
32 }
33 #else
FindGraphicsQueueIndex(const std::vector<VkQueueFamilyProperties> & properties)34 static uint32_t FindGraphicsQueueIndex(
35     const std::vector<VkQueueFamilyProperties>& properties) {
36   for (uint32_t i = 0, count = static_cast<uint32_t>(properties.size());
37        i < count; i++) {
38     if (properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
39       return i;
40     }
41   }
42   return kVulkanInvalidGraphicsQueueIndex;
43 }
44 #endif
45 
46 #ifdef RS_ENABLE_VK
VulkanDevice(VulkanProcTable & p_vk,VulkanHandle<VkPhysicalDevice> physical_device)47 VulkanDevice::VulkanDevice(VulkanProcTable& p_vk, VulkanHandle<VkPhysicalDevice> physical_device)
48     : vk(p_vk), physical_device_(std::move(physical_device)),
49       graphics_queue_index_(std::numeric_limits<uint32_t>::max()),
50       compute_queue_index_(std::numeric_limits<uint32_t>::max()), valid_(false)
51 {
52   if (!physical_device_ || !vk.AreInstanceProcsSetup()) {
53     return;
54   }
55 
56   std::vector<VkQueueFamilyProperties> properties = GetQueueFamilyProperties();
57   graphics_queue_index_ = FindQueueIndex(properties, VK_QUEUE_GRAPHICS_BIT);
58   compute_queue_index_ = FindQueueIndex(properties, VK_QUEUE_COMPUTE_BIT);
59 
60   if (graphics_queue_index_ == kVulkanInvalidGraphicsQueueIndex) {
61     LOGE("Could not find the graphics queue index.");
62     return;
63   }
64 
65   const float priorities[1] = {1.0f};
66 
67   std::vector<VkDeviceQueueCreateInfo> queue_create { {
68       .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
69       .pNext = nullptr,
70       .flags = 0,
71       .queueFamilyIndex = graphics_queue_index_,
72       .queueCount = 1,
73       .pQueuePriorities = priorities,
74   } };
75 
76   if (compute_queue_index_ != kVulkanInvalidGraphicsQueueIndex && compute_queue_index_ != graphics_queue_index_) {
77     queue_create.push_back({
78         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
79         .pNext = nullptr,
80         .flags = 0,
81         .queueFamilyIndex = graphics_queue_index_,
82         .queueCount = 1,
83         .pQueuePriorities = priorities,
84     });
85   }
86 
87   const char* extensions[] = {
88     VK_KHR_SWAPCHAIN_EXTENSION_NAME,
89   };
90 
91   auto enabled_layers = DeviceLayersToEnable(vk, physical_device_);
92 
93   const char* layers[enabled_layers.size()];
94 
95   for (size_t i = 0; i < enabled_layers.size(); i++) {
96     layers[i] = enabled_layers[i].c_str();
97   }
98 
99   const VkDeviceCreateInfo create_info = {
100       .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
101       .pNext = nullptr,
102       .flags = 0,
103       .queueCreateInfoCount = queue_create.size(),
104       .pQueueCreateInfos = queue_create.data(),
105       .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
106       .ppEnabledLayerNames = layers,
107       .enabledExtensionCount = sizeof(extensions) / sizeof(const char*),
108       .ppEnabledExtensionNames = extensions,
109       .pEnabledFeatures = nullptr,
110   };
111 
112   VkDevice device = VK_NULL_HANDLE;
113 
114   if (VK_CALL_LOG_ERROR(vk.CreateDevice(physical_device_, &create_info, nullptr,
115                                         &device)) != VK_SUCCESS) {
116     LOGE("Could not create device.");
117     return;
118   }
119 
120   device_ = {device,
121               [this](VkDevice device) { vk.DestroyDevice(device, nullptr); }};
122 
123   if (!vk.SetupDeviceProcAddresses(device_)) {
124     LOGE("Could not setup device proc addresses.");
125     return;
126   }
127 
128   VkQueue queue = VK_NULL_HANDLE;
129 
130   vk.GetDeviceQueue(device_, graphics_queue_index_, 0, &queue);
131 
132   if (queue == VK_NULL_HANDLE) {
133     LOGE("Could not get the device queue handle.");
134     return;
135   }
136 
137   queue_ = queue;
138 
139   const VkCommandPoolCreateInfo command_pool_create_info = {
140       .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
141       .pNext = nullptr,
142       .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
143       .queueFamilyIndex = 0,
144   };
145 
146   VkCommandPool command_pool = VK_NULL_HANDLE;
147   if (VK_CALL_LOG_ERROR(vk.CreateCommandPool(device_, &command_pool_create_info,
148                                              nullptr, &command_pool)) !=
149       VK_SUCCESS) {
150     LOGE("Could not create the command pool.");
151     return;
152   }
153 
154   command_pool_ = {command_pool, [this](VkCommandPool pool) {
155                     vk.DestroyCommandPool(device_, pool, nullptr);
156                   }};
157 
158   valid_ = true;
159 }
160 #else
VulkanDevice(VulkanProcTable & p_vk,VulkanHandle<VkPhysicalDevice> physical_device)161 VulkanDevice::VulkanDevice(VulkanProcTable& p_vk,
162                            VulkanHandle<VkPhysicalDevice> physical_device)
163     : vk(p_vk),
164       physical_device_(std::move(physical_device)),
165       graphics_queue_index_(std::numeric_limits<uint32_t>::max()),
166       valid_(false) {
167   if (!physical_device_ || !vk.AreInstanceProcsSetup()) {
168     return;
169   }
170 
171   graphics_queue_index_ = FindGraphicsQueueIndex(GetQueueFamilyProperties());
172 
173   if (graphics_queue_index_ == kVulkanInvalidGraphicsQueueIndex) {
174     FML_DLOG(INFO) << "Could not find the graphics queue index.";
175     return;
176   }
177 
178   const float priorities[1] = {1.0f};
179 
180   const VkDeviceQueueCreateInfo queue_create = {
181       .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
182       .pNext = nullptr,
183       .flags = 0,
184       .queueFamilyIndex = graphics_queue_index_,
185       .queueCount = 1,
186       .pQueuePriorities = priorities,
187   };
188 
189   const char* extensions[] = {
190 #if OS_ANDROID
191     VK_KHR_SWAPCHAIN_EXTENSION_NAME,
192 #endif
193 #if OS_FUCHSIA
194     VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
195     VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME,
196     VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
197     VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
198 #endif
199   };
200 
201   auto enabled_layers = DeviceLayersToEnable(vk, physical_device_);
202 
203   const char* layers[enabled_layers.size()];
204 
205   for (size_t i = 0; i < enabled_layers.size(); i++) {
206     layers[i] = enabled_layers[i].c_str();
207   }
208 
209   const VkDeviceCreateInfo create_info = {
210       .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
211       .pNext = nullptr,
212       .flags = 0,
213       .queueCreateInfoCount = 1,
214       .pQueueCreateInfos = &queue_create,
215       .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
216       .ppEnabledLayerNames = layers,
217       .enabledExtensionCount = sizeof(extensions) / sizeof(const char*),
218       .ppEnabledExtensionNames = extensions,
219       .pEnabledFeatures = nullptr,
220   };
221 
222   VkDevice device = VK_NULL_HANDLE;
223 
224   if (VK_CALL_LOG_ERROR(vk.CreateDevice(physical_device_, &create_info, nullptr,
225                                         &device)) != VK_SUCCESS) {
226     FML_DLOG(INFO) << "Could not create device.";
227     return;
228   }
229 
230   device_ = {device,
231              [this](VkDevice device) { vk.DestroyDevice(device, nullptr); }};
232 
233   if (!vk.SetupDeviceProcAddresses(device_)) {
234     FML_DLOG(INFO) << "Could not setup device proc addresses.";
235     return;
236   }
237 
238   VkQueue queue = VK_NULL_HANDLE;
239 
240   vk.GetDeviceQueue(device_, graphics_queue_index_, 0, &queue);
241 
242   if (queue == VK_NULL_HANDLE) {
243     FML_DLOG(INFO) << "Could not get the device queue handle.";
244     return;
245   }
246 
247   queue_ = queue;
248 
249   const VkCommandPoolCreateInfo command_pool_create_info = {
250       .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
251       .pNext = nullptr,
252       .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
253       .queueFamilyIndex = 0,
254   };
255 
256   VkCommandPool command_pool = VK_NULL_HANDLE;
257   if (VK_CALL_LOG_ERROR(vk.CreateCommandPool(device_, &command_pool_create_info,
258                                              nullptr, &command_pool)) !=
259       VK_SUCCESS) {
260     FML_DLOG(INFO) << "Could not create the command pool.";
261     return;
262   }
263 
264   command_pool_ = {command_pool, [this](VkCommandPool pool) {
265                      vk.DestroyCommandPool(device_, pool, nullptr);
266                    }};
267 
268   valid_ = true;
269 }
270 #endif
271 
~VulkanDevice()272 VulkanDevice::~VulkanDevice() {
273 #ifdef RS_ENABLE_VK
274   WaitIdle();
275 #else
276   FML_ALLOW_UNUSED_LOCAL(WaitIdle());
277 #endif
278 }
279 
IsValid() const280 bool VulkanDevice::IsValid() const {
281   return valid_;
282 }
283 
WaitIdle() const284 bool VulkanDevice::WaitIdle() const {
285   return VK_CALL_LOG_ERROR(vk.DeviceWaitIdle(device_)) == VK_SUCCESS;
286 }
287 
GetHandle() const288 const VulkanHandle<VkDevice>& VulkanDevice::GetHandle() const {
289   return device_;
290 }
291 
ReleaseDeviceOwnership()292 void VulkanDevice::ReleaseDeviceOwnership() {
293   device_.ReleaseOwnership();
294 }
295 
GetPhysicalDeviceHandle() const296 const VulkanHandle<VkPhysicalDevice>& VulkanDevice::GetPhysicalDeviceHandle()
297     const {
298   return physical_device_;
299 }
300 
GetQueueHandle() const301 const VulkanHandle<VkQueue>& VulkanDevice::GetQueueHandle() const {
302   return queue_;
303 }
304 
GetCommandPool() const305 const VulkanHandle<VkCommandPool>& VulkanDevice::GetCommandPool() const {
306   return command_pool_;
307 }
308 
GetGraphicsQueueIndex() const309 uint32_t VulkanDevice::GetGraphicsQueueIndex() const {
310   return graphics_queue_index_;
311 }
312 
GetSurfaceCapabilities(const VulkanSurface & surface,VkSurfaceCapabilitiesKHR * capabilities) const313 bool VulkanDevice::GetSurfaceCapabilities(
314     const VulkanSurface& surface,
315     VkSurfaceCapabilitiesKHR* capabilities) const {
316 #ifdef RS_ENABLE_VK
317 if (!surface.IsValid() || capabilities == nullptr) {
318     LOGE("GetSurfaceCapabilities surface is not valid or capabilities is null");
319     return false;
320   }
321 
322   bool success =
323       VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(
324           physical_device_, surface.Handle(), capabilities)) == VK_SUCCESS;
325 
326   if (!success) {
327     LOGE("GetPhysicalDeviceSurfaceCapabilitiesKHR not success");
328     return false;
329   }
330 
331   // Check if the physical device surface capabilities are valid. If so, there
332   // is nothing more to do.
333   if (capabilities->currentExtent.width != 0xFFFFFFFF &&
334       capabilities->currentExtent.height != 0xFFFFFFFF) {
335     return true;
336   }
337 
338   // Ask the native surface for its size as a fallback.
339   SkISize size = surface.GetSize();
340 
341   if (size.width() == 0 || size.height() == 0) {
342     LOGE("GetSurfaceCapabilities surface size is 0");
343     return false;
344   }
345 
346   capabilities->currentExtent.width = size.width();
347   capabilities->currentExtent.height = size.height();
348   return true;
349 #else
350 #if OS_ANDROID
351   if (!surface.IsValid() || capabilities == nullptr) {
352     return false;
353   }
354 
355   bool success =
356       VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(
357           physical_device_, surface.Handle(), capabilities)) == VK_SUCCESS;
358 
359   if (!success) {
360     return false;
361   }
362 
363   // Check if the physical device surface capabilities are valid. If so, there
364   // is nothing more to do.
365   if (capabilities->currentExtent.width != 0xFFFFFFFF &&
366       capabilities->currentExtent.height != 0xFFFFFFFF) {
367     return true;
368   }
369 
370   // Ask the native surface for its size as a fallback.
371   SkISize size = surface.GetSize();
372 
373   if (size.width() == 0 || size.height() == 0) {
374     return false;
375   }
376 
377   capabilities->currentExtent.width = size.width();
378   capabilities->currentExtent.height = size.height();
379   return true;
380 #else
381   return false;
382 #endif // OS_ANDROID
383 #endif // RS_ENABLE_VK
384 }
385 
GetPhysicalDeviceFeatures(VkPhysicalDeviceFeatures * features) const386 bool VulkanDevice::GetPhysicalDeviceFeatures(
387     VkPhysicalDeviceFeatures* features) const {
388   if (features == nullptr || !physical_device_) {
389     return false;
390   }
391   vk.GetPhysicalDeviceFeatures(physical_device_, features);
392   return true;
393 }
394 
GetPhysicalDeviceFeaturesSkia(uint32_t * sk_features) const395 bool VulkanDevice::GetPhysicalDeviceFeaturesSkia(uint32_t* sk_features) const {
396   if (sk_features == nullptr) {
397     return false;
398   }
399 
400   VkPhysicalDeviceFeatures features;
401 
402   if (!GetPhysicalDeviceFeatures(&features)) {
403     return false;
404   }
405 
406   uint32_t flags = 0;
407 
408   if (features.geometryShader) {
409     flags |= kGeometryShader_GrVkFeatureFlag;
410   }
411   if (features.dualSrcBlend) {
412     flags |= kDualSrcBlend_GrVkFeatureFlag;
413   }
414   if (features.sampleRateShading) {
415     flags |= kSampleRateShading_GrVkFeatureFlag;
416   }
417 
418   *sk_features = flags;
419   return true;
420 }
421 
GetQueueFamilyProperties() const422 std::vector<VkQueueFamilyProperties> VulkanDevice::GetQueueFamilyProperties()
423     const {
424   uint32_t count = 0;
425 
426   vk.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count, nullptr);
427 
428   std::vector<VkQueueFamilyProperties> properties;
429   properties.resize(count, {});
430 
431   vk.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count,
432                                             properties.data());
433 
434   return properties;
435 }
436 
ChooseSurfaceFormat(const VulkanSurface & surface,std::vector<VkFormat> desired_formats,VkSurfaceFormatKHR * format) const437 int VulkanDevice::ChooseSurfaceFormat(const VulkanSurface& surface,
438                                       std::vector<VkFormat> desired_formats,
439                                       VkSurfaceFormatKHR* format) const {
440 #ifdef RS_ENABLE_VK
441   if (!surface.IsValid() || format == nullptr) {
442     LOGE("ChooseSurfaceFormat surface not valid or format == null");
443     return -1;
444   }
445 
446   uint32_t format_count = 0;
447   if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
448           physical_device_, surface.Handle(), &format_count, nullptr)) !=
449       VK_SUCCESS) {
450     LOGE("ChooseSurfaceFormat sGetPhysicalDeviceSurfaceFormatsKHR not success");
451     return -1;
452   }
453 
454   if (format_count == 0) {
455     LOGE("ChooseSurfaceFormat format count = 0");
456     return -1;
457   }
458 
459   VkSurfaceFormatKHR formats[format_count];
460   if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
461           physical_device_, surface.Handle(), &format_count, formats)) !=
462       VK_SUCCESS) {
463     LOGE("ChooseSurfaceFormat sGetPhysicalDeviceSurfaceFormatsKHR not success 2");
464     return -1;
465   }
466 
467   std::map<VkFormat, VkSurfaceFormatKHR> supported_formats;
468   for (uint32_t i = 0; i < format_count; i++) {
469     supported_formats[formats[i].format] = formats[i];
470   }
471 
472   // Try to find the first supported format in the list of desired formats.
473   for (size_t i = 0; i < desired_formats.size(); ++i) {
474     auto found = supported_formats.find(desired_formats[i]);
475     if (found != supported_formats.end()) {
476       *format = found->second;
477       return static_cast<int>(i);
478     }
479   }
480   LOGE("ChooseSurfaceFormat failded");
481 #else
482 #if OS_ANDROID
483   if (!surface.IsValid() || format == nullptr) {
484     return -1;
485   }
486 
487   uint32_t format_count = 0;
488   if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
489           physical_device_, surface.Handle(), &format_count, nullptr)) !=
490       VK_SUCCESS) {
491     return -1;
492   }
493 
494   if (format_count == 0) {
495     return -1;
496   }
497 
498   VkSurfaceFormatKHR formats[format_count];
499   if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
500           physical_device_, surface.Handle(), &format_count, formats)) !=
501       VK_SUCCESS) {
502     return -1;
503   }
504 
505   std::map<VkFormat, VkSurfaceFormatKHR> supported_formats;
506   for (uint32_t i = 0; i < format_count; i++) {
507     supported_formats[formats[i].format] = formats[i];
508   }
509 
510   // Try to find the first supported format in the list of desired formats.
511   for (size_t i = 0; i < desired_formats.size(); ++i) {
512     auto found = supported_formats.find(desired_formats[i]);
513     if (found != supported_formats.end()) {
514       *format = found->second;
515       return static_cast<int>(i);
516     }
517   }
518 #endif // OS_ANDROID
519 #endif // RS_ENABLE_VK
520   return -1;
521 }
522 
ChoosePresentMode(const VulkanSurface & surface,VkPresentModeKHR * present_mode) const523 bool VulkanDevice::ChoosePresentMode(const VulkanSurface& surface,
524                                      VkPresentModeKHR* present_mode) const {
525   if (!surface.IsValid() || present_mode == nullptr) {
526 #ifdef RS_ENABLE_VK
527     LOGE("ChoosePresentMode surface not valid or presentmode is null");
528 #endif
529     return false;
530   }
531 
532   // https://github.com/LunarG/VulkanSamples/issues/98 indicates that
533   // VK_PRESENT_MODE_FIFO_KHR is preferable on mobile platforms. The problems
534   // mentioned in the ticket w.r.t the application being faster that the refresh
535   // rate of the screen should not be faced by any Flutter platforms as they are
536   // powered by Vsync pulses instead of depending the the submit to block.
537   // However, for platforms that don't have VSync providers setup, it is better
538   // to fall back to FIFO. For platforms that do have VSync providers, there
539   // should be little difference. In case there is a need for a mode other than
540   // FIFO, availability checks must be performed here before returning the
541   // result. FIFO is always present.
542   *present_mode = VK_PRESENT_MODE_FIFO_KHR;
543   return true;
544 }
545 
QueueSubmit(std::vector<VkPipelineStageFlags> wait_dest_pipeline_stages,const std::vector<VkSemaphore> & wait_semaphores,const std::vector<VkSemaphore> & signal_semaphores,const std::vector<VkCommandBuffer> & command_buffers,const VulkanHandle<VkFence> & fence) const546 bool VulkanDevice::QueueSubmit(
547     std::vector<VkPipelineStageFlags> wait_dest_pipeline_stages,
548     const std::vector<VkSemaphore>& wait_semaphores,
549     const std::vector<VkSemaphore>& signal_semaphores,
550     const std::vector<VkCommandBuffer>& command_buffers,
551     const VulkanHandle<VkFence>& fence) const {
552   if (wait_semaphores.size() != wait_dest_pipeline_stages.size()) {
553     return false;
554   }
555 
556   const VkSubmitInfo submit_info = {
557       .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
558       .pNext = nullptr,
559       .waitSemaphoreCount = static_cast<uint32_t>(wait_semaphores.size()),
560       .pWaitSemaphores = wait_semaphores.data(),
561       .pWaitDstStageMask = wait_dest_pipeline_stages.data(),
562       .commandBufferCount = static_cast<uint32_t>(command_buffers.size()),
563       .pCommandBuffers = command_buffers.data(),
564       .signalSemaphoreCount = static_cast<uint32_t>(signal_semaphores.size()),
565       .pSignalSemaphores = signal_semaphores.data(),
566   };
567 
568   if (VK_CALL_LOG_ERROR(vk.QueueSubmit(queue_, 1, &submit_info, fence)) !=
569       VK_SUCCESS) {
570     return false;
571   }
572 
573   return true;
574 }
575 
576 }  // namespace vulkan
577