// // 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" #if defined(ANGLE_PLATFORM_ANDROID) # include #endif #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; namespace angle { namespace android { 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 ANGLE_AHB_FORMAT_R8G8B8A8_UNORM: return GL_RGBA8; case ANGLE_AHB_FORMAT_R8G8B8X8_UNORM: return GL_RGB8; case ANGLE_AHB_FORMAT_R8G8B8_UNORM: return GL_RGB8; case ANGLE_AHB_FORMAT_R5G6B5_UNORM: return GL_RGB565; case ANGLE_AHB_FORMAT_B8G8R8A8_UNORM: return GL_BGRA8_EXT; case ANGLE_AHB_FORMAT_B5G5R5A1_UNORM: return GL_RGB5_A1; case ANGLE_AHB_FORMAT_B4G4R4A4_UNORM: return GL_RGBA4; case ANGLE_AHB_FORMAT_R16G16B16A16_FLOAT: return GL_RGBA16F; case ANGLE_AHB_FORMAT_R10G10B10A2_UNORM: return GL_RGB10_A2; case ANGLE_AHB_FORMAT_BLOB: return GL_NONE; case ANGLE_AHB_FORMAT_D16_UNORM: return GL_DEPTH_COMPONENT16; case ANGLE_AHB_FORMAT_D24_UNORM: return GL_DEPTH_COMPONENT24; case ANGLE_AHB_FORMAT_D24_UNORM_S8_UINT: return GL_DEPTH24_STENCIL8; case ANGLE_AHB_FORMAT_D32_FLOAT: return GL_DEPTH_COMPONENT32F; case ANGLE_AHB_FORMAT_D32_FLOAT_S8_UINT: return GL_DEPTH32F_STENCIL8; case ANGLE_AHB_FORMAT_S8_UINT: return GL_STENCIL_INDEX8; case ANGLE_AHB_FORMAT_R8_UNORM: return GL_R8; case ANGLE_AHB_FORMAT_Y8Cb8Cr8_420: case ANGLE_AHB_FORMAT_YV12: case ANGLE_AHB_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 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_R8: return ANGLE_AHB_FORMAT_R8_UNORM; case GL_RGBA8: return ANGLE_AHB_FORMAT_R8G8B8A8_UNORM; case GL_RGB8: return ANGLE_AHB_FORMAT_R8G8B8X8_UNORM; case GL_RGB565: return ANGLE_AHB_FORMAT_R5G6B5_UNORM; case GL_BGRA8_EXT: return ANGLE_AHB_FORMAT_B8G8R8A8_UNORM; case GL_RGB5_A1: return ANGLE_AHB_FORMAT_B5G5R5A1_UNORM; case GL_RGBA4: return ANGLE_AHB_FORMAT_B4G4R4A4_UNORM; case GL_RGBA16F: return ANGLE_AHB_FORMAT_R16G16B16A16_FLOAT; case GL_RGB10_A2: return ANGLE_AHB_FORMAT_R10G10B10A2_UNORM; case GL_NONE: return ANGLE_AHB_FORMAT_BLOB; case GL_DEPTH_COMPONENT16: return ANGLE_AHB_FORMAT_D16_UNORM; case GL_DEPTH_COMPONENT24: return ANGLE_AHB_FORMAT_D24_UNORM; case GL_DEPTH24_STENCIL8: return ANGLE_AHB_FORMAT_D24_UNORM_S8_UINT; case GL_DEPTH_COMPONENT32F: return ANGLE_AHB_FORMAT_D32_FLOAT; case GL_DEPTH32F_STENCIL8: return ANGLE_AHB_FORMAT_D32_FLOAT_S8_UINT; case GL_STENCIL_INDEX8: return ANGLE_AHB_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); } bool GetSystemProperty(const char *propertyName, std::string *value) { #if defined(ANGLE_PLATFORM_ANDROID) // PROP_VALUE_MAX from std::vector propertyBuf(PROP_VALUE_MAX); int len = __system_property_get(propertyName, propertyBuf.data()); if (len <= 0) { return false; } *value = std::string(propertyBuf.data()); return true; #else return false; #endif } } // namespace android } // namespace angle