#include "ui/ozone/common/native_pixmap_egl_binding.h"
#include "arkweb/build/features/features.h"
#include <array>
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "base/notreached.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/linux/drm_util_linux.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/buffer_format_utils.h"
#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/scoped_binders.h"
#if BUILDFLAG(ARKWEB_HEIF_SUPPORT)
#include "ui/gl/ohos/native_buffer_utils.h"
#endif
namespace ui {
namespace {
#define FOURCC(a, b, c, d) \
((static_cast<uint32_t>(a)) | (static_cast<uint32_t>(b) << 8) | \
(static_cast<uint32_t>(c) << 16) | (static_cast<uint32_t>(d) << 24))
#define DRM_FORMAT_R8 FOURCC('R', '8', ' ', ' ')
#define DRM_FORMAT_R16 FOURCC('R', '1', '6', ' ')
#define DRM_FORMAT_GR88 FOURCC('G', 'R', '8', '8')
#define DRM_FORMAT_GR1616 FOURCC('G', 'R', '3', '2')
#define DRM_FORMAT_RGB565 FOURCC('R', 'G', '1', '6')
#define DRM_FORMAT_ARGB8888 FOURCC('A', 'R', '2', '4')
#define DRM_FORMAT_ABGR8888 FOURCC('A', 'B', '2', '4')
#define DRM_FORMAT_XRGB8888 FOURCC('X', 'R', '2', '4')
#define DRM_FORMAT_XBGR8888 FOURCC('X', 'B', '2', '4')
#define DRM_FORMAT_ABGR2101010 FOURCC('A', 'B', '3', '0')
#define DRM_FORMAT_ARGB2101010 FOURCC('A', 'R', '3', '0')
#define DRM_FORMAT_ABGR16161616F FOURCC('A', 'B', '4', 'H')
#define DRM_FORMAT_YVU420 FOURCC('Y', 'V', '1', '2')
#define DRM_FORMAT_NV12 FOURCC('N', 'V', '1', '2')
#define DRM_FORMAT_P010 FOURCC('P', '0', '1', '0')
#define DRM_FORMAT_INVALID 0
unsigned GLInternalFormat(viz::SharedImageFormat shared_format) {
if (!shared_format.is_single_plane()) {
return GL_NONE;
}
gfx::BufferFormat format = viz::SinglePlaneSharedImageFormatToBufferFormat(shared_format);
switch (format) {
case gfx::BufferFormat::RGBA_4444:
case gfx::BufferFormat::RGBA_F16:
case gfx::BufferFormat::P010:
return GL_RGB_YCBCR_P010_CHROMIUM;
default:
break;
}
return gl::BufferFormatToGLInternalFormat(format);
}
}
NativePixmapEGLBinding::NativePixmapEGLBinding(const gfx::Size& size,
viz::SharedImageFormat format,
gfx::BufferPlane plane)
: size_(size), format_(format), plane_(plane) {}
NativePixmapEGLBinding::~NativePixmapEGLBinding() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
}
bool NativePixmapEGLBinding::IsSharedImageFormatSupported(
viz::SharedImageFormat format) {
return GetFourCCFormatFromSharedImageFormat(format) != DRM_FORMAT_INVALID;
}
std::unique_ptr<NativePixmapGLBinding> NativePixmapEGLBinding::Create(
scoped_refptr<gfx::NativePixmap> pixmap,
viz::SharedImageFormat plane_format,
gfx::BufferPlane plane,
gfx::Size plane_size,
const gfx::ColorSpace& color_space,
GLenum target,
GLuint texture_id) {
DCHECK_GT(texture_id, 0u);
auto binding =
std::make_unique<NativePixmapEGLBinding>(plane_size, plane_format, plane);
if (!binding->InitializeFromNativePixmap(std::move(pixmap), color_space,
target, texture_id)) {
LOG(ERROR) << "Unable to initialize binding from pixmap";
return nullptr;
}
return binding;
}
bool NativePixmapEGLBinding::InitializeFromNativePixmap(
scoped_refptr<gfx::NativePixmap> pixmap,
const gfx::ColorSpace& color_space,
GLenum target,
GLuint texture_id) {
DCHECK(!pixmap_);
#if BUILDFLAG(ARKWEB_HEIF_SUPPORT)
LOG(DEBUG) << "[HeifSupport] InitializeFromNativePixmap GLInternalFormat " << (int)GLInternalFormat(format_)
<< ", format_ " << format_.ToString() << ", plane_ " << (int)plane_ << ", WindowBuffer " << pixmap->GetWindowBuffer();
#endif
if (GetFourCCFormatFromSharedImageFormat(format_) == DRM_FORMAT_INVALID) {
LOG(ERROR) << "Unsupported format: " << format_.ToString();
return false;
}
if (!pixmap->AreDmaBufFdsValid()) {
LOG(ERROR) << "Pixmap doesn't have valid dma bufs";
return false;
}
#if BUILDFLAG(ARKWEB_HEIF_SUPPORT)
egl_image_ = gl::ohos::CreateEGLImage(
static_cast<EGLClientBuffer>(pixmap->GetWindowBuffer()));
if (egl_image_ == EGL_NO_IMAGE_KHR) {
LOG(ERROR) << "[HeifSupport] egl_image_ is EGL_NO_IMAGE_KHR.";
return false;
}
#else
std::vector<EGLint> attrs;
attrs.push_back(EGL_WIDTH);
attrs.push_back(size_.width());
attrs.push_back(EGL_HEIGHT);
attrs.push_back(size_.height());
attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
attrs.push_back(GetFourCCFormatFromSharedImageFormat(format_));
if (format_ == viz::MultiPlaneFormat::kNV12 ||
format_ == viz::MultiPlaneFormat::kYV12 ||
format_ == viz::MultiPlaneFormat::kP010) {
attrs.push_back(EGL_YUV_COLOR_SPACE_HINT_EXT);
switch (color_space.GetMatrixID()) {
case gfx::ColorSpace::MatrixID::BT2020_NCL:
attrs.push_back(EGL_ITU_REC2020_EXT);
break;
default:
attrs.push_back(EGL_ITU_REC601_EXT);
}
attrs.push_back(EGL_SAMPLE_RANGE_HINT_EXT);
switch (color_space.GetRangeID()) {
case gfx::ColorSpace::RangeID::FULL:
attrs.push_back(EGL_YUV_FULL_RANGE_EXT);
break;
default:
attrs.push_back(EGL_YUV_NARROW_RANGE_EXT);
}
}
if (plane_ == gfx::BufferPlane::DEFAULT) {
constexpr auto kPlaneFDAttrs = std::to_array<EGLint>({
EGL_DMA_BUF_PLANE0_FD_EXT,
EGL_DMA_BUF_PLANE1_FD_EXT,
EGL_DMA_BUF_PLANE2_FD_EXT,
EGL_DMA_BUF_PLANE3_FD_EXT,
});
constexpr auto kPlaneOffsetAttrs = std::to_array<EGLint>({
EGL_DMA_BUF_PLANE0_OFFSET_EXT,
EGL_DMA_BUF_PLANE1_OFFSET_EXT,
EGL_DMA_BUF_PLANE2_OFFSET_EXT,
EGL_DMA_BUF_PLANE3_OFFSET_EXT,
});
constexpr auto kPlanePitchAttrs = std::to_array<EGLint>({
EGL_DMA_BUF_PLANE0_PITCH_EXT,
EGL_DMA_BUF_PLANE1_PITCH_EXT,
EGL_DMA_BUF_PLANE2_PITCH_EXT,
EGL_DMA_BUF_PLANE3_PITCH_EXT,
});
constexpr auto kPlaneLoModifierAttrs = std::to_array<EGLint>({
EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
});
constexpr auto kPlaneHiModifierAttrs = std::to_array<EGLint>({
EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
});
bool has_dma_buf_import_modifier =
gl::GLSurfaceEGL::GetGLDisplayEGL()
->ext->b_EGL_EXT_image_dma_buf_import_modifiers;
CHECK_LE(pixmap->GetNumberOfPlanes(), std::size(kPlaneFDAttrs));
for (size_t attrs_plane = 0; attrs_plane < pixmap->GetNumberOfPlanes();
++attrs_plane) {
attrs.push_back(kPlaneFDAttrs[attrs_plane]);
attrs.push_back(pixmap->GetDmaBufFd(attrs_plane));
attrs.push_back(kPlaneOffsetAttrs[attrs_plane]);
attrs.push_back(pixmap->GetDmaBufOffset(attrs_plane));
attrs.push_back(kPlanePitchAttrs[attrs_plane]);
attrs.push_back(pixmap->GetDmaBufPitch(attrs_plane));
uint64_t modifier = pixmap->GetBufferFormatModifier();
if (has_dma_buf_import_modifier &&
modifier != gfx::NativePixmapHandle::kNoModifier) {
DCHECK(attrs_plane < std::size(kPlaneLoModifierAttrs));
DCHECK(attrs_plane < std::size(kPlaneHiModifierAttrs));
attrs.push_back(kPlaneLoModifierAttrs[attrs_plane]);
attrs.push_back(modifier & 0xffffffff);
attrs.push_back(kPlaneHiModifierAttrs[attrs_plane]);
attrs.push_back(static_cast<uint32_t>(modifier >> 32));
}
}
attrs.push_back(EGL_NONE);
} else {
DCHECK(plane_ == gfx::BufferPlane::Y || plane_ == gfx::BufferPlane::UV);
size_t pixmap_plane = plane_ == gfx::BufferPlane::Y ? 0 : 1;
attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT);
attrs.push_back(pixmap->GetDmaBufFd(pixmap_plane));
attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT);
attrs.push_back(pixmap->GetDmaBufOffset(pixmap_plane));
attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT);
attrs.push_back(pixmap->GetDmaBufPitch(pixmap_plane));
attrs.push_back(EGL_NONE);
}
egl_image_ =
gl::MakeScopedEGLImage(EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
static_cast<EGLClientBuffer>(nullptr), &attrs[0]);
#endif
if (!egl_image_.get()) {
return false;
}
pixmap_ = pixmap;
gl::ScopedTextureBinder binder(target, texture_id);
glEGLImageTargetTexture2DOES(target, egl_image_.get());
return true;
}
}