Flutter Impeller
impeller::AllocatedTextureSourceVK Class Referencefinal
Inheritance diagram for impeller::AllocatedTextureSourceVK:
impeller::TextureSourceVK

Public Member Functions

 AllocatedTextureSourceVK (const ContextVK &context, const TextureDescriptor &desc, VmaAllocator allocator, vk::Device device, bool supports_memoryless_textures)
 
 ~AllocatedTextureSourceVK ()=default
 
bool IsValid () const
 
vk::Image GetImage () const override
 Get the image handle for this texture source. More...
 
vk::ImageView GetImageView () const override
 Retrieve the image view used for sampling/blitting/compute with this texture source. More...
 
vk::ImageView GetRenderTargetView (uint32_t mip_level, uint32_t array_layer) const override
 Retrieve the image view used to attach a specific subresource of this texture as a render target. More...
 
bool IsSwapchainImage () const override
 Determines if swapchain image. That is, an image used as the root render target. More...
 
- Public Member Functions inherited from impeller::TextureSourceVK
virtual ~TextureSourceVK ()
 
const TextureDescriptor & GetTextureDescriptor () const
 Gets the texture descriptor for this image source. More...
 
fml::Status SetLayout (const BarrierVK &barrier) const
 Encodes the layout transition barrier to barrier.cmd_buffer for the image. More...
 
vk::ImageLayout SetLayoutWithoutEncoding (vk::ImageLayout layout) const
 Store the layout of the image. More...
 
vk::ImageLayout GetLayout () const
 Get the last layout assigned to the TextureSourceVK. More...
 
virtual std::shared_ptr< YUVConversionVK > GetYUVConversion () const
 When sampling from textures whose formats are not known to Vulkan, a custom conversion is necessary to setup custom samplers. This accessor provides this conversion if one is present. Most texture source have none. More...
 
void SetCachedFrameData (const FramebufferAndRenderPass &data, SampleCount sample_count, uint32_t mip_level=0u, uint32_t slice=0u)
 
FramebufferAndRenderPass GetCachedFrameData (SampleCount sample_count, uint32_t mip_level=0u, uint32_t slice=0u) const
 

Additional Inherited Members

- Protected Member Functions inherited from impeller::TextureSourceVK
 TextureSourceVK (TextureDescriptor desc)
 
- Protected Attributes inherited from impeller::TextureSourceVK
const TextureDescriptor desc_
 

Detailed Description

Definition at line 289 of file allocator_vk.cc.

Constructor & Destructor Documentation

◆ AllocatedTextureSourceVK()

impeller::AllocatedTextureSourceVK::AllocatedTextureSourceVK ( const ContextVK &  context,
const TextureDescriptor &  desc,
VmaAllocator  allocator,
vk::Device  device,
bool  supports_memoryless_textures 
)
inline

Definition at line 291 of file allocator_vk.cc.

