Flutter Engine
The Flutter Engine
vulkan_device.cc
Go to the documentation of this file.
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_device.h"
6
7#include <limits>
8#include <map>
9#include <vector>
10
11#include "flutter/vulkan/procs/vulkan_proc_table.h"
13#include "vulkan_surface.h"
14#include "vulkan_utilities.h"
15
16namespace vulkan {
17
20
21static uint32_t FindGraphicsQueueIndex(
22 const std::vector<VkQueueFamilyProperties>& properties) {
23 for (uint32_t i = 0, count = static_cast<uint32_t>(properties.size());
24 i < count; i++) {
25 if (properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {
26 return i;
27 }
28 }
30}
31
34 bool enable_validation_layers)
35 : vk_(p_vk),
36 physical_device_(std::move(physical_device)),
37 graphics_queue_index_(std::numeric_limits<uint32_t>::max()),
38 valid_(false) {
39 if (!physical_device_ || !vk_.AreInstanceProcsSetup()) {
40 return;
41 }
42
43 graphics_queue_index_ = FindGraphicsQueueIndex(GetQueueFamilyProperties());
44
45 if (graphics_queue_index_ == kVulkanInvalidGraphicsQueueIndex) {
46 FML_DLOG(INFO) << "Could not find the graphics queue index.";
47 return;
48 }
49
50 const float priorities[1] = {1.0f};
51
52 const VkDeviceQueueCreateInfo queue_create = {
54 .pNext = nullptr,
55 .flags = 0,
56 .queueFamilyIndex = graphics_queue_index_,
57 .queueCount = 1,
58 .pQueuePriorities = priorities,
59 };
60
61 const char* extensions[] = {
62#if FML_OS_ANDROID
64#endif
65#if OS_FUCHSIA
69 VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME,
70 VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
71 VK_FUCHSIA_BUFFER_COLLECTION_EXTENSION_NAME,
72#endif
73 };
74
75 auto enabled_layers =
76 DeviceLayersToEnable(vk_, physical_device_, enable_validation_layers);
77
78 std::vector<const char*> layers;
79
80 for (size_t i = 0; i < enabled_layers.size(); i++) {
81 layers.push_back(enabled_layers[i].c_str());
82 }
83
84 const VkDeviceCreateInfo create_info = {
86 .pNext = nullptr,
87 .flags = 0,
88 .queueCreateInfoCount = 1,
89 .pQueueCreateInfos = &queue_create,
90 .enabledLayerCount = static_cast<uint32_t>(layers.size()),
91 .ppEnabledLayerNames = layers.data(),
92 .enabledExtensionCount = sizeof(extensions) / sizeof(const char*),
93 .ppEnabledExtensionNames = extensions,
94 .pEnabledFeatures = nullptr,
95 };
96
97 VkDevice device = VK_NULL_HANDLE;
98
99 if (VK_CALL_LOG_ERROR(vk_.CreateDevice(physical_device_, &create_info,
100 nullptr, &device)) != VK_SUCCESS) {
101 FML_DLOG(INFO) << "Could not create device.";
102 return;
103 }
104
105 device_ = VulkanHandle<VkDevice>{
106 device, [this](VkDevice device) { vk_.DestroyDevice(device, nullptr); }};
107
108 if (!vk_.SetupDeviceProcAddresses(device_)) {
109 FML_DLOG(INFO) << "Could not set up device proc addresses.";
110 return;
111 }
112
113 VkQueue queue = VK_NULL_HANDLE;
114
115 vk_.GetDeviceQueue(device_, graphics_queue_index_, 0, &queue);
116
117 if (queue == VK_NULL_HANDLE) {
118 FML_DLOG(INFO) << "Could not get the device queue handle.";
119 return;
120 }
121
123
124 if (!InitializeCommandPool()) {
125 return;
126 }
127
128 valid_ = true;
129}
130
134 uint32_t queue_family_index,
136 : vk_(p_vk),
137 physical_device_(std::move(physical_device)),
138 device_(std::move(device)),
139 queue_(std::move(queue)),
140 graphics_queue_index_(queue_family_index),
141 valid_(false) {
142 if (!physical_device_ || !vk_.AreInstanceProcsSetup()) {
143 return;
144 }
145
146 if (!InitializeCommandPool()) {
147 return;
148 }
149
150 valid_ = true;
151}
152
153bool VulkanDevice::InitializeCommandPool() {
154 const VkCommandPoolCreateInfo command_pool_create_info = {
156 .pNext = nullptr,
158 .queueFamilyIndex = 0,
159 };
160
161 VkCommandPool command_pool = VK_NULL_HANDLE;
162 if (VK_CALL_LOG_ERROR(vk_.CreateCommandPool(
163 device_, &command_pool_create_info, nullptr, &command_pool)) !=
164 VK_SUCCESS) {
165 FML_DLOG(INFO) << "Could not create the command pool.";
166 return false;
167 }
168
169 command_pool_ = VulkanHandle<VkCommandPool>{
170 command_pool, [this](VkCommandPool pool) {
171 vk_.DestroyCommandPool(device_, pool, nullptr);
172 }};
173
174 return true;
175}
176
179}
180
182 return valid_;
183}
184
186 return VK_CALL_LOG_ERROR(vk_.DeviceWaitIdle(device_)) == VK_SUCCESS;
187}
188
190 return device_;
191}
192
194 device_.ReleaseOwnership();
195}
196
198 const {
199 return physical_device_;
200}
201
203 return queue_;
204}
205
207 return command_pool_;
208}
209
211 return graphics_queue_index_;
212}
213
215 const VulkanSurface& surface,
216 VkSurfaceCapabilitiesKHR* capabilities) const {
217#if FML_OS_ANDROID
218 if (!surface.IsValid() || capabilities == nullptr) {
219 return false;
220 }
221
222 bool success =
223 VK_CALL_LOG_ERROR(vk_.GetPhysicalDeviceSurfaceCapabilitiesKHR(
224 physical_device_, surface.Handle(), capabilities)) == VK_SUCCESS;
225
226 if (!success) {
227 return false;
228 }
229
230 // Check if the physical device surface capabilities are valid. If so, there
231 // is nothing more to do.
232 if (capabilities->currentExtent.width != 0xFFFFFFFF &&
233 capabilities->currentExtent.height != 0xFFFFFFFF) {
234 return true;
235 }
236
237 // Ask the native surface for its size as a fallback.
238 SkISize size = surface.GetSize();
239
240 if (size.width() == 0 || size.height() == 0) {
241 return false;
242 }
243
244 capabilities->currentExtent.width = size.width();
245 capabilities->currentExtent.height = size.height();
246 return true;
247#else
248 return false;
249#endif
250}
251
253 VkPhysicalDeviceFeatures* features) const {
254 if (features == nullptr || !physical_device_) {
255 return false;
256 }
257 vk_.GetPhysicalDeviceFeatures(physical_device_, features);
258 return true;
259}
260
261std::vector<VkQueueFamilyProperties> VulkanDevice::GetQueueFamilyProperties()
262 const {
263 uint32_t count = 0;
264
265 vk_.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count, nullptr);
266
267 std::vector<VkQueueFamilyProperties> properties;
268 properties.resize(count, {});
269
270 vk_.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count,
271 properties.data());
272
273 return properties;
274}
275
277 const VulkanSurface& surface,
278 const std::vector<VkFormat>& desired_formats,
279 VkSurfaceFormatKHR* format) const {
280#if FML_OS_ANDROID
281 if (!surface.IsValid() || format == nullptr) {
282 return -1;
283 }
284
285 uint32_t format_count = 0;
286 if (VK_CALL_LOG_ERROR(vk_.GetPhysicalDeviceSurfaceFormatsKHR(
287 physical_device_, surface.Handle(), &format_count, nullptr)) !=
288 VK_SUCCESS) {
289 return -1;
290 }
291
292 if (format_count == 0) {
293 return -1;
294 }
295
296 std::vector<VkSurfaceFormatKHR> formats;
297 formats.resize(format_count);
298
299 if (VK_CALL_LOG_ERROR(vk_.GetPhysicalDeviceSurfaceFormatsKHR(
300 physical_device_, surface.Handle(), &format_count, formats.data())) !=
301 VK_SUCCESS) {
302 return -1;
303 }
304
305 std::map<VkFormat, VkSurfaceFormatKHR> supported_formats;
306 for (uint32_t i = 0; i < format_count; i++) {
307 supported_formats[formats[i].format] = formats[i];
308 }
309
310 // Try to find the first supported format in the list of desired formats.
311 for (size_t i = 0; i < desired_formats.size(); ++i) {
312 auto found = supported_formats.find(desired_formats[i]);
313 if (found != supported_formats.end()) {
314 *format = found->second;
315 return static_cast<int>(i);
316 }
317 }
318#endif
319 return -1;
320}
321
323 VkPresentModeKHR* present_mode) const {
324 if (!surface.IsValid() || present_mode == nullptr) {
325 return false;
326 }
327
328 // https://github.com/LunarG/VulkanSamples/issues/98 indicates that
329 // VK_PRESENT_MODE_FIFO_KHR is preferable on mobile platforms. The problems
330 // mentioned in the ticket w.r.t the application being faster that the refresh
331 // rate of the screen should not be faced by any Flutter platforms as they are
332 // powered by Vsync pulses instead of depending the submit to block.
333 // However, for platforms that don't have VSync providers set up, it is better
334 // to fall back to FIFO. For platforms that do have VSync providers, there
335 // should be little difference. In case there is a need for a mode other than
336 // FIFO, availability checks must be performed here before returning the
337 // result. FIFO is always present.
338 *present_mode = VK_PRESENT_MODE_FIFO_KHR;
339 return true;
340}
341
343 std::vector<VkPipelineStageFlags> wait_dest_pipeline_stages,
344 const std::vector<VkSemaphore>& wait_semaphores,
345 const std::vector<VkSemaphore>& signal_semaphores,
346 const std::vector<VkCommandBuffer>& command_buffers,
347 const VulkanHandle<VkFence>& fence) const {
348 if (wait_semaphores.size() != wait_dest_pipeline_stages.size()) {
349 return false;
350 }
351
352 const VkSubmitInfo submit_info = {
354 .pNext = nullptr,
355 .waitSemaphoreCount = static_cast<uint32_t>(wait_semaphores.size()),
356 .pWaitSemaphores = wait_semaphores.data(),
357 .pWaitDstStageMask = wait_dest_pipeline_stages.data(),
358 .commandBufferCount = static_cast<uint32_t>(command_buffers.size()),
359 .pCommandBuffers = command_buffers.data(),
360 .signalSemaphoreCount = static_cast<uint32_t>(signal_semaphores.size()),
361 .pSignalSemaphores = signal_semaphores.data(),
362 };
363
364 if (VK_CALL_LOG_ERROR(vk_.QueueSubmit(queue_, 1, &submit_info, fence)) !=
365 VK_SUCCESS) {
366 return false;
367 }
368
369 return true;
370}
371
372} // namespace vulkan
AutoreleasePool pool
int count
Definition: FontMgrTest.cpp:50
VulkanDevice(VulkanProcTable &vk, VulkanHandle< VkPhysicalDevice > physical_device, bool enable_validation_layers)
Create a new VkDevice with a resolved VkQueue suitable for rendering with Skia.
const VulkanHandle< VkQueue > & GetQueueHandle() const
const VulkanHandle< VkPhysicalDevice > & GetPhysicalDeviceHandle() const
bool ChoosePresentMode(const VulkanSurface &surface, VkPresentModeKHR *present_mode) const
bool 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) const
bool GetSurfaceCapabilities(const VulkanSurface &surface, VkSurfaceCapabilitiesKHR *capabilities) const
const VulkanHandle< VkDevice > & GetHandle() const
int ChooseSurfaceFormat(const VulkanSurface &surface, const std::vector< VkFormat > &desired_formats, VkSurfaceFormatKHR *format) const
bool GetPhysicalDeviceFeatures(VkPhysicalDeviceFeatures *features) const
const VulkanHandle< VkCommandPool > & GetCommandPool() const
uint32_t GetGraphicsQueueIndex() const
bool AreInstanceProcsSetup() const
bool SetupDeviceProcAddresses(const VulkanHandle< VkDevice > &device)
VkPhysicalDevice physical_device
Definition: main.cc:51
VkDevice device
Definition: main.cc:53
VkQueue queue
Definition: main.cc:55
uint32_t queue_family_index
Definition: main.cc:54
VkSurfaceKHR surface
Definition: main.cc:49
uint32_t uint32_t * format
#define FML_ALLOW_UNUSED_LOCAL(x)
#define FML_DLOG(severity)
Definition: logging.h:102
static float max(float r, float g, float b)
Definition: hsl.cpp:49
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
Definition: ref_ptr.h:256
static uint32_t FindGraphicsQueueIndex(const std::vector< VkQueueFamilyProperties > &properties)
constexpr auto kVulkanInvalidGraphicsQueueIndex
std::vector< std::string > DeviceLayersToEnable(const VulkanProcTable &vk, const VulkanHandle< VkPhysicalDevice > &physical_device, bool enable_validation_layers)
Definition: SkSize.h:16
VkStructureType sType
Definition: vulkan_core.h:3865
VkStructureType sType
Definition: vulkan_core.h:3258
VkStructureType sType
Definition: vulkan_core.h:3249
uint32_t width
Definition: vulkan_core.h:2858
uint32_t height
Definition: vulkan_core.h:2859
VkStructureType sType
Definition: vulkan_core.h:3283
#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME
Definition: vulkan_core.h:8788
#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME
Definition: vulkan_core.h:8708
#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME
Definition: vulkan_core.h:9396
@ VK_QUEUE_GRAPHICS_BIT
Definition: vulkan_core.h:2413
@ VK_SUCCESS
Definition: vulkan_core.h:141
VkPresentModeKHR
Definition: vulkan_core.h:7594
@ VK_PRESENT_MODE_FIFO_KHR
Definition: vulkan_core.h:7597
#define VK_NULL_HANDLE
Definition: vulkan_core.h:46
@ VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
Definition: vulkan_core.h:2817
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME
Definition: vulkan_core.h:7707
@ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
Definition: vulkan_core.h:204
@ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
Definition: vulkan_core.h:205
@ VK_STRUCTURE_TYPE_SUBMIT_INFO
Definition: vulkan_core.h:206
@ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
Definition: vulkan_core.h:241
#define VK_CALL_LOG_ERROR(expression)