Flutter Impeller
impeller::CapabilitiesVK Class Referencefinal

The Vulkan layers and extensions wrangler. More...

#include <capabilities_vk.h>

Inheritance diagram for impeller::CapabilitiesVK:
impeller::Capabilities impeller::BackendCast< CapabilitiesVK, Capabilities >

Public Member Functions

 CapabilitiesVK (bool enable_validations)
 
 ~CapabilitiesVK ()
 
bool IsValid () const
 
bool AreValidationsEnabled () const
 
bool HasOptionalDeviceExtension (OptionalDeviceExtensionVK extension) const
 
std::optional< std::vector< std::string > > GetEnabledLayers () const
 
std::optional< std::vector< std::string > > GetEnabledInstanceExtensions () const
 
std::optional< std::vector< std::string > > GetEnabledDeviceExtensions (const vk::PhysicalDevice &physical_device) const
 
std::optional< vk::PhysicalDeviceFeatures > GetEnabledDeviceFeatures (const vk::PhysicalDevice &physical_device) const
 
bool SetPhysicalDevice (const vk::PhysicalDevice &physical_device)
 
const vk::PhysicalDeviceProperties & GetPhysicalDeviceProperties () const
 
void SetOffscreenFormat (PixelFormat pixel_format) const
 
bool SupportsOffscreenMSAA () const override
 Whether the context backend supports attaching offscreen MSAA color/stencil textures. More...
 
bool SupportsSSBO () const override
 Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines. More...
 
bool SupportsBufferToTextureBlits () const override
 Whether the context backend supports blitting from a given DeviceBuffer view to a texture region (via the relevant BlitPass::AddCopy overloads). More...
 
bool SupportsTextureToTextureBlits () const override
 Whether the context backend supports blitting from one texture region to another texture region (via the relevant BlitPass::AddCopy overloads). More...
 
bool SupportsFramebufferFetch () const override
 Whether the context backend is able to support pipelines with shaders that read from the framebuffer (i.e. pixels that have been written by previous draw calls in the current render pass). More...
 
bool SupportsCompute () const override
 Whether the context backend supports ComputePass. More...
 
bool SupportsComputeSubgroups () const override
 Whether the context backend supports configuring ComputePass command subgroups. More...
 
bool SupportsReadFromResolve () const override
 Whether the context backend supports binding the current RenderPass attachments. This is supported if the backend can guarantee that attachment textures will not be mutated until the render pass has fully completed. More...
 
bool SupportsReadFromOnscreenTexture () const override
 Whether the context backend supports binding the on-screen surface texture for shader reading. More...
 
bool SupportsDecalSamplerAddressMode () const override
 Whether the context backend supports SamplerAddressMode::Decal. More...
 
bool SupportsDeviceTransientTextures () const override
 Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") textures, which are temporary textures kept in tile memory for the duration of the RenderPass it's attached to. More...
 
PixelFormat GetDefaultColorFormat () const override
 Returns a supported PixelFormat for textures that store 4-channel colors (red/green/blue/alpha). More...
 
PixelFormat GetDefaultStencilFormat () const override
 Returns a supported PixelFormat for textures that store stencil information. May include a depth channel if a stencil-only format is not available. More...
 
PixelFormat GetDefaultDepthStencilFormat () const override
 Returns a supported PixelFormat for textures that store both a stencil and depth component. This will never return a depth-only or stencil-only texture. Returns PixelFormat::kUnknown if no suitable depth+stencil format was found. More...
 
- Public Member Functions inherited from impeller::Capabilities
virtual ~Capabilities ()
 

Additional Inherited Members

- Static Public Member Functions inherited from impeller::BackendCast< CapabilitiesVK, Capabilities >
static CapabilitiesVKCast (Capabilities &base)
 
static const CapabilitiesVKCast (const Capabilities &base)
 
static CapabilitiesVKCast (Capabilities *base)
 
static const CapabilitiesVKCast (const Capabilities *base)
 
- Protected Member Functions inherited from impeller::Capabilities
 Capabilities ()
 
 FML_DISALLOW_COPY_AND_ASSIGN (Capabilities)
 

Detailed Description

The Vulkan layers and extensions wrangler.

Definition at line 30 of file capabilities_vk.h.

Constructor & Destructor Documentation

