| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "impeller/renderer/backend/vulkan/android_hardware_buffer_texture_source_vk.h" |
| #include "impeller/renderer/backend/vulkan/texture_source_vk.h" |
| |
| #ifdef FML_OS_ANDROID |
| |
| namespace impeller { |
| |
| namespace { |
| |
| bool GetHardwareBufferProperties( |
| const vk::Device& device, |
| struct AHardwareBuffer* hardware_buffer, |
| ::impeller::vk::AndroidHardwareBufferPropertiesANDROID* ahb_props, |
| ::impeller::vk::AndroidHardwareBufferFormatPropertiesANDROID* |
| ahb_format_props) { |
| FML_CHECK(ahb_format_props != nullptr); |
| FML_CHECK(ahb_props != nullptr); |
| ahb_props->pNext = ahb_format_props; |
| ::impeller::vk::Result result = |
| device.getAndroidHardwareBufferPropertiesANDROID(hardware_buffer, |
| ahb_props); |
| if (result != impeller::vk::Result::eSuccess) { |
| return false; |
| } |
| return true; |
| } |
| |
| vk::ExternalFormatANDROID MakeExternalFormat( |
| const vk::AndroidHardwareBufferFormatPropertiesANDROID& format_props) { |
| vk::ExternalFormatANDROID external_format; |
| external_format.pNext = nullptr; |
| external_format.externalFormat = 0; |
| if (format_props.format == vk::Format::eUndefined) { |
| external_format.externalFormat = format_props.externalFormat; |
| } |
| return external_format; |
| } |
| |
| // Returns -1 if not found. |
| int FindMemoryTypeIndex( |
| const vk::AndroidHardwareBufferPropertiesANDROID& props) { |
| uint32_t memory_type_bits = props.memoryTypeBits; |
| int32_t type_index = -1; |
| for (uint32_t i = 0; memory_type_bits; |
| memory_type_bits = memory_type_bits >> 0x1, ++i) { |
| if (memory_type_bits & 0x1) { |
| type_index = i; |
| break; |
| } |
| } |
| return type_index; |
| } |
| |
| } // namespace |
| |
| AndroidHardwareBufferTextureSourceVK::AndroidHardwareBufferTextureSourceVK( |
| TextureDescriptor desc, |
| const vk::Device& device, |
| struct AHardwareBuffer* hardware_buffer, |
| const AHardwareBuffer_Desc& hardware_buffer_desc) |
| : TextureSourceVK(desc), device_(device) { |
| vk::AndroidHardwareBufferFormatPropertiesANDROID ahb_format_props; |
| vk::AndroidHardwareBufferPropertiesANDROID ahb_props; |
| if (!GetHardwareBufferProperties(device, hardware_buffer, &ahb_props, |
| &ahb_format_props)) { |
| return; |
| } |
| vk::ExternalFormatANDROID external_format = |
| MakeExternalFormat(ahb_format_props); |
| vk::ExternalMemoryImageCreateInfo external_memory_image_info; |
| external_memory_image_info.pNext = &external_format; |
| external_memory_image_info.handleTypes = |
| vk::ExternalMemoryHandleTypeFlagBits::eAndroidHardwareBufferANDROID; |
| const int memory_type_index = FindMemoryTypeIndex(ahb_props); |
| if (memory_type_index < 0) { |
| FML_LOG(ERROR) << "Could not find memory type."; |
| return; |
| } |
| |
| vk::ImageCreateFlags image_create_flags; |
| vk::ImageUsageFlags image_usage_flags; |
| if (hardware_buffer_desc.usage & AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE) { |
| image_usage_flags |= impeller::vk::ImageUsageFlagBits::eSampled | |
| impeller::vk::ImageUsageFlagBits::eInputAttachment; |
| } |
| if (hardware_buffer_desc.usage & AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT) { |
| image_usage_flags |= impeller::vk::ImageUsageFlagBits::eColorAttachment; |
| } |
| if (hardware_buffer_desc.usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT) { |
| image_create_flags |= impeller::vk::ImageCreateFlagBits::eProtected; |
| } |
| |
| vk::ImageCreateInfo image_create_info; |
| image_create_info.pNext = &external_memory_image_info; |
| image_create_info.imageType = vk::ImageType::e2D; |
| image_create_info.format = ahb_format_props.format; |
| image_create_info.extent.width = hardware_buffer_desc.width; |
| image_create_info.extent.height = hardware_buffer_desc.height; |
| image_create_info.extent.depth = 1; |
| image_create_info.mipLevels = 1; |
| image_create_info.arrayLayers = 1; |
| image_create_info.samples = vk::SampleCountFlagBits::e1; |
| image_create_info.tiling = vk::ImageTiling::eOptimal; |
| image_create_info.usage = image_usage_flags; |
| image_create_info.flags = image_create_flags; |
| image_create_info.sharingMode = vk::SharingMode::eExclusive; |
| image_create_info.initialLayout = vk::ImageLayout::eUndefined; |
| |
| vk::ResultValue<impeller::vk::Image> maybe_image = |
| device.createImage(image_create_info); |
| if (maybe_image.result != vk::Result::eSuccess) { |
| FML_LOG(ERROR) << "device.createImage failed: " |
| << static_cast<int>(maybe_image.result); |
| return; |
| } |
| vk::Image image = maybe_image.value; |
| |
| vk::ImportAndroidHardwareBufferInfoANDROID ahb_import_info; |
| ahb_import_info.pNext = nullptr; |
| ahb_import_info.buffer = hardware_buffer; |
| |
| vk::MemoryDedicatedAllocateInfo dedicated_alloc_info; |
| dedicated_alloc_info.pNext = &ahb_import_info; |
| dedicated_alloc_info.image = image; |
| dedicated_alloc_info.buffer = VK_NULL_HANDLE; |
| |
| vk::MemoryAllocateInfo mem_alloc_info; |
| mem_alloc_info.pNext = &dedicated_alloc_info; |
| mem_alloc_info.allocationSize = ahb_props.allocationSize; |
| mem_alloc_info.memoryTypeIndex = memory_type_index; |
| |
| vk::ResultValue<vk::DeviceMemory> allocate_result = |
| device.allocateMemory(mem_alloc_info); |
| if (allocate_result.result != vk::Result::eSuccess) { |
| FML_LOG(ERROR) << "vkAllocateMemory failed : " |
| << static_cast<int>(allocate_result.result); |
| device.destroyImage(image); |
| return; |
| } |
| vk::DeviceMemory device_memory = allocate_result.value; |
| |
| // Bind memory to the image object. |
| vk::Result bind_image_result = |
| device.bindImageMemory(image, device_memory, 0); |
| if (bind_image_result != vk::Result::eSuccess) { |
| FML_LOG(ERROR) << "vkBindImageMemory failed : " |
| << static_cast<int>(bind_image_result); |
| device.destroyImage(image); |
| device.freeMemory(device_memory); |
| return; |
| } |
| image_ = image; |
| device_memory_ = device_memory; |
| |
| // Create image view. |
| vk::ImageViewCreateInfo view_info; |
| view_info.image = image_; |
| view_info.viewType = vk::ImageViewType::e2D; |
| view_info.format = ToVKImageFormat(desc.format); |
| view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eColor; |
| view_info.subresourceRange.baseMipLevel = 0u; |
| view_info.subresourceRange.baseArrayLayer = 0u; |
| view_info.subresourceRange.levelCount = desc.mip_count; |
| view_info.subresourceRange.layerCount = ToArrayLayerCount(desc.type); |
| auto [view_result, view] = device.createImageViewUnique(view_info); |
| if (view_result != vk::Result::eSuccess) { |
| FML_LOG(ERROR) << "createImageViewUnique failed : " |
| << static_cast<int>(view_result); |
| return; |
| } |
| image_view_ = std::move(view); |
| is_valid_ = true; |
| } |
| |
| // |TextureSourceVK| |
| AndroidHardwareBufferTextureSourceVK::~AndroidHardwareBufferTextureSourceVK() { |
| device_.destroyImage(image_); |
| device_.freeMemory(device_memory_); |
| } |
| |
| bool AndroidHardwareBufferTextureSourceVK::IsValid() const { |
| return is_valid_; |
| } |
| |
| // |TextureSourceVK| |
| vk::Image AndroidHardwareBufferTextureSourceVK::GetImage() const { |
| FML_CHECK(IsValid()); |
| return image_; |
| } |
| |
| // |TextureSourceVK| |
| vk::ImageView AndroidHardwareBufferTextureSourceVK::GetImageView() const { |
| FML_CHECK(IsValid()); |
| return image_view_.get(); |
| } |
| |
| } // namespace impeller |
| |
| #endif |