// // 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 #if defined(ANGLE_PLATFORM_ANDROID) && __ANDROID_API__ >= 26 # define ANGLE_AHARDWARE_BUFFER_SUPPORT // NDK header file for access to Android Hardware Buffers # include #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 AHARDWAREBUFFER_FORMAT_YV12 = 0x32315659, AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED = 0x22, }; // 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(sizeof(void *)) * 2; template T1 *OffsetPointer(T2 *ptr, int bytes) { return reinterpret_cast(reinterpret_cast(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: case AHARDWAREBUFFER_FORMAT_YV12: case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED: *isYUV = true; return GL_RGB8; default: // Treat unknown formats as RGB. They are vendor-specific YUV formats that would sample // as RGB. *isYUV = true; return GL_RGB8; } } } // anonymous namespace namespace angle { namespace android { ANativeWindowBuffer *ClientBufferToANativeWindowBuffer(EGLClientBuffer clientBuffer) { return reinterpret_cast(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(width); aHardwareBufferDescription.height = static_cast(height); aHardwareBufferDescription.layers = static_cast(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); #else return nullptr; #endif // ANGLE_AHARDWARE_BUFFER_SUPPORT } void GetANativeWindowBufferProperties(const ANativeWindowBuffer *buffer, int *width, int *height, int *depth, int *pixelFormat, uint64_t *usage) { *width = buffer->width; *height = buffer->height; *depth = static_cast(buffer->layerCount); *height = buffer->height; *pixelFormat = buffer->format; *usage = buffer->usage; } 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(windowBuffer, -kAHardwareBufferToANativeWindowBufferOffset); } EGLClientBuffer AHardwareBufferToClientBuffer(const AHardwareBuffer *hardwareBuffer) { return OffsetPointer(hardwareBuffer, kAHardwareBufferToANativeWindowBufferOffset); } AHardwareBuffer *ClientBufferToAHardwareBuffer(EGLClientBuffer clientBuffer) { return OffsetPointer(clientBuffer, -kAHardwareBufferToANativeWindowBufferOffset); } } // namespace android } // namespace angle