◆ CapabilitiesVK()

impeller::CapabilitiesVK::CapabilitiesVK ( bool  enable_validations)
explicit

Definition at line 17 of file capabilities_vk.cc.

17  {
18  auto extensions = vk::enumerateInstanceExtensionProperties();
19  auto layers = vk::enumerateInstanceLayerProperties();
20 
21  if (extensions.result != vk::Result::eSuccess ||
22  layers.result != vk::Result::eSuccess) {
23  return;
24  }
25 
26  for (const auto& ext : extensions.value) {
27  exts_[kInstanceLayer].insert(ext.extensionName);
28  }
29 
30  for (const auto& layer : layers.value) {
31  const std::string layer_name = layer.layerName;
32  auto layer_exts = vk::enumerateInstanceExtensionProperties(layer_name);
33  if (layer_exts.result != vk::Result::eSuccess) {
34  return;
35  }
36  for (const auto& layer_ext : layer_exts.value) {
37  exts_[layer_name].insert(layer_ext.extensionName);
38  }
39  }
40 
41  validations_enabled_ =
42  enable_validations && HasLayer("VK_LAYER_KHRONOS_validation");
43  if (enable_validations && !validations_enabled_) {
44  FML_LOG(ERROR)
45  << "Requested Impeller context creation with validations but the "
46  "validation layers could not be found. Expect no Vulkan validation "
47  "checks!";
48  }
49  if (validations_enabled_) {
50  FML_LOG(INFO) << "Vulkan validations are enabled.";
51  }
52  is_valid_ = true;
53 }

References impeller::kInstanceLayer.

◆ ~CapabilitiesVK()

impeller::CapabilitiesVK::~CapabilitiesVK ( )
default

Member Function Documentation

◆ AreValidationsEnabled()

bool impeller::CapabilitiesVK::AreValidationsEnabled ( ) const

Definition at line 61 of file capabilities_vk.cc.

61  {
62  return validations_enabled_;
63 }

Referenced by impeller::DebugReportVK::DebugReportVK(), and impeller::testing::TEST().

◆ GetDefaultColorFormat()

PixelFormat impeller::CapabilitiesVK::GetDefaultColorFormat ( ) const
overridevirtual

Returns a supported PixelFormat for textures that store 4-channel colors (red/green/blue/alpha).

Implements impeller::Capabilities.

Definition at line 464 of file capabilities_vk.cc.

464  {
465  return default_color_format_;
466 }

◆ GetDefaultDepthStencilFormat()

PixelFormat impeller::CapabilitiesVK::GetDefaultDepthStencilFormat ( ) const
overridevirtual

Returns a supported PixelFormat for textures that store both a stencil and depth component. This will never return a depth-only or stencil-only texture. Returns PixelFormat::kUnknown if no suitable depth+stencil format was found.

Implements impeller::Capabilities.

Definition at line 474 of file capabilities_vk.cc.

474  {
475  return default_depth_stencil_format_;
476 }

◆ GetDefaultStencilFormat()

PixelFormat impeller::CapabilitiesVK::GetDefaultStencilFormat ( ) const
overridevirtual

Returns a supported PixelFormat for textures that store stencil information. May include a depth channel if a stencil-only format is not available.

Implements impeller::Capabilities.

Definition at line 469 of file capabilities_vk.cc.

469  {
470  return default_stencil_format_;
471 }

◆ GetEnabledDeviceExtensions()

std::optional< std::vector< std::string > > impeller::CapabilitiesVK::GetEnabledDeviceExtensions ( const vk::PhysicalDevice &  physical_device) const

Definition at line 192 of file capabilities_vk.cc.

