Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
19 std::numeric_limits<uint32_t>::max();
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
180
182 return valid_;
183}
184
186 return VK_CALL_LOG_ERROR(vk_.DeviceWaitIdle(device_)) == VK_SUCCESS;
187}
188
190 return device_;
191}
192
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
261bool VulkanDevice::GetPhysicalDeviceFeaturesSkia(uint32_t* sk_features) const {
262 if (sk_features == nullptr) {
263 return false;
264 }
265
267
268 if (!GetPhysicalDeviceFeatures(&features)) {
269 return false;
270 }
271
272 uint32_t flags = 0;
273
274 if (features.geometryShader) {
276 }
277 if (features.dualSrcBlend) {
279 }
280 if (features.sampleRateShading) {
282 }
283
284 *sk_features = flags;
285 return true;
286}
287
288std::vector<VkQueueFamilyProperties> VulkanDevice::GetQueueFamilyProperties()
289 const {
290 uint32_t count = 0;
291
292 vk_.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count, nullptr);
293
294 std::vector<VkQueueFamilyProperties> properties;
295 properties.resize(count, {});
296
297 vk_.GetPhysicalDeviceQueueFamilyProperties(physical_device_, &count,
298 properties.data());
299
300 return properties;
301}
302
304 const VulkanSurface& surface,
305 const std::vector<VkFormat>& desired_formats,
306 VkSurfaceFormatKHR* format) const {
307#if FML_OS_ANDROID
308 if (!surface.IsValid() || format == nullptr) {
309 return -1;
310 }
311
312 uint32_t format_count = 0;
313 if (VK_CALL_LOG_ERROR(vk_.GetPhysicalDeviceSurfaceFormatsKHR(
314 physical_device_, surface.Handle(), &format_count, nullptr)) !=
315 VK_SUCCESS) {
316 return -1;
317 }
318
319 if (format_count == 0) {
320 return -1;
321 }
322
323 std::vector<VkSurfaceFormatKHR> formats;
324 formats.resize(format_count);
325
326 if (VK_CALL_LOG_ERROR(vk_.GetPhysicalDeviceSurfaceFormatsKHR(
327 physical_device_, surface.Handle(), &format_count, formats.data())) !=
328 VK_SUCCESS) {
329 return -1;
330 }
331
332 std::map<VkFormat, VkSurfaceFormatKHR> supported_formats;
333 for (uint32_t i = 0; i < format_count; i++) {
334 supported_formats[formats[i].format] = formats[i];
335 }
336
337 // Try to find the first supported format in the list of desired formats.
338 for (size_t i = 0; i < desired_formats.size(); ++i) {
339 auto found = supported_formats.find(desired_formats[i]);
340 if (found != supported_formats.end()) {
341 *format = found->second;
342 return static_cast<int>(i);
343 }
344 }
345#endif
346 return -1;
347}
348
350 VkPresentModeKHR* present_mode) const {
351 if (!surface.IsValid() || present_mode == nullptr) {
352 return false;
353 }
354
355 // https://github.com/LunarG/VulkanSamples/issues/98 indicates that
356 // VK_PRESENT_MODE_FIFO_KHR is preferable on mobile platforms. The problems
357 // mentioned in the ticket w.r.t the application being faster that the refresh
358 // rate of the screen should not be faced by any Flutter platforms as they are
359 // powered by Vsync pulses instead of depending the submit to block.
360 // However, for platforms that don't have VSync providers set up, it is better
361 // to fall back to FIFO. For platforms that do have VSync providers, there
362 // should be little difference. In case there is a need for a mode other than
363 // FIFO, availability checks must be performed here before returning the
364 // result. FIFO is always present.
365 *present_mode = VK_PRESENT_MODE_FIFO_KHR;
366 return true;
367}
368
370 std::vector<VkPipelineStageFlags> wait_dest_pipeline_stages,
371 const std::vector<VkSemaphore>& wait_semaphores,
372 const std::vector<VkSemaphore>& signal_semaphores,
373 const std::vector<VkCommandBuffer>& command_buffers,
374 const VulkanHandle<VkFence>& fence) const {
375 if (wait_semaphores.size() != wait_dest_pipeline_stages.size()) {
376 return false;
377 }
378
379 const VkSubmitInfo submit_info = {
381 .pNext = nullptr,
382 .waitSemaphoreCount = static_cast<uint32_t>(wait_semaphores.size()),
383 .pWaitSemaphores = wait_semaphores.data(),
384 .pWaitDstStageMask = wait_dest_pipeline_stages.data(),
385 .commandBufferCount = static_cast<uint32_t>(command_buffers.size()),
386 .pCommandBuffers = command_buffers.data(),
387 .signalSemaphoreCount = static_cast<uint32_t>(signal_semaphores.size()),
388 .pSignalSemaphores = signal_semaphores.data(),
389 };
390
391 if (VK_CALL_LOG_ERROR(vk_.QueueSubmit(queue_, 1, &submit_info, fence)) !=
392 VK_SUCCESS) {
393 return false;
394 }
395
396 return true;
397}
398
399} // namespace vulkan
AutoreleasePool pool
int count
@ kSampleRateShading_GrVkFeatureFlag
@ kDualSrcBlend_GrVkFeatureFlag
@ kGeometryShader_GrVkFeatureFlag
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
bool GetPhysicalDeviceFeaturesSkia(uint32_t *features) 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 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
FlutterSemanticsFlag flags
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
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)
VkStructureType sType
VkStructureType sType
VkStructureType sType
uint32_t width
uint32_t height
VkStructureType sType
#define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME
#define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME
#define VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME
@ VK_QUEUE_GRAPHICS_BIT
@ VK_SUCCESS
VkPresentModeKHR
@ VK_PRESENT_MODE_FIFO_KHR
#define VK_NULL_HANDLE
Definition vulkan_core.h:46
@ VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
#define VK_KHR_SWAPCHAIN_EXTENSION_NAME
@ VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
@ VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
@ VK_STRUCTURE_TYPE_SUBMIT_INFO
@ VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
#define VK_CALL_LOG_ERROR(expression)