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