Flutter Engine
vulkan::VulkanDevice Class Reference

#include <vulkan_device.h>

Public Member Functions

 VulkanDevice (VulkanProcTable &vk, VulkanHandle< VkPhysicalDevice > physical_device, bool enable_validation_layers)
 
 ~VulkanDevice ()
 
bool IsValid () const
 
const VulkanHandle< VkDevice > & GetHandle () const
 
const VulkanHandle< VkPhysicalDevice > & GetPhysicalDeviceHandle () const
 
const VulkanHandle< VkQueue > & GetQueueHandle () const
 
const VulkanHandle< VkCommandPool > & GetCommandPool () const
 
uint32_t GetGraphicsQueueIndex () const
 
void ReleaseDeviceOwnership ()
 
bool GetSurfaceCapabilities (const VulkanSurface &surface, VkSurfaceCapabilitiesKHR *capabilities) const
 
bool GetPhysicalDeviceFeatures (VkPhysicalDeviceFeatures *features) const
 
bool GetPhysicalDeviceFeaturesSkia (uint32_t *features) const
 
int ChooseSurfaceFormat (const VulkanSurface &surface, std::vector< VkFormat > desired_formats, VkSurfaceFormatKHR *format) 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 WaitIdle () const
 

Detailed Description

Definition at line 19 of file vulkan_device.h.

Constructor & Destructor Documentation

◆ VulkanDevice()

vulkan::VulkanDevice::VulkanDevice ( VulkanProcTable vk,
VulkanHandle< VkPhysicalDevice >  physical_device,
bool  enable_validation_layers 
)

Definition at line 32 of file vulkan_device.cc.

References vulkan::VulkanProcTable::AreInstanceProcsSetup(), vulkan::DeviceLayersToEnable(), vulkan::FindGraphicsQueueIndex(), FML_DLOG, vulkan::VulkanProcTable::SetupDeviceProcAddresses(), and VK_CALL_LOG_ERROR.

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  enable_validation_layers_(enable_validation_layers) {
40  if (!physical_device_ || !vk.AreInstanceProcsSetup()) {
41  return;
42  }
43 
44  graphics_queue_index_ = FindGraphicsQueueIndex(GetQueueFamilyProperties());
45 
46  if (graphics_queue_index_ == kVulkanInvalidGraphicsQueueIndex) {
47  FML_DLOG(INFO) << "Could not find the graphics queue index.";
48  return;
49  }
50 
51  const float priorities[1] = {1.0f};
52 
53  const VkDeviceQueueCreateInfo queue_create = {
54  .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
55  .pNext = nullptr,
56  .flags = 0,
57  .queueFamilyIndex = graphics_queue_index_,
58  .queueCount = 1,
59  .pQueuePriorities = priorities,
60  };
61 
62  const char* extensions[] = {
63 #if OS_ANDROID
64  VK_KHR_SWAPCHAIN_EXTENSION_NAME,
65 #endif
66 #if OS_FUCHSIA
67  VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
68  VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
69  VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
70  VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME,
71  VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
72  VK_FUCHSIA_BUFFER_COLLECTION_X_EXTENSION_NAME,
73 #endif
74  };
75 
76  auto enabled_layers =
77  DeviceLayersToEnable(vk, physical_device_, enable_validation_layers_);
78 
79  const char* layers[enabled_layers.size()];
80 
81  for (size_t i = 0; i < enabled_layers.size(); i++) {
82  layers[i] = enabled_layers[i].c_str();
83  }
84 
85  const VkDeviceCreateInfo create_info = {
86  .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
87  .pNext = nullptr,
88  .flags = 0,
89  .queueCreateInfoCount = 1,
90  .pQueueCreateInfos = &queue_create,
91  .enabledLayerCount = static_cast<uint32_t>(enabled_layers.size()),
92  .ppEnabledLayerNames = layers,
93  .enabledExtensionCount = sizeof(extensions) / sizeof(const char*),
94  .ppEnabledExtensionNames = extensions,
95  .pEnabledFeatures = nullptr,
96  };
97 
98  VkDevice device = VK_NULL_HANDLE;
99 
100  if (VK_CALL_LOG_ERROR(vk.CreateDevice(physical_device_, &create_info, nullptr,
101  &device)) != VK_SUCCESS) {
102  FML_DLOG(INFO) << "Could not create device.";
103  return;
104  }
105 
106  device_ = {device,
107  [this](VkDevice device) { vk.DestroyDevice(device, nullptr); }};
108 
109  if (!vk.SetupDeviceProcAddresses(device_)) {
110  FML_DLOG(INFO) << "Could not set up device proc addresses.";
111  return;
112  }
113 
114  VkQueue queue = VK_NULL_HANDLE;
115 
116  vk.GetDeviceQueue(device_, graphics_queue_index_, 0, &queue);
117 
118  if (queue == VK_NULL_HANDLE) {
119  FML_DLOG(INFO) << "Could not get the device queue handle.";
120  return;
121  }
122 
123  queue_ = queue;
124 
125  const VkCommandPoolCreateInfo command_pool_create_info = {
126  .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
127  .pNext = nullptr,
128  .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
129  .queueFamilyIndex = 0,
130  };
131 
132  VkCommandPool command_pool = VK_NULL_HANDLE;
133  if (VK_CALL_LOG_ERROR(vk.CreateCommandPool(device_, &command_pool_create_info,
134  nullptr, &command_pool)) !=
135  VK_SUCCESS) {
136  FML_DLOG(INFO) << "Could not create the command pool.";
137  return;
138  }
139 
140  command_pool_ = {command_pool, [this](VkCommandPool pool) {
141  vk.DestroyCommandPool(device_, pool, nullptr);
142  }};
143 
144  valid_ = true;
145 }
bool SetupDeviceProcAddresses(const VulkanHandle< VkDevice > &device)
bool AreInstanceProcsSetup() const
constexpr auto kVulkanInvalidGraphicsQueueIndex
#define VK_CALL_LOG_ERROR(expression)
std::vector< std::string > DeviceLayersToEnable(const VulkanProcTable &vk, const VulkanHandle< VkPhysicalDevice > &physical_device, bool enable_validation_layers)
static uint32_t FindGraphicsQueueIndex(const std::vector< VkQueueFamilyProperties > &properties)
#define FML_DLOG(severity)
Definition: logging.h:85