193  {
194  auto exts = GetSupportedDeviceExtensions(physical_device);
195 
196  if (!exts.has_value()) {
197  return std::nullopt;
198  }
199 
200  std::vector<std::string> enabled;
201 
202  if (exts->find("VK_KHR_swapchain") == exts->end()) {
203  VALIDATION_LOG << "Device does not support the swapchain extension.";
204  return std::nullopt;
205  }
206  enabled.push_back("VK_KHR_swapchain");
207 
208  // Required for non-conformant implementations like MoltenVK.
209  if (exts->find("VK_KHR_portability_subset") != exts->end()) {
210  enabled.push_back("VK_KHR_portability_subset");
211  }
212 
213 #ifdef FML_OS_ANDROID
214  if (exts->find("VK_ANDROID_external_memory_android_hardware_buffer") ==
215  exts->end()) {
217  << "Device does not support "
218  "VK_ANDROID_external_memory_android_hardware_buffer extension.";
219  return std::nullopt;
220  }
221  enabled.push_back("VK_ANDROID_external_memory_android_hardware_buffer");
222  enabled.push_back("VK_EXT_queue_family_foreign");
223 #endif
224 
225  // Enable all optional extensions if the device supports it.
226  IterateOptionalDeviceExtensions([&](auto ext) {
227  auto ext_name = GetDeviceExtensionName(ext);
228  if (exts->find(ext_name) != exts->end()) {
229  enabled.push_back(ext_name);
230  }
231  });
232 
233  return enabled;
234 }

References impeller::GetDeviceExtensionName(), impeller::GetSupportedDeviceExtensions(), impeller::IterateOptionalDeviceExtensions(), and VALIDATION_LOG.

Referenced by GetEnabledDeviceFeatures().

◆ GetEnabledDeviceFeatures()

std::optional< vk::PhysicalDeviceFeatures > impeller::CapabilitiesVK::GetEnabledDeviceFeatures ( const vk::PhysicalDevice &  physical_device) const

Definition at line 286 of file capabilities_vk.cc.

287  {
289  VALIDATION_LOG << "Device doesn't support the required formats.";
290  return std::nullopt;
291  }
292 
293  if (!HasRequiredProperties(device)) {
294  VALIDATION_LOG << "Device doesn't support the required properties.";
295  return std::nullopt;
296  }
297 
298  if (!HasRequiredQueues(device)) {
299  VALIDATION_LOG << "Device doesn't support the required queues.";
300  return std::nullopt;
301  }
302 
303  if (!GetEnabledDeviceExtensions(device).has_value()) {
304  VALIDATION_LOG << "Device doesn't support the required queues.";
305  return std::nullopt;
306  }
307 
308  const auto device_features = device.getFeatures();
309 
310  vk::PhysicalDeviceFeatures required;
311 
312  // We require this for enabling wireframes in the playground. But its not
313  // necessarily a big deal if we don't have this feature.
314  required.fillModeNonSolid = device_features.fillModeNonSolid;
315 
316  return required;
317 }

References GetEnabledDeviceExtensions(), impeller::HasRequiredProperties(), impeller::HasRequiredQueues(), impeller::PhysicalDeviceSupportsRequiredFormats(), and VALIDATION_LOG.

Referenced by impeller::PickPhysicalDevice().

◆ GetEnabledInstanceExtensions()

std::optional< std::vector< std::string > > impeller::CapabilitiesVK::GetEnabledInstanceExtensions ( ) const

Definition at line 78 of file capabilities_vk.cc.

78  {
79  std::vector<std::string> required;
80 
81  if (!HasExtension("VK_KHR_surface")) {
82  // Swapchain support is required and this is a dependency of
83  // VK_KHR_swapchain.
84  VALIDATION_LOG << "Could not find the surface extension.";
85  return std::nullopt;
86  }
87  required.push_back("VK_KHR_surface");
88 
89  auto has_wsi = false;
90  if (HasExtension("VK_MVK_macos_surface")) {
91  required.push_back("VK_MVK_macos_surface");
92  has_wsi = true;
93  }
94 
95  if (HasExtension("VK_EXT_metal_surface")) {
96  required.push_back("VK_EXT_metal_surface");
97  has_wsi = true;
98  }
99 
100  if (HasExtension("VK_KHR_portability_enumeration")) {
101  required.push_back("VK_KHR_portability_enumeration");
102  has_wsi = true;
103  }
104 
105  if (HasExtension("VK_KHR_win32_surface")) {
106  required.push_back("VK_KHR_win32_surface");
107  has_wsi = true;
108  }
109 
110  if (HasExtension("VK_KHR_android_surface")) {
111  required.push_back("VK_KHR_android_surface");
112  has_wsi = true;
113  }
114 
115  if (HasExtension("VK_KHR_xcb_surface")) {
116  required.push_back("VK_KHR_xcb_surface");
117  has_wsi = true;
118  }
119 
120  if (HasExtension("VK_KHR_xlib_surface")) {
121  required.push_back("VK_KHR_xlib_surface");
122  has_wsi = true;
123  }
124 
125  if (HasExtension("VK_KHR_wayland_surface")) {
126  required.push_back("VK_KHR_wayland_surface");
127  has_wsi = true;
128  }
129 
130  if (!has_wsi) {
131  // Don't really care which WSI extension there is as long there is at least
132  // one.
133  VALIDATION_LOG << "Could not find a WSI extension.";
134  return std::nullopt;
135  }
136 
137  if (validations_enabled_) {
138  if (!HasExtension("VK_EXT_debug_utils")) {
139  VALIDATION_LOG << "Requested validations but could not find the "
140  "VK_EXT_debug_utils extension.";
141  return std::nullopt;
142  }
143  required.push_back("VK_EXT_debug_utils");
144 
145  if (HasExtension("VK_EXT_validation_features")) {
146  // It's valid to not have `VK_EXT_validation_features` available. That's
147  // the case when using AGI as a frame debugger.
148  required.push_back("VK_EXT_validation_features");
149  }
150  }
151 
152  return required;
153 }