296  : TextureSourceVK(desc), resource_(context.GetResourceManager()) {
297  FML_DCHECK(desc.format != PixelFormat::kUnknown);
298  vk::StructureChain<vk::ImageCreateInfo, vk::ImageCompressionControlEXT>
299  image_info_chain;
300  auto& image_info = image_info_chain.get();
301  image_info.flags = ToVKImageCreateFlags(desc.type);
302  image_info.imageType = vk::ImageType::e2D;
303  image_info.format = ToVKImageFormat(desc.format);
304  image_info.extent = VkExtent3D{
305  static_cast<uint32_t>(desc.size.width), // width
306  static_cast<uint32_t>(desc.size.height), // height
307  1u // depth
308  };
309  image_info.samples = ToVKSampleCount(desc.sample_count);
310  image_info.mipLevels = desc.mip_count;
311  image_info.arrayLayers = ToArrayLayerCount(desc.type);
312  image_info.tiling = vk::ImageTiling::eOptimal;
313  image_info.initialLayout = vk::ImageLayout::eUndefined;
314  image_info.usage = AllocatorVK::ToVKImageUsageFlags(
315  desc.format, desc.usage, desc.storage_mode,
316  supports_memoryless_textures);
317  image_info.sharingMode = vk::SharingMode::eExclusive;
318 
319  vk::ImageCompressionFixedRateFlagsEXT frc_rates[1] = {
320  vk::ImageCompressionFixedRateFlagBitsEXT::eNone};
321 
322  const auto frc_rate =
323  CapabilitiesVK::Cast(*context.GetCapabilities())
324  .GetSupportedFRCRate(desc.compression_type,
325  FRCFormatDescriptor{image_info});
326  if (frc_rate.has_value()) {
327  // This array must not be in a temporary scope.
328  frc_rates[0] = frc_rate.value();
329 
330  auto& compression_info =
331  image_info_chain.get<vk::ImageCompressionControlEXT>();
332  compression_info.pFixedRateFlags = frc_rates;
333  compression_info.compressionControlPlaneCount = 1u;
334  compression_info.flags =
335  vk::ImageCompressionFlagBitsEXT::eFixedRateExplicit;
336  } else {
337  image_info_chain.unlink<vk::ImageCompressionControlEXT>();
338  }
339 
340  VmaAllocationCreateInfo alloc_nfo = {};
341 
342  alloc_nfo.usage = ToVMAMemoryUsage();
343  alloc_nfo.preferredFlags =
344  static_cast<VkMemoryPropertyFlags>(ToVKTextureMemoryPropertyFlags(
345  desc.storage_mode, supports_memoryless_textures));
346  alloc_nfo.flags = ToVmaAllocationCreateFlags(desc.storage_mode);
347 
348  VkImage vk_image = VK_NULL_HANDLE;
349  VmaAllocation allocation = {};
350  VmaAllocationInfo allocation_info = {};
351 
352  // Performs the VMA image allocation using the current create-info chain.
353  // The native create-info is re-derived from the chain on each call, so an
354  // unlink of the compression-control struct between calls is reflected.
355  const auto try_create_image = [&]() -> vk::Result {
356  vk::ImageCreateInfo::NativeType create_info_native =
357  static_cast<vk::ImageCreateInfo::NativeType>(
358  image_info_chain.get<vk::ImageCreateInfo>());
359  return vk::Result{::vmaCreateImage(allocator, //
360  &create_info_native, //
361  &alloc_nfo, //
362  &vk_image, //
363  &allocation, //
364  &allocation_info //
365  )};
366  };
367 
368  // Fixed-rate compression was requested iff a rate was selected above.
369  const bool requested_compression = frc_rate.has_value();
370  vk::Result alloc_result = try_create_image();
371 
372  // Some drivers (e.g. PowerVR) can return VK_ERROR_COMPRESSION_EXHAUSTED_EXT
373  // when fixed-rate compression resources are depleted. Per the Vulkan spec
374  // this error is only returned for fixed-rate compression requests, so
375  // retrying without compression is a valid recovery. Without it the
376  // allocation fails, the texture is invalid, and the resulting null render
377  // target crashes the raster thread.
378  if (alloc_result == vk::Result::eErrorCompressionExhaustedEXT &&
379  requested_compression) {
380  static std::once_flag warn_once;
381  std::call_once(warn_once, [] {
382  FML_LOG(WARNING)
383  << "Fixed-rate image compression exhausted; falling back to "
384  "uncompressed image allocation. (This message is logged once.)";
385  });
386  // The compression-control struct is only present here because compression
387  // was requested above, so unlinking it once is safe (no double-unlink).
388  image_info_chain.unlink<vk::ImageCompressionControlEXT>();
389  alloc_result = try_create_image();
390  }
391 
392  if (alloc_result != vk::Result::eSuccess) {
393  VALIDATION_LOG << "Unable to allocate Vulkan Image: "
394  << vk::to_string(alloc_result)
395  << " Type: " << TextureTypeToString(desc.type)
396  << " Mode: " << StorageModeToString(desc.storage_mode)
397  << " Usage: " << TextureUsageMaskToString(desc.usage)
398  << " [VK]Flags: " << vk::to_string(image_info.flags)
399  << " [VK]Format: " << vk::to_string(image_info.format)
400  << " [VK]Usage: " << vk::to_string(image_info.usage)
401  << " [VK]Mem. Flags: "
402  << vk::to_string(
403  vk::MemoryPropertyFlags(alloc_nfo.preferredFlags));
404  return;
405  }
406 
407  auto image = vk::Image{vk_image};
408 
409  vk::ImageViewCreateInfo view_info = {};
410  view_info.image = image;
411  view_info.viewType = ToVKImageViewType(desc.type);
412  view_info.format = image_info.format;
413  view_info.subresourceRange.aspectMask = ToVKImageAspectFlags(desc.format);
414  view_info.subresourceRange.levelCount = image_info.mipLevels;
415  view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type);
416 
417  // Vulkan does not have an image format that is equivalent to
418  // `MTLPixelFormatA8Unorm`, so we use `R8Unorm` instead. Given that the
419  // shaders expect that alpha channel to be set in the cases, we swizzle.
420  // See: https://github.com/flutter/flutter/issues/115461 for more details.
421  if (desc.format == PixelFormat::kA8UNormInt) {
422  view_info.components.a = vk::ComponentSwizzle::eR;
423  view_info.components.r = vk::ComponentSwizzle::eA;
424  }
425 
426  auto [result, image_view] = device.createImageViewUnique(view_info);
427  if (result != vk::Result::eSuccess) {
428  VALIDATION_LOG << "Unable to create an image view for allocation: "
429  << vk::to_string(result);
430  return;
431  }
432  // Create one 2D attachment view per (mip level, array layer) so a
433  // specific subresource can be rendered into. Render targets are usually a
434  // single 2D mip (one view); cube and mipmapped render targets get the
435  // full set. Non-render-target textures only need the base view.
436  view_info.viewType = vk::ImageViewType::e2D;
437  view_info.subresourceRange.levelCount = 1u;
438  view_info.subresourceRange.layerCount = 1u;
439  const bool is_render_target = !!(desc.usage & TextureUsage::kRenderTarget);
440  const uint32_t rt_mip_count = is_render_target ? image_info.mipLevels : 1u;
441  const uint32_t rt_layer_count =
442  is_render_target ? ToArrayLayerCount(desc.type) : 1u;
443  std::vector<vk::UniqueImageView> rt_image_views;
444  rt_image_views.reserve(rt_mip_count * rt_layer_count);
445  for (uint32_t mip = 0; mip < rt_mip_count; mip++) {
446  for (uint32_t layer = 0; layer < rt_layer_count; layer++) {
447  view_info.subresourceRange.baseMipLevel = mip;
448  view_info.subresourceRange.baseArrayLayer = layer;
449  auto [rt_result, rt_image_view] =
450  device.createImageViewUnique(view_info);
451  if (rt_result != vk::Result::eSuccess) {
452  VALIDATION_LOG << "Unable to create a render target image view: "
453  << vk::to_string(rt_result);
454  return;
455  }
456  rt_image_views.push_back(std::move(rt_image_view));
457  }
458  }
459 
460  resource_.Swap(ImageResource(
461  ImageVMA{allocator, allocation, image}, std::move(image_view),
462  std::move(rt_image_views), context.GetResourceAllocator(),
463  context.GetDeviceHolder()));
464  is_valid_ = true;
465  }
static vk::ImageUsageFlags ToVKImageUsageFlags(PixelFormat format, TextureUsageMask usage, StorageMode mode, bool supports_memoryless_textures)
static CapabilitiesVK & Cast(Capabilities &base)
Definition: backend_cast.h:13
std::optional< vk::ImageCompressionFixedRateFlagBitsEXT > GetSupportedFRCRate(CompressionType compression_type, const FRCFormatDescriptor &desc) const
Get the fixed compression rate supported by the context for the given format and usage.
TextureSourceVK(TextureDescriptor desc)
void Swap(ResourceType &&other)
Reclaims the existing resource, if any, and replaces it.
constexpr uint32_t ToArrayLayerCount(TextureType type)
Definition: formats_vk.h:611
std::string TextureUsageMaskToString(TextureUsageMask mask)
Definition: formats.cc:95
constexpr const char * TextureTypeToString(TextureType type)
Definition: formats.h:457
static constexpr VmaMemoryUsage ToVMAMemoryUsage()
constexpr vk::ImageViewType ToVKImageViewType(TextureType type)
Definition: formats_vk.h:625
constexpr vk::SampleCountFlagBits ToVKSampleCount(SampleCount sample_count)
Definition: formats_vk.h:250
constexpr vk::Format ToVKImageFormat(PixelFormat format)
Definition: formats_vk.h:146
static VmaAllocationCreateFlags ToVmaAllocationCreateFlags(StorageMode mode)
static constexpr vk::Flags< vk::MemoryPropertyFlagBits > ToVKTextureMemoryPropertyFlags(StorageMode mode, bool supports_memoryless_textures)
constexpr const char * StorageModeToString(StorageMode mode)
Definition: formats.h:60
constexpr vk::ImageCreateFlags ToVKImageCreateFlags(TextureType type)
Definition: formats_vk.h:639
constexpr vk::ImageAspectFlags ToVKImageAspectFlags(PixelFormat format)
Definition: formats_vk.h:567
std::shared_ptr< ContextGLES > context
#define VALIDATION_LOG
Definition: validation.h:91

