diff options
| -rw-r--r-- | libs/nativewindow/AHardwareBuffer.cpp | 135 | ||||
| -rw-r--r-- | libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h | 5 | ||||
| -rw-r--r-- | libs/nativewindow/include/android/hardware_buffer.h | 175 | ||||
| -rw-r--r-- | libs/nativewindow/libnativewindow.map.txt | 1 |
4 files changed, 226 insertions, 90 deletions
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 7e26b0b587..a19fe17d16 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -41,33 +41,11 @@ using namespace android; // ---------------------------------------------------------------------------- int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer) { - if (!outBuffer || !desc) - return BAD_VALUE; - - if (!AHardwareBuffer_isValidPixelFormat(desc->format)) { - ALOGE("Invalid AHardwareBuffer pixel format %u (%#x))", desc->format, desc->format); - return BAD_VALUE; - } + if (!outBuffer || !desc) return BAD_VALUE; + if (!AHardwareBuffer_isValidDescription(desc, /*log=*/true)) return BAD_VALUE; int format = AHardwareBuffer_convertToPixelFormat(desc->format); - if (desc->rfu0 != 0 || desc->rfu1 != 0) { - ALOGE("AHardwareBuffer_Desc::rfu fields must be 0"); - return BAD_VALUE; - } - - if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) { - ALOGE("Height must be 1 when using the AHARDWAREBUFFER_FORMAT_BLOB format"); - return BAD_VALUE; - } - - if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) && - (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) { - ALOGE("AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER " - "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER"); - return BAD_VALUE; - } - - uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage); + uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage); sp<GraphicBuffer> gbuffer(new GraphicBuffer( desc->width, desc->height, format, desc->layers, usage, std::string("AHardwareBuffer pid [") + std::to_string(getpid()) + "]")); @@ -122,19 +100,26 @@ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) { ALOGE("Invalid usage flags passed to AHardwareBuffer_lock; only " - " AHARDWAREBUFFER_USAGE_CPU_* flags are allowed"); + "AHARDWAREBUFFER_USAGE_CPU_* flags are allowed"); return BAD_VALUE; } usage = AHardwareBuffer_convertToGrallocUsageBits(usage); - GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer); + GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer); + + if (gbuffer->getLayerCount() > 1) { + ALOGE("Buffer with multiple layers passed to AHardwareBuffer_lock; " + "only buffers with one layer are allowed"); + return INVALID_OPERATION; + } + Rect bounds; if (!rect) { - bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight())); + bounds.set(Rect(gbuffer->getWidth(), gbuffer->getHeight())); } else { bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom)); } - return gBuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence); + return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence); } int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) { @@ -274,6 +259,25 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out return NO_ERROR; } +int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) { + if (!desc) return 0; + if (!AHardwareBuffer_isValidDescription(desc, /*log=*/false)) return 0; + + // Make a trial allocation. + // TODO(b/115660272): add implementation that uses a HAL query. + AHardwareBuffer_Desc trialDesc = *desc; + trialDesc.width = 4; + trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4; + trialDesc.layers = desc->layers == 1 ? 1 : 2; + AHardwareBuffer* trialBuffer = nullptr; + int result = AHardwareBuffer_allocate(&trialDesc, &trialBuffer); + if (result == NO_ERROR) { + AHardwareBuffer_release(trialBuffer); + return 1; + } + return 0; +} + // ---------------------------------------------------------------------------- // VNDK functions @@ -322,14 +326,71 @@ int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc, namespace android { -// A 1:1 mapping of AHardwaqreBuffer bitmasks to gralloc1 bitmasks. -struct UsageMaskMapping { - uint64_t hardwareBufferMask; - uint64_t grallocMask; -}; +bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log) { + if (desc->width == 0 || desc->height == 0 || desc->layers == 0) { + ALOGE_IF(log, "Width, height and layers must all be nonzero"); + return false; + } + + if (!AHardwareBuffer_isValidPixelFormat(desc->format)) { + ALOGE_IF(log, "Invalid AHardwareBuffer pixel format %u (%#x))", + desc->format, desc->format); + return false; + } + + if (desc->rfu0 != 0 || desc->rfu1 != 0) { + ALOGE_IF(log, "AHardwareBuffer_Desc::rfu fields must be 0"); + return false; + } + + if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB) { + if (desc->height != 1 || desc->layers != 1) { + ALOGE_IF(log, "Height and layers must be 1 for AHARDWAREBUFFER_FORMAT_BLOB"); + return false; + } + const uint64_t blobInvalidGpuMask = + AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE | + AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | + AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE | + AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP; + if (desc->usage & blobInvalidGpuMask) { + ALOGE_IF(log, "Invalid GPU usage flag for AHARDWAREBUFFER_FORMAT_BLOB; " + "only AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER is allowed"); + return false; + } + if (desc->usage & AHARDWAREBUFFER_USAGE_VIDEO_ENCODE) { + ALOGE_IF(log, "AHARDWAREBUFFER_FORMAT_BLOB cannot be encoded as video"); + return false; + } + } else { + if (desc->usage & AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA) { + ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA requires AHARDWAREBUFFER_FORMAT_BLOB"); + return false; + } + if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER) { + ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER requires AHARDWAREBUFFER_FORMAT_BLOB"); + return false; + } + } + + if ((desc->usage & (AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) && + (desc->usage & AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT)) { + ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT requires AHARDWAREBUFFER_USAGE_CPU_READ_NEVER " + "and AHARDWAREBUFFER_USAGE_CPU_WRITE_NEVER"); + return false; + } -static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) { - return (mask & bitsToCheck) == bitsToCheck && bitsToCheck; + if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) { + if (desc->width != desc->height) { + ALOGE_IF(log, "Cube maps must be square"); + return false; + } + if (desc->layers % 6 != 0) { + ALOGE_IF(log, "Cube map layers must be a multiple of 6"); + return false; + } + } + return true; } bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { @@ -445,7 +506,7 @@ uint64_t AHardwareBuffer_convertToGrallocUsageBits(uint64_t usage) { "gralloc and AHardwareBuffer flags don't match"); static_assert(AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE == (uint64_t)BufferUsage::GPU_TEXTURE, "gralloc and AHardwareBuffer flags don't match"); - static_assert(AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT == (uint64_t)BufferUsage::GPU_RENDER_TARGET, + static_assert(AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER == (uint64_t)BufferUsage::GPU_RENDER_TARGET, "gralloc and AHardwareBuffer flags don't match"); static_assert(AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT == (uint64_t)BufferUsage::PROTECTED, "gralloc and AHardwareBuffer flags don't match"); diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h index 71f563467d..bf688f8ef8 100644 --- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h +++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h @@ -28,10 +28,15 @@ #include <stdint.h> struct AHardwareBuffer; +struct AHardwareBuffer_Desc; struct ANativeWindowBuffer; namespace android { +// Validates whether the passed description does not have conflicting +// parameters. Note: this does not verify any platform-specific contraints. +bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log); + // whether this AHardwareBuffer format is valid bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format); diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index 23ac60bf53..03545a68ca 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -102,8 +102,10 @@ enum AHardwareBuffer_Format { AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM = 0x2b, /** - * An opaque binary blob format that must have height 1, with width equal to - * the buffer size in bytes. + * Opaque binary blob format. + * Must have height 1 and one layer, with width equal to the buffer + * size in bytes. Corresponds to Vulkan buffers and OpenGL buffer + * objects. Can be bound to the latter using GL_EXT_external_buffer. */ AHARDWAREBUFFER_FORMAT_BLOB = 0x21, @@ -195,20 +197,25 @@ enum AHardwareBuffer_UsageFlags { /// The buffer will be written to by the GPU as a framebuffer attachment. AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER = 1UL << 9, /** - * The buffer will be written to by the GPU as a framebuffer attachment. - * Note that the name of this flag is somewhat misleading: it does not imply - * that the buffer contains a color format. A buffer with depth or stencil - * format that will be used as a framebuffer attachment should also have - * this flag. + * The buffer will be written to by the GPU as a framebuffer + * attachment. + * + * Note that the name of this flag is somewhat misleading: it does + * not imply that the buffer contains a color format. A buffer with + * depth or stencil format that will be used as a framebuffer + * attachment should also have this flag. Use the equivalent flag + * AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER to avoid this confusion. */ AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, /** - * The buffer is protected from direct CPU access or being read by non-secure - * hardware, such as video encoders. This flag is incompatible with CPU - * read and write flags. It is mainly used when handling DRM video. - * Refer to the EGL extension EGL_EXT_protected_content and GL extension - * EXT_protected_textures for more information on how these buffers are expected - * to behave. + * The buffer is protected from direct CPU access or being read by + * non-secure hardware, such as video encoders. + * + * This flag is incompatible with CPU read and write flags. It is + * mainly used when handling DRM video. Refer to the EGL extension + * EGL_EXT_protected_content and GL extension + * GL_EXT_protected_textures for more information on how these + * buffers are expected to behave. */ AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT = 1UL << 14, /// The buffer will be read by a hardware video encoder. @@ -225,11 +232,17 @@ enum AHardwareBuffer_UsageFlags { AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER = 1UL << 24, /** * The buffer will be used as a cube map texture. - * When this flag is present, the buffer must have a layer count that is - * a multiple of 6. + * When this flag is present, the buffer must have a layer count + * that is a multiple of 6. Note that buffers with this flag must be + * bound to OpenGL textures using the extension + * GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image. */ AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP = 1UL << 25, - /// The buffer contains a complete mipmap hierarchy. + /** + * The buffer contains a complete mipmap hierarchy. + * Note that buffers with this flag must be bound to OpenGL textures using + * the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image. + */ AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE = 1UL << 26, AHARDWAREBUFFER_USAGE_VENDOR_0 = 1ULL << 28, @@ -255,13 +268,21 @@ enum AHardwareBuffer_UsageFlags { }; /** - * Buffer description. Used for allocating new buffers and querying parameters - * of existing ones. + * Buffer description. Used for allocating new buffers and querying + * parameters of existing ones. */ typedef struct AHardwareBuffer_Desc { uint32_t width; ///< Width in pixels. uint32_t height; ///< Height in pixels. - uint32_t layers; ///< Number of images in an image array. + /** + * Number of images in an image array. AHardwareBuffers with one + * layer correspond to regular 2D textures. AHardwareBuffers with + * more than layer correspond to texture arrays. If the layer count + * is a multiple of 6 and the usage flag + * AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is + * a cube map or a cube map array. + */ + uint32_t layers; uint32_t format; ///< One of AHardwareBuffer_Format. uint64_t usage; ///< Combination of AHardwareBuffer_UsageFlags. uint32_t stride; ///< Row stride in pixels, ignored for AHardwareBuffer_allocate() @@ -290,8 +311,10 @@ typedef struct AHardwareBuffer AHardwareBuffer; int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc, AHardwareBuffer** outBuffer) __INTRODUCED_IN(26); /** - * Acquire a reference on the given AHardwareBuffer object. This prevents the - * object from being deleted until the last reference is removed. + * Acquire a reference on the given AHardwareBuffer object. + * + * This prevents the object from being deleted until the last reference + * is removed. */ void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26); @@ -309,50 +332,73 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26); /** - * Lock the AHardwareBuffer for reading or writing, depending on the usage flags - * passed. This call may block if the hardware needs to finish rendering or if - * CPU caches need to be synchronized, or possibly for other implementation- - * specific reasons. If fence is not negative, then it specifies a fence file - * descriptor that will be signaled when the buffer is locked, otherwise the - * caller will block until the buffer is available. + * Lock the AHardwareBuffer for direct CPU access. * - * If \a rect is not NULL, the caller promises to modify only data in the area - * specified by rect. If rect is NULL, the caller may modify the contents of the - * entire buffer. + * This function can lock the buffer for either reading or writing. + * It may block if the hardware needs to finish rendering, if CPU caches + * need to be synchronized, or possibly for other implementation- + * specific reasons. * - * The content of the buffer outside of the specified rect is NOT modified - * by this call. + * The passed AHardwareBuffer must have one layer, otherwise the call + * will fail. * - * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set, - * then outVirtualAddress is filled with the address of the buffer in virtual - * memory. + * If \a fence is not negative, it specifies a fence file descriptor on + * which to wait before locking the buffer. If it's negative, the caller + * is responsible for ensuring that writes to the buffer have completed + * before calling this function. Using this parameter is more efficient + * than waiting on the fence and then calling this function. * - * THREADING CONSIDERATIONS: + * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. + * If set, then outVirtualAddress is filled with the address of the + * buffer in virtual memory. The flags must also be compatible with + * usage flags specified at buffer creation: if a read flag is passed, + * the buffer must have been created with + * AHARDWAREBUFFER_USAGE_CPU_READ_RARELY or + * AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN. If a write flag is passed, it + * must have been created with AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY or + * AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN. * - * It is legal for several different threads to lock a buffer for read access; - * none of the threads are blocked. + * If \a rect is not NULL, the caller promises to modify only data in + * the area specified by rect. If rect is NULL, the caller may modify + * the contents of the entire buffer. The content of the buffer outside + * of the specified rect is NOT modified by this call. * - * Locking a buffer simultaneously for write or read/write is undefined, but - * will neither terminate the process nor block the caller; AHardwareBuffer_lock - * may return an error or leave the buffer's content into an indeterminate - * state. + * It is legal for several different threads to lock a buffer for read + * access; none of the threads are blocked. * - * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage - * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error - * number of the lock fails for any reason. + * Locking a buffer simultaneously for write or read/write is undefined, + * but will neither terminate the process nor block the caller. + * AHardwareBuffer_lock may return an error or leave the buffer's + * content in an indeterminate state. + * + * If the buffer has AHARDWAREBUFFER_FORMAT_BLOB, it is legal lock it + * for reading and writing in multiple threads and/or processes + * simultaneously, and the contents of the buffer behave like shared + * memory. + * + * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags + * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer + * has more than one layer. Error number if the lock fails for any other + * reason. */ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26); /** - * Unlock the AHardwareBuffer; must be called after all changes to the buffer - * are completed by the caller. If fence is not NULL then it will be set to a - * file descriptor that is signaled when all pending work on the buffer is - * completed. The caller is responsible for closing the fence when it is no - * longer needed. + * Unlock the AHardwareBuffer from direct CPU access. * - * \return 0 on success, -EINVAL if \a buffer is NULL, or an error - * number if the unlock fails for any reason. + * Must be called after all changes to the buffer are completed by the + * caller. If \a fence is NULL, the function will block until all work + * is completed. Otherwise, \a fence will be set either to a valid file + * descriptor or to -1. The file descriptor will become signaled once + * the unlocking is complete and buffer contents are updated. + * The caller is responsible for closing the file descriptor once it's + * no longer needed. The value -1 indicates that unlocking has already + * completed before the function returned and no further operations are + * necessary. + * + * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if + * the unlock fails for any reason. */ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26); @@ -365,7 +411,7 @@ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26); /** - * Receive the AHardwareBuffer from an AF_UNIX socket. + * Receive an AHardwareBuffer from an AF_UNIX socket. * * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error * number if the operation fails for any reason. @@ -374,6 +420,29 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out #endif // __ANDROID_API__ >= 26 +#if __ANDROID_API__ >= 29 + +/** + * Test whether the given format and usage flag combination is + * allocatable. + * + * If this function returns true, it means that a buffer with the given + * description can be allocated on this implementation, unless resource + * exhaustion occurs. If this function returns false, it means that the + * allocation of the given description will never succeed. + * + * The return value of this function may depend on all fields in the + * description, except stride, which is always ignored. For example, + * some implementations have implementation-defined limits on texture + * size and layer count. + * + * \return 1 if the format and usage flag combination is allocatable, + * 0 otherwise. + */ +int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29); + +#endif // __ANDROID_API__ >= 29 + __END_DECLS #endif // ANDROID_HARDWARE_BUFFER_H diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 753954d97a..a796e97e29 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -5,6 +5,7 @@ LIBNATIVEWINDOW { AHardwareBuffer_createFromHandle; # vndk AHardwareBuffer_describe; AHardwareBuffer_getNativeHandle; # vndk + AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; AHardwareBuffer_recvHandleFromUnixSocket; AHardwareBuffer_release; |