◆ ~VulkanDevice()

vulkan::VulkanDevice::~VulkanDevice ( )

Definition at line 147 of file vulkan_device.cc.

References FML_ALLOW_UNUSED_LOCAL, and WaitIdle().

147  {
149 }
#define FML_ALLOW_UNUSED_LOCAL(x)

Member Function Documentation

◆ ChoosePresentMode()

bool vulkan::VulkanDevice::ChoosePresentMode ( const VulkanSurface surface,
VkPresentModeKHR *  present_mode 
) const

Definition at line 318 of file vulkan_device.cc.

References vulkan::VulkanSurface::IsValid().

319  {
320  if (!surface.IsValid() || present_mode == nullptr) {
321  return false;
322  }
323 
324  // https://github.com/LunarG/VulkanSamples/issues/98 indicates that
325  // VK_PRESENT_MODE_FIFO_KHR is preferable on mobile platforms. The problems
326  // mentioned in the ticket w.r.t the application being faster that the refresh
327  // rate of the screen should not be faced by any Flutter platforms as they are
328  // powered by Vsync pulses instead of depending the submit to block.
329  // However, for platforms that don't have VSync providers set up, it is better
330  // to fall back to FIFO. For platforms that do have VSync providers, there
331  // should be little difference. In case there is a need for a mode other than
332  // FIFO, availability checks must be performed here before returning the
333  // result. FIFO is always present.
334  *present_mode = VK_PRESENT_MODE_FIFO_KHR;
335  return true;
336 }

◆ ChooseSurfaceFormat()

int vulkan::VulkanDevice::ChooseSurfaceFormat ( const VulkanSurface surface,
std::vector< VkFormat >  desired_formats,
VkSurfaceFormatKHR *  format 
) const

Definition at line 273 of file vulkan_device.cc.