References impeller::TextureDescriptor::compression_type, context, impeller::TextureDescriptor::format, impeller::TSize< T >::height, impeller::TextureDescriptor::mip_count, impeller::TextureDescriptor::sample_count, impeller::TextureDescriptor::size, impeller::TextureDescriptor::storage_mode, impeller::StorageModeToString(), impeller::TextureTypeToString(), impeller::TextureUsageMaskToString(), impeller::ToArrayLayerCount(), impeller::ToVKImageAspectFlags(), impeller::ToVKImageCreateFlags(), impeller::ToVKImageFormat(), impeller::ToVKImageViewType(), impeller::ToVKSampleCount(), impeller::ToVKTextureMemoryPropertyFlags(), impeller::ToVmaAllocationCreateFlags(), impeller::ToVMAMemoryUsage(), impeller::TextureDescriptor::type, impeller::TextureDescriptor::usage, VALIDATION_LOG, and impeller::TSize< T >::width.

◆ ~AllocatedTextureSourceVK()

impeller::AllocatedTextureSourceVK::~AllocatedTextureSourceVK ( )
default

Member Function Documentation

◆ GetImage()

vk::Image impeller::AllocatedTextureSourceVK::GetImage ( ) const
inlineoverridevirtual

Get the image handle for this texture source.

