#include <vulkan/vulkan.h>
#include "vulkan/vulkan.h"
#include "base/debug/crash_logging.h"
#include "base/logging.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_function_pointers.h"
#include "gpu/vulkan/vulkan_image.h"
#include "ohos_adapter_helper.h"
#include "gpu/command_buffer/service/ohos/native_buffer_config_impl.h"
namespace gpu {
namespace {
bool IsSinglePlaneRGBVulkanAHBFormat(VkFormat format) {
switch (format) {
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8_UNORM:
case VK_FORMAT_R5G6B5_UNORM_PACK16:
case VK_FORMAT_R16G16B16A16_SFLOAT:
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
return true;
default:
return false;
}
}
}
bool VulkanImage::InitializeFromGpuMemoryBufferHandle(
scoped_refptr<gfx::NativePixmap> pixmap,
VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferHandle gmb_handle,
const gfx::Size& size,
VkFormat format,
VkImageUsageFlags usage,
VkImageCreateFlags flags,
VkImageTiling image_tiling,
uint32_t queue_family_index) {
if (gmb_handle.type == gfx::GpuMemoryBufferType::NATIVE_PIXMAP) {
#if BUILDFLAG(ENABLE_HEIF_DECODER)
queue_family_index_ = queue_family_index;
auto& native_pixmap_handle = gmb_handle.native_pixmap_handle;
auto& scoped_fd = native_pixmap_handle.planes[0].fd;
if (!scoped_fd.is_valid()) {
LOG(ERROR) << "VKImage scoped_fd invalid ! ";
return false;
}
VkExternalFormatOHOS external_format = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_OHOS,
.externalFormat = 0,
};
VkExternalMemoryImageCreateInfo external_memory_image_info = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.pNext = &external_format,
.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OHOS_NATIVE_BUFFER_BIT_OHOS,
};
VkImageUsageFlags usage_flags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
void* native_buffer = nullptr;
OHOS::NWeb::OhosNativeBufferAdapter& adapter =
OHOS::NWeb::OhosAdapterHelper::GetInstance().GetOhosNativeBufferAdapter();
adapter.NativeBufferFromNativeWindowBuffer(pixmap->GetWindowBuffer(), &native_buffer);
VkImportNativeBufferInfoOHOS nb_import_info = {
.sType = VK_STRUCTURE_TYPE_IMPORT_NATIVE_BUFFER_INFO_OHOS,
.buffer = static_cast<OH_NativeBuffer*>(native_buffer),
};
VkMemoryRequirements* req = nullptr;
if (!InitializeSingleOrJointPlanes(
device_queue, size,
VK_FORMAT_R8G8B8A8_UNORM,
usage_flags, 0, VK_IMAGE_TILING_OPTIMAL,
&external_memory_image_info, &nb_import_info, req)) {
LOG(ERROR) << "VKImage InitializeSingleOrJointPlanes fails!";
return false;
}
return true;
#endif
} else if (gmb_handle.type == gfx::GpuMemoryBufferType::OHOS_NATIVE_BUFFER) {
DCHECK(gmb_handle.ohos_hardware_buffer.is_valid());
SCOPED_CRASH_KEY_BOOL("vulkan", "gmb_buffer.is_valid",
gmb_handle.ohos_hardware_buffer.is_valid());
auto& nb_handle = gmb_handle.ohos_hardware_buffer;
VkNativeBufferFormatPropertiesOHOS nb_format_props = {
VK_STRUCTURE_TYPE_NATIVE_BUFFER_FORMAT_PROPERTIES_OHOS,
};
VkNativeBufferPropertiesOHOS nb_props = {
.sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_PROPERTIES_OHOS,
.pNext = &nb_format_props,
};
if (!nb_handle.get()) {
LOG(ERROR) << "InitializeFromGpuMemoryBufferHandle null!";
return false;
}
VkDevice vk_device = device_queue->GetVulkanDevice();
VkResult result =
vkGetNativeBufferPropertiesOHOS(vk_device, static_cast<OH_NativeBuffer*>(nb_handle.get()), &nb_props);
if (result != VK_SUCCESS) {
LOG(ERROR) << "GetAhbProps: vkGetNativeBufferPropertiesOHOS failed : " << result;
return false;
}
VkExternalFormatOHOS external_format = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_OHOS,
.externalFormat = 0,
};
const bool should_use_external_format =
!IsSinglePlaneRGBVulkanAHBFormat(nb_format_props.format);
if (should_use_external_format) {
external_format.externalFormat = nb_format_props.externalFormat;
}
VkExternalMemoryImageCreateInfo external_memory_image_info = {
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
.pNext = &external_format,
.handleTypes =
VK_EXTERNAL_MEMORY_HANDLE_TYPE_OHOS_NATIVE_BUFFER_BIT_OHOS,
};
OHOS::NWeb::OhosNativeBufferAdapter& adapter =
OHOS::NWeb::OhosAdapterHelper::GetInstance().GetOhosNativeBufferAdapter();
std::shared_ptr<OHOS::NWeb::NativeBufferConfigAdapterImpl> nb_desc =
std::make_shared<OHOS::NWeb::NativeBufferConfigAdapterImpl>();
adapter.Describe(nb_desc, nb_handle.get());
VkImageUsageFlags usage_flags = 0;
auto res = nb_desc->GetBufferUsage();
if ((res & gpu::NATIVEBUFFER_USAGE_HW_TEXTURE) ||
(res & gpu::NATIVEBUFFER_USAGE_MEM_DMA)) {
usage_flags = usage_flags | VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
}
if ((res & gpu::NATIVEBUFFER_USAGE_HW_RENDER) ||
(res & gpu::NATIVEBUFFER_USAGE_MEM_DMA)) {
usage_flags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}
if (!usage_flags) {
LOG(ERROR) << "No valid usage flags found";
return false;
}
usage_flags |=
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
VkImageCreateFlags create_flags = 0;
VkImportNativeBufferInfoOHOS nb_import_info = {
.sType = VK_STRUCTURE_TYPE_IMPORT_NATIVE_BUFFER_INFO_OHOS,
.buffer = static_cast<OH_NativeBuffer*>(nb_handle.get()),
};
VkMemoryRequirements requirements = {
.size = nb_props.allocationSize,
.memoryTypeBits = nb_props.memoryTypeBits,
};
if (!InitializeSingleOrJointPlanes(
device_queue, size,
should_use_external_format ? VK_FORMAT_UNDEFINED
: nb_format_props.format,
usage_flags, create_flags, VK_IMAGE_TILING_OPTIMAL,
&external_memory_image_info, &nb_import_info, &requirements)) {
LOG(ERROR) << "InitializeSingleOrJointPlanes fails!";
return false;
}
queue_family_index_ = queue_family_index;
if (should_use_external_format) {
ycbcr_info_.emplace(VK_FORMAT_UNDEFINED, nb_format_props.externalFormat,
nb_format_props.suggestedYcbcrModel,
nb_format_props.suggestedYcbcrRange,
nb_format_props.suggestedXChromaOffset,
nb_format_props.suggestedYChromaOffset,
nb_format_props.formatFeatures);
}
return true;
}
return false;
}
}