References vulkan::VulkanSurface::Handle(), vulkan::VulkanSurface::IsValid(), and VK_CALL_LOG_ERROR.

275  {
276 #if OS_ANDROID
277  if (!surface.IsValid() || format == nullptr) {
278  return -1;
279  }
280 
281  uint32_t format_count = 0;
282  if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
283  physical_device_, surface.Handle(), &format_count, nullptr)) !=
284  VK_SUCCESS) {
285  return -1;
286  }
287 
288  if (format_count == 0) {
289  return -1;
290  }
291 
292  std::vector<VkSurfaceFormatKHR> formats;
293  formats.resize(format_count);
294 
295  if (VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceFormatsKHR(
296  physical_device_, surface.Handle(), &format_count, formats.data())) !=
297  VK_SUCCESS) {
298  return -1;
299  }
300 
301  std::map<VkFormat, VkSurfaceFormatKHR> supported_formats;
302  for (uint32_t i = 0; i < format_count; i++) {
303  supported_formats[formats[i].format] = formats[i];
304  }
305 
306  // Try to find the first supported format in the list of desired formats.
307  for (size_t i = 0; i < desired_formats.size(); ++i) {
308  auto found = supported_formats.find(desired_formats[i]);
309  if (found != supported_formats.end()) {
310  *format = found->second;
311  return static_cast<int>(i);
312  }
313  }
314 #endif
315  return -1;
316 }
uint32_t uint32_t * format
#define VK_CALL_LOG_ERROR(expression)

◆ GetCommandPool()

const VulkanHandle< VkCommandPool > & vulkan::VulkanDevice::GetCommandPool ( ) const

Definition at line 176 of file vulkan_device.cc.

176  {
177  return command_pool_;
178 }

◆ GetGraphicsQueueIndex()

uint32_t vulkan::VulkanDevice::GetGraphicsQueueIndex ( ) const

Definition at line 180 of file vulkan_device.cc.

180  {
181  return graphics_queue_index_;
182 }

◆ GetHandle()

const VulkanHandle< VkDevice > & vulkan::VulkanDevice::GetHandle ( ) const

Definition at line 159 of file vulkan_device.cc.

159  {
160  return device_;
161 }

◆ GetPhysicalDeviceFeatures()

bool vulkan::VulkanDevice::GetPhysicalDeviceFeatures ( VkPhysicalDeviceFeatures *  features) const

Definition at line 222 of file vulkan_device.cc.

Referenced by GetPhysicalDeviceFeaturesSkia().

223  {
224  if (features == nullptr || !physical_device_) {
225  return false;
226  }
227  vk.GetPhysicalDeviceFeatures(physical_device_, features);
228  return true;
229 }

◆ GetPhysicalDeviceFeaturesSkia()

bool vulkan::VulkanDevice::GetPhysicalDeviceFeaturesSkia ( uint32_t *  features) const

Definition at line 231 of file vulkan_device.cc.

References flags, and GetPhysicalDeviceFeatures().

231  {
232  if (sk_features == nullptr) {
233  return false;
234  }
235 
236  VkPhysicalDeviceFeatures features;
237 
238  if (!GetPhysicalDeviceFeatures(&features)) {
239  return false;
240  }
241 
242  uint32_t flags = 0;
243 
244  if (features.geometryShader) {
245  flags |= kGeometryShader_GrVkFeatureFlag;
246  }
247  if (features.dualSrcBlend) {
248  flags |= kDualSrcBlend_GrVkFeatureFlag;
249  }
250  if (features.sampleRateShading) {
251  flags |= kSampleRateShading_GrVkFeatureFlag;
252  }
253 
254  *sk_features = flags;
255  return true;
256 }
FlutterSemanticsFlag flags
bool GetPhysicalDeviceFeatures(VkPhysicalDeviceFeatures *features) const

◆ GetPhysicalDeviceHandle()

const VulkanHandle< VkPhysicalDevice > & vulkan::VulkanDevice::GetPhysicalDeviceHandle ( ) const

Definition at line 167 of file vulkan_device.cc.

168  {
169  return physical_device_;
170 }