Returns
The image.

Implements impeller::TextureSourceVK.

Definition at line 471 of file allocator_vk.cc.

471 { return resource_->image.get().image; }

◆ GetImageView()

vk::ImageView impeller::AllocatedTextureSourceVK::GetImageView ( ) const
inlineoverridevirtual

Retrieve the image view used for sampling/blitting/compute with this texture source.

Returns
The image view.

Implements impeller::TextureSourceVK.

Definition at line 473 of file allocator_vk.cc.

473  {
474  return resource_->image_view.get();
475  }

◆ GetRenderTargetView()

vk::ImageView impeller::AllocatedTextureSourceVK::GetRenderTargetView ( uint32_t  mip_level,
uint32_t  array_layer 
) const
inlineoverridevirtual

Retrieve the image view used to attach a specific subresource of this texture as a render target.

The returned view covers a single mip level and a single array layer (or cube map face), since attachment views cannot span multiple levels or layers.

Parameters
[in]mip_levelThe mip level to attach.
[in]array_layerThe array layer or cube map face to attach.
Returns
The render target view.

Implements impeller::TextureSourceVK.

Definition at line 477 of file allocator_vk.cc.

478  {
479  const auto& views = resource_->rt_image_views;
480  if (views.empty()) {
481  return VK_NULL_HANDLE;
482  }
483  const uint32_t layer_count = ToArrayLayerCount(GetTextureDescriptor().type);
484  const size_t index =
485  static_cast<size_t>(mip_level) * layer_count + array_layer;
486  return index < views.size() ? views[index].get() : views[0].get();
487  }
const TextureDescriptor & GetTextureDescriptor() const
Gets the texture descriptor for this image source.

References impeller::ToArrayLayerCount().

◆ IsSwapchainImage()

bool impeller::AllocatedTextureSourceVK::IsSwapchainImage ( ) const
inlineoverridevirtual

Determines if swapchain image. That is, an image used as the root render target.

Returns
Whether or not this is a swapchain image.

Implements impeller::TextureSourceVK.

Definition at line 489 of file allocator_vk.cc.

489 { return false; }

◆ IsValid()

bool impeller::AllocatedTextureSourceVK::IsValid ( ) const
inline

Definition at line 469 of file allocator_vk.cc.

469 { return is_valid_; }

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