References VALIDATION_LOG.

◆ GetEnabledLayers()

std::optional< std::vector< std::string > > impeller::CapabilitiesVK::GetEnabledLayers ( ) const

Definition at line 65 of file capabilities_vk.cc.

66  {
67  std::vector<std::string> required;
68 
69  if (validations_enabled_) {
70  // The presence of this layer is already checked in the ctor.
71  required.push_back("VK_LAYER_KHRONOS_validation");
72  }
73 
74  return required;
75 }

◆ GetPhysicalDeviceProperties()

const vk::PhysicalDeviceProperties & impeller::CapabilitiesVK::GetPhysicalDeviceProperties ( ) const

Definition at line 479 of file capabilities_vk.cc.

479  {
480  return device_properties_;
481 }

◆ HasOptionalDeviceExtension()

bool impeller::CapabilitiesVK::HasOptionalDeviceExtension ( OptionalDeviceExtensionVK  extension) const

Definition at line 483 of file capabilities_vk.cc.

484  {
485  return optional_device_extensions_.find(extension) !=
486  optional_device_extensions_.end();
487 }

◆ IsValid()

bool impeller::CapabilitiesVK::IsValid ( ) const

Definition at line 57 of file capabilities_vk.cc.

57  {
58  return is_valid_;
59 }

◆ SetOffscreenFormat()

void impeller::CapabilitiesVK::SetOffscreenFormat ( PixelFormat  pixel_format) const

Definition at line 337 of file capabilities_vk.cc.

337  {
338  default_color_format_ = pixel_format;
339 }

Referenced by impeller::ContextVK::SetOffscreenFormat().

◆ SetPhysicalDevice()

bool impeller::CapabilitiesVK::SetPhysicalDevice ( const vk::PhysicalDevice &  physical_device)

Definition at line 341 of file capabilities_vk.cc.