◆ GetQueueHandle()

const VulkanHandle< VkQueue > & vulkan::VulkanDevice::GetQueueHandle ( ) const

Definition at line 172 of file vulkan_device.cc.

172  {
173  return queue_;
174 }

◆ GetSurfaceCapabilities()

bool vulkan::VulkanDevice::GetSurfaceCapabilities ( const VulkanSurface surface,
VkSurfaceCapabilitiesKHR *  capabilities 
) const

Definition at line 184 of file vulkan_device.cc.

References vulkan::VulkanSurface::GetSize(), vulkan::VulkanSurface::Handle(), vulkan::VulkanSurface::IsValid(), fml::size(), and VK_CALL_LOG_ERROR.

186  {
187 #if OS_ANDROID
188  if (!surface.IsValid() || capabilities == nullptr) {
189  return false;
190  }
191 
192  bool success =
193  VK_CALL_LOG_ERROR(vk.GetPhysicalDeviceSurfaceCapabilitiesKHR(
194  physical_device_, surface.Handle(), capabilities)) == VK_SUCCESS;
195 
196  if (!success) {
197  return false;
198  }
199 
200  // Check if the physical device surface capabilities are valid. If so, there
201  // is nothing more to do.
202  if (capabilities->currentExtent.width != 0xFFFFFFFF &&
203  capabilities->currentExtent.height != 0xFFFFFFFF) {
204  return true;
205  }
206 
207  // Ask the native surface for its size as a fallback.
208  SkISize size = surface.GetSize();
209 
210  if (size.width() == 0 || size.height() == 0) {
211  return false;
212  }
213 
214  capabilities->currentExtent.width = size.width();
215  capabilities->currentExtent.height = size.height();
216  return true;
217 #else
218  return false;
219 #endif
220 }
constexpr std::size_t size(T(&array)[N])
Definition: size.h:13
#define VK_CALL_LOG_ERROR(expression)

◆ IsValid()

bool vulkan::VulkanDevice::IsValid ( ) const

Definition at line 151 of file vulkan_device.cc.

151  {
152  return valid_;
153 }

◆ QueueSubmit()

bool vulkan::VulkanDevice::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

Definition at line 338 of file vulkan_device.cc.

References VK_CALL_LOG_ERROR.

343  {
344  if (wait_semaphores.size() != wait_dest_pipeline_stages.size()) {
345  return false;
346  }
347 
348  const VkSubmitInfo submit_info = {
349  .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
350  .pNext = nullptr,
351  .waitSemaphoreCount = static_cast<uint32_t>(wait_semaphores.size()),
352  .pWaitSemaphores = wait_semaphores.data(),
353  .pWaitDstStageMask = wait_dest_pipeline_stages.data(),
354  .commandBufferCount = static_cast<uint32_t>(command_buffers.size()),
355  .pCommandBuffers = command_buffers.data(),
356  .signalSemaphoreCount = static_cast<uint32_t>(signal_semaphores.size()),
357  .pSignalSemaphores = signal_semaphores.data(),
358  };
359 
360  if (VK_CALL_LOG_ERROR(vk.QueueSubmit(queue_, 1, &submit_info, fence)) !=
361  VK_SUCCESS) {
362  return false;
363  }
364 
365  return true;
366 }
#define VK_CALL_LOG_ERROR(expression)

◆ ReleaseDeviceOwnership()

void vulkan::VulkanDevice::ReleaseDeviceOwnership ( )

Definition at line 163 of file vulkan_device.cc.

References vulkan::VulkanHandle< T >::ReleaseOwnership().

163  {
164  device_.ReleaseOwnership();
165 }

◆ WaitIdle()

bool vulkan::VulkanDevice::WaitIdle ( ) const

Definition at line 155 of file vulkan_device.cc.

References VK_CALL_LOG_ERROR.

Referenced by ~VulkanDevice().

155  {
156  return VK_CALL_LOG_ERROR(vk.DeviceWaitIdle(device_)) == VK_SUCCESS;
157 }
#define VK_CALL_LOG_ERROR(expression)

The documentation for this class was generated from the following files: