diff options
Diffstat (limited to 'gfx/angle/checkout/src/common/android_util.cpp')
-rw-r--r-- | gfx/angle/checkout/src/common/android_util.cpp | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/common/android_util.cpp b/gfx/angle/checkout/src/common/android_util.cpp new file mode 100644 index 0000000000..436b1b798a --- /dev/null +++ b/gfx/angle/checkout/src/common/android_util.cpp @@ -0,0 +1,417 @@ +// +// Copyright 2018 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// android_util.cpp: Utilities for the using the Android platform + +#include "common/android_util.h" +#include "common/debug.h" + +#include <cstdint> + +#if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 26 +# define ANGLE_AHARDWARE_BUFFER_SUPPORT +// NDK header file for access to Android Hardware Buffers +# include <android/hardware_buffer.h> +#endif + +// Taken from cutils/native_handle.h: +// https://android.googlesource.com/platform/system/core/+/master/libcutils/include/cutils/native_handle.h +typedef struct native_handle +{ + int version; /* sizeof(native_handle_t) */ + int numFds; /* number of file-descriptors at &data[0] */ + int numInts; /* number of ints at &data[numFds] */ +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wzero-length-array" +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4200) +#endif + int data[0]; /* numFds + numInts ints */ +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif +} native_handle_t; + +// Taken from nativebase/nativebase.h +// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativebase/include/nativebase/nativebase.h +typedef const native_handle_t *buffer_handle_t; + +typedef struct android_native_base_t +{ + /* a magic value defined by the actual EGL native type */ + int magic; + /* the sizeof() of the actual EGL native type */ + int version; + void *reserved[4]; + /* reference-counting interface */ + void (*incRef)(struct android_native_base_t *base); + void (*decRef)(struct android_native_base_t *base); +} android_native_base_t; + +typedef struct ANativeWindowBuffer +{ + struct android_native_base_t common; + int width; + int height; + int stride; + int format; + int usage_deprecated; + uintptr_t layerCount; + void *reserved[1]; + const native_handle_t *handle; + uint64_t usage; + // we needed extra space for storing the 64-bits usage flags + // the number of slots to use from reserved_proc depends on the + // architecture. + void *reserved_proc[8 - (sizeof(uint64_t) / sizeof(void *))]; +} ANativeWindowBuffer_t; + +// Taken from android/hardware_buffer.h +// https://android.googlesource.com/platform/frameworks/native/+/master/libs/nativewindow/include/android/hardware_buffer.h + +// AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM, +// AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM formats were deprecated and re-added explicitly. + +// clang-format off +/** + * Buffer pixel formats. + */ +enum { + +#ifndef ANGLE_AHARDWARE_BUFFER_SUPPORT + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_R8G8B8A8_UNORM + * OpenGL ES: GL_RGBA8 + */ + AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM = 1, + + /** + * 32 bits per pixel, 8 bits per channel format where alpha values are + * ignored (always opaque). + * Corresponding formats: + * Vulkan: VK_FORMAT_R8G8B8A8_UNORM + * OpenGL ES: GL_RGB8 + */ + AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM = 2, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_R8G8B8_UNORM + * OpenGL ES: GL_RGB8 + */ + AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM = 3, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_R5G6B5_UNORM_PACK16 + * OpenGL ES: GL_RGB565 + */ + AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM = 4, +#endif // ANGLE_AHARDWARE_BUFFER_SUPPORT + + AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM = 5, + AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM = 6, + AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM = 7, + +#ifndef ANGLE_AHARDWARE_BUFFER_SUPPORT + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_R16G16B16A16_SFLOAT + * OpenGL ES: GL_RGBA16F + */ + AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT = 0x16, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_A2B10G10R10_UNORM_PACK32 + * OpenGL ES: GL_RGB10_A2 + */ + AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM = 0x2b, + + /** + * An opaque binary blob format that must have height 1, with width equal to + * the buffer size in bytes. + */ + AHARDWAREBUFFER_FORMAT_BLOB = 0x21, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D16_UNORM + * OpenGL ES: GL_DEPTH_COMPONENT16 + */ + AHARDWAREBUFFER_FORMAT_D16_UNORM = 0x30, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_X8_D24_UNORM_PACK32 + * OpenGL ES: GL_DEPTH_COMPONENT24 + */ + AHARDWAREBUFFER_FORMAT_D24_UNORM = 0x31, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D24_UNORM_S8_UINT + * OpenGL ES: GL_DEPTH24_STENCIL8 + */ + AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT = 0x32, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D32_SFLOAT + * OpenGL ES: GL_DEPTH_COMPONENT32F + */ + AHARDWAREBUFFER_FORMAT_D32_FLOAT = 0x33, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_D32_SFLOAT_S8_UINT + * OpenGL ES: GL_DEPTH32F_STENCIL8 + */ + AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT = 0x34, + + /** + * Corresponding formats: + * Vulkan: VK_FORMAT_S8_UINT + * OpenGL ES: GL_STENCIL_INDEX8 + */ + AHARDWAREBUFFER_FORMAT_S8_UINT = 0x35, + + /** + * YUV 420 888 format. + * Must have an even width and height. Can be accessed in OpenGL + * shaders through an external sampler. Does not support mip-maps + * cube-maps or multi-layered textures. + */ + AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23, + +#endif // ANGLE_AHARDWARE_BUFFER_SUPPORT +}; +// clang-format on + +namespace +{ + +// In the Android system: +// - AHardwareBuffer is essentially a typedef of GraphicBuffer. Conversion functions simply +// reinterpret_cast. +// - GraphicBuffer inherits from two base classes, ANativeWindowBuffer and RefBase. +// +// GraphicBuffer implements a getter for ANativeWindowBuffer (getNativeBuffer) by static_casting +// itself to its base class ANativeWindowBuffer. The offset of the ANativeWindowBuffer pointer +// from the GraphicBuffer pointer is 16 bytes. This is likely due to two pointers: The vtable of +// GraphicBuffer and the one pointer member of the RefBase class. +// +// This is not future proof at all. We need to look into getting utilities added to Android to +// perform this cast for us. +constexpr int kAHardwareBufferToANativeWindowBufferOffset = static_cast<int>(sizeof(void *)) * 2; + +template <typename T1, typename T2> +T1 *offsetPointer(T2 *ptr, int bytes) +{ + return reinterpret_cast<T1 *>(reinterpret_cast<intptr_t>(ptr) + bytes); +} + +GLenum getPixelFormatInfo(int pixelFormat, bool *isYUV) +{ + *isYUV = false; + switch (pixelFormat) + { + case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: + return GL_RGBA8; + case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: + return GL_RGB8; + case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: + return GL_RGB8; + case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: + return GL_RGB565; + case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM: + return GL_BGRA8_EXT; + case AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM: + return GL_RGB5_A1; + case AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM: + return GL_RGBA4; + case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT: + return GL_RGBA16F; + case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: + return GL_RGB10_A2; + case AHARDWAREBUFFER_FORMAT_BLOB: + return GL_NONE; + case AHARDWAREBUFFER_FORMAT_D16_UNORM: + return GL_DEPTH_COMPONENT16; + case AHARDWAREBUFFER_FORMAT_D24_UNORM: + return GL_DEPTH_COMPONENT24; + case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: + return GL_DEPTH24_STENCIL8; + case AHARDWAREBUFFER_FORMAT_D32_FLOAT: + return GL_DEPTH_COMPONENT32F; + case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: + return GL_DEPTH32F_STENCIL8; + case AHARDWAREBUFFER_FORMAT_S8_UINT: + return GL_STENCIL_INDEX8; + case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: + *isYUV = true; + return GL_RGB8; + default: + // Treat unknown formats as RGB. They are vendor-specific YUV formats that would sample + // as RGB. + WARN() << "Unknown pixelFormat: " << pixelFormat << ". Treating as RGB8"; + *isYUV = true; + return GL_RGB8; + } +} + +} // anonymous namespace + +namespace angle +{ + +namespace android +{ + +ANativeWindowBuffer *ClientBufferToANativeWindowBuffer(EGLClientBuffer clientBuffer) +{ + return reinterpret_cast<ANativeWindowBuffer *>(clientBuffer); +} + +uint64_t GetAHBUsage(int eglNativeBufferUsage) +{ + uint64_t ahbUsage = 0; +#if defined(ANGLE_AHARDWARE_BUFFER_SUPPORT) + if (eglNativeBufferUsage & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) + { + ahbUsage |= AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT; + } + if (eglNativeBufferUsage & EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID) + { + ahbUsage |= AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER; + } + if (eglNativeBufferUsage & EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID) + { + ahbUsage |= AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE; + } +#endif // ANGLE_AHARDWARE_BUFFER_SUPPORT + return ahbUsage; +} + +EGLClientBuffer CreateEGLClientBufferFromAHardwareBuffer(int width, + int height, + int depth, + int androidFormat, + int usage) +{ +#if defined(ANGLE_AHARDWARE_BUFFER_SUPPORT) + + // The height and width are number of pixels of size format + AHardwareBuffer_Desc aHardwareBufferDescription = {}; + aHardwareBufferDescription.width = static_cast<uint32_t>(width); + aHardwareBufferDescription.height = static_cast<uint32_t>(height); + aHardwareBufferDescription.layers = static_cast<uint32_t>(depth); + aHardwareBufferDescription.format = androidFormat; + aHardwareBufferDescription.usage = GetAHBUsage(usage); + + // Allocate memory from Android Hardware Buffer + AHardwareBuffer *aHardwareBuffer = nullptr; + int res = AHardwareBuffer_allocate(&aHardwareBufferDescription, &aHardwareBuffer); + if (res != 0) + { + return nullptr; + } + + return AHardwareBufferToClientBuffer(aHardwareBuffer); +#endif // ANGLE_AHARDWARE_BUFFER_SUPPORT + return nullptr; +} + +void GetANativeWindowBufferProperties(const ANativeWindowBuffer *buffer, + int *width, + int *height, + int *depth, + int *pixelFormat) +{ + *width = buffer->width; + *height = buffer->height; + *depth = static_cast<int>(buffer->layerCount); + *height = buffer->height; + *pixelFormat = buffer->format; +} + +GLenum NativePixelFormatToGLInternalFormat(int pixelFormat) +{ + bool isYuv = false; + return getPixelFormatInfo(pixelFormat, &isYuv); +} + +int GLInternalFormatToNativePixelFormat(GLenum internalFormat) +{ + switch (internalFormat) + { + case GL_RGBA8: + return AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM; + case GL_RGB8: + return AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM; + case GL_RGB565: + return AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM; + case GL_BGRA8_EXT: + return AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM; + case GL_RGB5_A1: + return AHARDWAREBUFFER_FORMAT_B5G5R5A1_UNORM; + case GL_RGBA4: + return AHARDWAREBUFFER_FORMAT_B4G4R4A4_UNORM; + case GL_RGBA16F: + return AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT; + case GL_RGB10_A2: + return AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM; + case GL_NONE: + return AHARDWAREBUFFER_FORMAT_BLOB; + case GL_DEPTH_COMPONENT16: + return AHARDWAREBUFFER_FORMAT_D16_UNORM; + case GL_DEPTH_COMPONENT24: + return AHARDWAREBUFFER_FORMAT_D24_UNORM; + case GL_DEPTH24_STENCIL8: + return AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT; + case GL_DEPTH_COMPONENT32F: + return AHARDWAREBUFFER_FORMAT_D32_FLOAT; + case GL_DEPTH32F_STENCIL8: + return AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT; + case GL_STENCIL_INDEX8: + return AHARDWAREBUFFER_FORMAT_S8_UINT; + default: + WARN() << "Unknown internalFormat: " << internalFormat << ". Treating as 0"; + return 0; + } +} + +bool NativePixelFormatIsYUV(int pixelFormat) +{ + bool isYuv = false; + getPixelFormatInfo(pixelFormat, &isYuv); + return isYuv; +} + +AHardwareBuffer *ANativeWindowBufferToAHardwareBuffer(ANativeWindowBuffer *windowBuffer) +{ + return offsetPointer<AHardwareBuffer>(windowBuffer, + -kAHardwareBufferToANativeWindowBufferOffset); +} + +EGLClientBuffer AHardwareBufferToClientBuffer(const AHardwareBuffer *hardwareBuffer) +{ + return offsetPointer<EGLClientBuffer>(hardwareBuffer, + kAHardwareBufferToANativeWindowBufferOffset); +} + +AHardwareBuffer *ClientBufferToAHardwareBuffer(EGLClientBuffer clientBuffer) +{ + return offsetPointer<AHardwareBuffer>(clientBuffer, + -kAHardwareBufferToANativeWindowBufferOffset); +} +} // namespace android +} // namespace angle |