341  {
342  if (HasSuitableDepthStencilFormat(device, vk::Format::eD32SfloatS8Uint)) {
343  default_depth_stencil_format_ = PixelFormat::kD32FloatS8UInt;
344  } else if (HasSuitableDepthStencilFormat(device,
345  vk::Format::eD24UnormS8Uint)) {
346  default_depth_stencil_format_ = PixelFormat::kD24UnormS8Uint;
347  } else {
348  default_depth_stencil_format_ = PixelFormat::kUnknown;
349  }
350 
351  if (HasSuitableDepthStencilFormat(device, vk::Format::eS8Uint)) {
352  default_stencil_format_ = PixelFormat::kS8UInt;
353  } else if (default_stencil_format_ != PixelFormat::kUnknown) {
354  default_stencil_format_ = default_depth_stencil_format_;
355  } else {
356  return false;
357  }
358 
359  device_properties_ = device.getProperties();
360 
361  auto physical_properties_2 =
362  device.getProperties2<vk::PhysicalDeviceProperties2,
363  vk::PhysicalDeviceSubgroupProperties>();
364 
365  // Currently shaders only want access to arithmetic subgroup features.
366  // If that changes this needs to get updated, and so does Metal (which right
367  // now assumes it from compile time flags based on the MSL target version).
368 
369  supports_compute_subgroups_ =
370  !!(physical_properties_2.get<vk::PhysicalDeviceSubgroupProperties>()
371  .supportedOperations &
372  vk::SubgroupFeatureFlagBits::eArithmetic);
373 
374  {
375  // Query texture support.
376  // TODO(jonahwilliams):
377  // https://github.com/flutter/flutter/issues/129784
378  vk::PhysicalDeviceMemoryProperties memory_properties;
379  device.getMemoryProperties(&memory_properties);
380 
381  for (auto i = 0u; i < memory_properties.memoryTypeCount; i++) {
382  if (memory_properties.memoryTypes[i].propertyFlags &
383  vk::MemoryPropertyFlagBits::eLazilyAllocated) {
384  supports_device_transient_textures_ = true;
385  }
386  }
387  }
388 
389  // Determine the optional device extensions this physical device supports.
390  {
391  optional_device_extensions_.clear();
392  auto exts = GetSupportedDeviceExtensions(device);
393  if (!exts.has_value()) {
394  return false;
395  }
396  IterateOptionalDeviceExtensions([&](auto ext) {
397  auto ext_name = GetDeviceExtensionName(ext);
398  if (exts->find(ext_name) != exts->end()) {
399  optional_device_extensions_.insert(ext);
400  }
401  });
402  }
403 
404  return true;
405 }

References impeller::GetDeviceExtensionName(), impeller::GetSupportedDeviceExtensions(), impeller::HasSuitableDepthStencilFormat(), impeller::IterateOptionalDeviceExtensions(), impeller::kD24UnormS8Uint, impeller::kD32FloatS8UInt, impeller::kS8UInt, and impeller::kUnknown.

◆ SupportsBufferToTextureBlits()

bool impeller::CapabilitiesVK::SupportsBufferToTextureBlits ( ) const
overridevirtual

Whether the context backend supports blitting from a given DeviceBuffer view to a texture region (via the relevant BlitPass::AddCopy overloads).

Implements impeller::Capabilities.

Definition at line 418 of file capabilities_vk.cc.

418  {
419  return true;
420 }

◆ SupportsCompute()

bool impeller::CapabilitiesVK::SupportsCompute ( ) const
overridevirtual

Whether the context backend supports ComputePass.

Implements impeller::Capabilities.

Definition at line 433 of file capabilities_vk.cc.

433  {
434  // Vulkan 1.1 requires support for compute.
435  return true;
436 }

◆ SupportsComputeSubgroups()

bool impeller::CapabilitiesVK::SupportsComputeSubgroups ( ) const
overridevirtual

Whether the context backend supports configuring ComputePass command subgroups.

Implements impeller::Capabilities.

Definition at line 439 of file capabilities_vk.cc.

439  {
440  // Set by |SetPhysicalDevice|.
441  return supports_compute_subgroups_;
442 }

◆ SupportsDecalSamplerAddressMode()

bool impeller::CapabilitiesVK::SupportsDecalSamplerAddressMode ( ) const
overridevirtual

Whether the context backend supports SamplerAddressMode::Decal.

Implements impeller::Capabilities.

Definition at line 454 of file capabilities_vk.cc.

454  {
455  return true;
456 }

◆ SupportsDeviceTransientTextures()

bool impeller::CapabilitiesVK::SupportsDeviceTransientTextures ( ) const
overridevirtual

Whether the context backend supports allocating StorageMode::kDeviceTransient (aka "memoryless") textures, which are temporary textures kept in tile memory for the duration of the RenderPass it's attached to.

This feature is especially useful for MSAA and stencils.

Implements impeller::Capabilities.

Definition at line 459 of file capabilities_vk.cc.

459  {
460  return supports_device_transient_textures_;
461 }

◆ SupportsFramebufferFetch()

bool impeller::CapabilitiesVK::SupportsFramebufferFetch ( ) const
overridevirtual

Whether the context backend is able to support pipelines with shaders that read from the framebuffer (i.e. pixels that have been written by previous draw calls in the current render pass).

Example of reading from the first color attachment in a GLSL shader: ``` uniform subpassInput subpass_input;

out vec4 frag_color;

void main() { vec4 color = subpassLoad(subpass_input); // Invert the colors drawn to the framebuffer. frag_color = vec4(vec3(1) - color.rgb, color.a); } ```

Implements impeller::Capabilities.

Definition at line 428 of file capabilities_vk.cc.

428  {
429  return false;
430 }

◆ SupportsOffscreenMSAA()

bool impeller::CapabilitiesVK::SupportsOffscreenMSAA ( ) const
overridevirtual

Whether the context backend supports attaching offscreen MSAA color/stencil textures.

Implements impeller::Capabilities.

Definition at line 408 of file capabilities_vk.cc.

408  {
409  return true;
410 }

◆ SupportsReadFromOnscreenTexture()

bool impeller::CapabilitiesVK::SupportsReadFromOnscreenTexture ( ) const
overridevirtual

Whether the context backend supports binding the on-screen surface texture for shader reading.

Implements impeller::Capabilities.

Definition at line 450 of file capabilities_vk.cc.

450  {
451  return false;
452 }

◆ SupportsReadFromResolve()

bool impeller::CapabilitiesVK::SupportsReadFromResolve ( ) const
overridevirtual

Whether the context backend supports binding the current RenderPass attachments. This is supported if the backend can guarantee that attachment textures will not be mutated until the render pass has fully completed.

This is possible because many mobile graphics cards track RenderPass attachment state in intermediary tile memory prior to Storing the pass in the heap allocated attachments on DRAM. Metal's hazard tracking and Vulkan's barriers are granular enough to allow for safely accessing attachment textures prior to storage in the same RenderPass.

Implements impeller::Capabilities.

Definition at line 445 of file capabilities_vk.cc.

445  {
446  return false;
447 }

◆ SupportsSSBO()

bool impeller::CapabilitiesVK::SupportsSSBO ( ) const
overridevirtual

Whether the context backend supports binding Shader Storage Buffer Objects (SSBOs) to pipelines.

Implements impeller::Capabilities.

Definition at line 413 of file capabilities_vk.cc.

413  {
414  return true;
415 }

◆ SupportsTextureToTextureBlits()

bool impeller::CapabilitiesVK::SupportsTextureToTextureBlits ( ) const
overridevirtual

Whether the context backend supports blitting from one texture region to another texture region (via the relevant BlitPass::AddCopy overloads).

Implements impeller::Capabilities.

Definition at line 423 of file capabilities_vk.cc.

423  {
424  return true;
425 }

The documentation for this class was generated from the following files:
impeller::HasRequiredProperties
static bool HasRequiredProperties(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:262
impeller::kInstanceLayer
static constexpr const char * kInstanceLayer
Definition: capabilities_vk.cc:15
impeller::HasSuitableDepthStencilFormat
static bool HasSuitableDepthStencilFormat(const vk::PhysicalDevice &device, vk::Format format)
Definition: capabilities_vk.cc:244
impeller::HasRequiredQueues
static bool HasRequiredQueues(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:271
impeller::IterateOptionalDeviceExtensions
static void IterateOptionalDeviceExtensions(const std::function< void(OptionalDeviceExtensionVK)> &it)
Definition: capabilities_vk.cc:165
impeller::PhysicalDeviceSupportsRequiredFormats
static bool PhysicalDeviceSupportsRequiredFormats(const vk::PhysicalDevice &device)
Definition: capabilities_vk.cc:251
impeller::GetSupportedDeviceExtensions
static std::optional< std::set< std::string > > GetSupportedDeviceExtensions(const vk::PhysicalDevice &physical_device)
Definition: capabilities_vk.cc:176
impeller::PixelFormat::kD32FloatS8UInt
@ kD32FloatS8UInt
impeller::PixelFormat::kUnknown
@ kUnknown
impeller::GetDeviceExtensionName
static const char * GetDeviceExtensionName(OptionalDeviceExtensionVK ext)
Definition: capabilities_vk.cc:155
impeller::PixelFormat::kD24UnormS8Uint
@ kD24UnormS8Uint
VALIDATION_LOG
#define VALIDATION_LOG
Definition: validation.h:60
impeller::PixelFormat::kS8UInt
@ kS8UInt
impeller::CapabilitiesVK::GetEnabledDeviceExtensions
std::optional< std::vector< std::string > > GetEnabledDeviceExtensions(const vk::PhysicalDevice &physical_device) const
Definition: capabilities_vk.cc:192