From a5c54bc61ae3c6d301ae9075ae0e76abba4810a2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosiński Date: Fri, 16 Nov 2018 18:24:33 -0800 Subject: Add AHardwareBuffer_isSupported. This new function will check whether a buffer with the given description is allocatable. If the function returns false, buffer allocation will never succeed. The current implementation performs a trial allocation of a small buffer, but in the future this will be replaced by a HAL query. Bug: 115660272 Test: Builds and passes CTS on Pixel 2. Change-Id: Id0b1573ebf3194b1163324da773279da95782143 --- libs/nativewindow/AHardwareBuffer.cpp | 135 ++++++++++++++++++++++++---------- 1 file changed, 98 insertions(+), 37 deletions(-) (limited to 'libs/nativewindow/AHardwareBuffer.cpp') 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 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"); -- cgit v1.2.3-59-g8ed1b From c4b9ce02d0a230acf8b4acbcf1d7cde8ca467c8c Mon Sep 17 00:00:00 2001 From: Krzysztof Kosiński Date: Wed, 2 Jan 2019 16:27:05 -0800 Subject: Fix AHardwareBuffer_isSupported for cube maps. Cube maps need a multiple of 6 layers, but the function attempted a trial allocation with 1 or 2 layers instead, which cannot succeed. Bug: 121285176 Bug: 122267389 Test: Builds successfully. Change-Id: Id4cf26359ad2884d597c6571501b452b930fa4fa --- libs/nativewindow/AHardwareBuffer.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'libs/nativewindow/AHardwareBuffer.cpp') diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index a19fe17d16..6ea127064b 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -268,7 +268,11 @@ int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) { AHardwareBuffer_Desc trialDesc = *desc; trialDesc.width = 4; trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4; - trialDesc.layers = desc->layers == 1 ? 1 : 2; + if (desc->usage & AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP) { + trialDesc.layers = desc->layers == 6 ? 6 : 12; + } else { + trialDesc.layers = desc->layers == 1 ? 1 : 2; + } AHardwareBuffer* trialBuffer = nullptr; int result = AHardwareBuffer_allocate(&trialDesc, &trialBuffer); if (result == NO_ERROR) { -- cgit v1.2.3-59-g8ed1b From 4e9e48d856dbd87df2b071e69acd12235e05f8df Mon Sep 17 00:00:00 2001 From: renn Date: Thu, 11 Oct 2018 14:43:13 -0700 Subject: Add support for multi-plane YUV HardwareBuffers This adds a new lock method that allows locking all planes in the hardware-buffer. To do this we also add new structs to hold this buffer information. Documentation and testing is now in place. Change-Id: Id4933bbdd8d47d5209a9a08e27391908df26dae1 One-Pager: https://docs.google.com/document/d/1jPlDlaAOzg6QfrX77fZ6OYwR6xeqj_xQlW81mQGigHA/edit?usp=sharing Bug: 117617861 Test: Manual - run CTS tests --- libs/nativewindow/AHardwareBuffer.cpp | 97 +++++++++++++++++++++- .../private/android/AHardwareBufferHelpers.h | 6 ++ .../nativewindow/include/android/hardware_buffer.h | 56 ++++++++++++- libs/nativewindow/include/vndk/hardware_buffer.h | 2 - 4 files changed, 157 insertions(+), 4 deletions(-) (limited to 'libs/nativewindow/AHardwareBuffer.cpp') diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 6ea127064b..ff64f61fe8 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -122,6 +122,54 @@ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, return gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence); } +int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, + int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) { + if (!buffer || !outPlanes) return BAD_VALUE; + + 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"); + return BAD_VALUE; + } + + usage = AHardwareBuffer_convertToGrallocUsageBits(usage); + GraphicBuffer* gBuffer = AHardwareBuffer_to_GraphicBuffer(buffer); + Rect bounds; + if (!rect) { + bounds.set(Rect(gBuffer->getWidth(), gBuffer->getHeight())); + } else { + bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom)); + } + int format = AHardwareBuffer_convertFromPixelFormat(uint32_t(gBuffer->getPixelFormat())); + memset(outPlanes->planes, 0, sizeof(outPlanes->planes)); + if (AHardwareBuffer_formatIsYuv(format)) { + android_ycbcr yuvData; + int result = gBuffer->lockAsyncYCbCr(usage, bounds, &yuvData, fence); + if (result == 0) { + outPlanes->planeCount = 3; + outPlanes->planes[0].data = yuvData.y; + outPlanes->planes[0].pixelStride = 1; + outPlanes->planes[0].rowStride = yuvData.ystride; + outPlanes->planes[1].data = yuvData.cb; + outPlanes->planes[1].pixelStride = yuvData.chroma_step; + outPlanes->planes[1].rowStride = yuvData.cstride; + outPlanes->planes[2].data = yuvData.cr; + outPlanes->planes[2].pixelStride = yuvData.chroma_step; + outPlanes->planes[2].rowStride = yuvData.cstride; + } else { + outPlanes->planeCount = 0; + } + return result; + } else { + const uint32_t pixelStride = AHardwareBuffer_bytesPerPixel(format); + outPlanes->planeCount = 1; + outPlanes->planes[0].pixelStride = pixelStride; + outPlanes->planes[0].rowStride = gBuffer->getStride() * pixelStride; + return gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence); + } +} + int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) { if (!buffer) return BAD_VALUE; @@ -366,6 +414,19 @@ bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool l ALOGE_IF(log, "AHARDWAREBUFFER_FORMAT_BLOB cannot be encoded as video"); return false; } + } else if (AHardwareBuffer_formatIsYuv(desc->format)) { + if (desc->layers != 1) { + ALOGE_IF(log, "Layers must be 1 for YUV formats."); + return false; + } + const uint64_t yuvInvalidGpuMask = + AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE | + AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP; + if (desc->usage & yuvInvalidGpuMask) { + ALOGE_IF(log, "Invalid usage flags specified for YUV format; " + "mip-mapping and cube-mapping are not allowed."); + return false; + } } else { if (desc->usage & AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA) { ALOGE_IF(log, "AHARDWAREBUFFER_USAGE_SENSOR_DIRECT_DATA requires AHARDWAREBUFFER_FORMAT_BLOB"); @@ -465,6 +526,7 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { case AHARDWAREBUFFER_FORMAT_D32_FLOAT: case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT: case AHARDWAREBUFFER_FORMAT_S8_UINT: + case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: // VNDK formats only -- unfortunately we can't differentiate from where we're called case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM: case AHARDWAREBUFFER_FORMAT_YV12: @@ -475,7 +537,6 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { case AHARDWAREBUFFER_FORMAT_RAW12: case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE: case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED: - case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP: case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: @@ -486,6 +547,40 @@ bool AHardwareBuffer_isValidPixelFormat(uint32_t format) { } } +bool AHardwareBuffer_formatIsYuv(uint32_t format) { + switch (format) { + case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420: + case AHARDWAREBUFFER_FORMAT_YV12: + case AHARDWAREBUFFER_FORMAT_Y8: + case AHARDWAREBUFFER_FORMAT_Y16: + case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP: + case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP: + case AHARDWAREBUFFER_FORMAT_YCbCr_422_I: + return true; + default: + return false; + } +} + +uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format) { + switch (format) { + case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM: + case AHARDWAREBUFFER_FORMAT_D16_UNORM: + return 2; + case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM: + case AHARDWAREBUFFER_FORMAT_D24_UNORM: + return 3; + case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM: + case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM: + case AHARDWAREBUFFER_FORMAT_D32_FLOAT: + case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM: + case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT: + return 4; + default: + return 0; + } +} + uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) { return hal_format; } diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h index bf688f8ef8..ddfd1d1918 100644 --- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h +++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h @@ -40,6 +40,12 @@ bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool l // whether this AHardwareBuffer format is valid bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format); +// whether this is a YUV type format +bool AHardwareBuffer_formatIsYuv(uint32_t format); + +// number of bytes per pixel or 0 if unknown or multi-planar +uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format); + // convert AHardwareBuffer format to HAL format (note: this is a no-op) uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format); diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index 2796c75f04..02c7c1b934 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -150,6 +150,14 @@ enum AHardwareBuffer_Format { * 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, }; /** @@ -301,6 +309,24 @@ typedef struct AHardwareBuffer_Desc { uint64_t rfu1; ///< Initialize to zero, reserved for future use. } AHardwareBuffer_Desc; +/** + * Holds data for a single image plane. + */ +typedef struct AHardwareBuffer_Plane { + void* data; ///< Points to first byte in plane + uint32_t pixelStride; ///< Distance in bytes from the color channel of one pixel to the next + uint32_t rowStride; ///< Distance in bytes from the first value of one row of the image to + /// the first value of the next row. +} AHardwareBuffer_Plane; + +/** + * Holds all image planes that contain the pixel data. + */ +typedef struct AHardwareBuffer_Planes { + uint32_t planeCount; ///< Number of distinct planes + AHardwareBuffer_Plane planes[4]; ///< Array of image planes +} AHardwareBuffer_Planes; + /** * Opaque handle for a native hardware buffer. */ @@ -323,7 +349,7 @@ 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. */ @@ -395,6 +421,34 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26); +/** + * Lock a potentially multi-planar AHardwareBuffer for direct CPU access. + * + * This function is similar to AHardwareBuffer_lock, but can lock multi-planar + * formats. The locked planes are returned in the \a outPlanes argument. Note, + * that multi-planar should not be confused with multi-layer images, which this + * locking function does not support. + * + * YUV formats are always represented by three separate planes of data, one for + * each color plane. The order of planes in the array is guaranteed such that + * plane #0 is always Y, plane #1 is always U (Cb), and plane #2 is always V + * (Cr). All other formats are represented by a single plane. + * + * Additional information always accompanies the buffers, describing the row + * stride and the pixel stride for each plane. + * + * In case the buffer cannot be locked, \a outPlanes will contain zero planes. + * + * See the AHardwareBuffer_lock documentation for all other locking semantics. + * + * \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_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, + int32_t fence, const ARect* rect, AHardwareBuffer_Planes* outPlanes) __INTRODUCED_IN(29); + /** * Unlock the AHardwareBuffer from direct CPU access. * diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h index 6c9ec3498e..3392d7f094 100644 --- a/libs/nativewindow/include/vndk/hardware_buffer.h +++ b/libs/nativewindow/include/vndk/hardware_buffer.h @@ -73,8 +73,6 @@ enum { AHARDWAREBUFFER_FORMAT_RAW_OPAQUE = 0x24, /* same as HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED */ AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED = 0x22, - /* same as HAL_PIXEL_FORMAT_YCBCR_420_888 */ - AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420 = 0x23, /* same as HAL_PIXEL_FORMAT_YCBCR_422_SP */ AHARDWAREBUFFER_FORMAT_YCbCr_422_SP = 0x10, /* same as HAL_PIXEL_FORMAT_YCRCB_420_SP */ -- cgit v1.2.3-59-g8ed1b From a2414f06bd4330e58c1ea3626c20dace7b1c6b7d Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Thu, 7 Feb 2019 13:42:43 -0800 Subject: Adding support for Hal query in AHardwareBuffer isSupported Bug: 120440873 Test: Build, boot, AHardwareBufferGLTest cts test Change-Id: I980f621598214ca514f02fc2d9861dfb3fa3bb12 --- libs/nativewindow/AHardwareBuffer.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'libs/nativewindow/AHardwareBuffer.cpp') diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 6ea127064b..8ef4896d61 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -263,8 +263,17 @@ 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. + bool supported = false; + GraphicBuffer* gBuffer = new GraphicBuffer(); + status_t err = gBuffer->isSupported(desc->width, desc->height, desc->format, desc->layers, + desc->usage, &supported); + + if (err == NO_ERROR) { + return supported; + } + + // function isSupported is not implemented on device or an error occurred during HAL + // query. Make a trial allocation. AHardwareBuffer_Desc trialDesc = *desc; trialDesc.width = 4; trialDesc.height = desc->format == AHARDWAREBUFFER_FORMAT_BLOB ? 1 : 4; -- cgit v1.2.3-59-g8ed1b From e672cd0eef276d65293bb4baa573765534a2431d Mon Sep 17 00:00:00 2001 From: Pawin Vongmasa Date: Thu, 14 Feb 2019 16:01:29 -0800 Subject: Implement converters for bufferqueue@2.0 Test: make cts -j123 && cts-tradefed run cts-dev -m \ CtsMediaTestCases --compatibility:module-arg \ CtsMediaTestCases:include-annotation:\ android.platform.test.annotations.RequiresDevice Bug: 112508112 Change-Id: I60f2068788136b01c45e03fc4d846d4e37edc7f2 --- libs/gui/Android.bp | 75 +-- libs/gui/IGraphicBufferProducer.cpp | 15 +- libs/gui/IProducerListener.cpp | 22 +- libs/gui/bufferqueue/1.0/H2BProducerListener.cpp | 59 +++ .../bufferqueue/2.0/B2HGraphicBufferProducer.cpp | 331 +++++++++++++ libs/gui/bufferqueue/2.0/B2HProducerListener.cpp | 47 ++ .../bufferqueue/2.0/H2BGraphicBufferProducer.cpp | 514 +++++++++++++++++++++ libs/gui/bufferqueue/2.0/H2BProducerListener.cpp | 57 +++ libs/gui/bufferqueue/2.0/types.cpp | 301 ++++++++++++ libs/gui/include/gui/IGraphicBufferProducer.h | 15 +- libs/gui/include/gui/IProducerListener.h | 13 +- .../gui/bufferqueue/1.0/H2BProducerListener.h | 52 +++ .../gui/bufferqueue/2.0/B2HGraphicBufferProducer.h | 121 +++++ .../gui/bufferqueue/2.0/B2HProducerListener.h | 57 +++ .../gui/bufferqueue/2.0/H2BGraphicBufferProducer.h | 107 +++++ .../gui/bufferqueue/2.0/H2BProducerListener.h | 52 +++ libs/gui/include/gui/bufferqueue/2.0/types.h | 129 ++++++ libs/nativewindow/AHardwareBuffer.cpp | 6 +- libs/nativewindow/Android.bp | 2 +- libs/ui/Android.bp | 2 +- libs/ui/GraphicBuffer.cpp | 16 + libs/ui/include/ui/Fence.h | 6 + libs/ui/include/ui/GraphicBuffer.h | 5 + 23 files changed, 1936 insertions(+), 68 deletions(-) create mode 100644 libs/gui/bufferqueue/1.0/H2BProducerListener.cpp create mode 100644 libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp create mode 100644 libs/gui/bufferqueue/2.0/B2HProducerListener.cpp create mode 100644 libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp create mode 100644 libs/gui/bufferqueue/2.0/H2BProducerListener.cpp create mode 100644 libs/gui/bufferqueue/2.0/types.cpp create mode 100644 libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h create mode 100644 libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h create mode 100644 libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h create mode 100644 libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h create mode 100644 libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h create mode 100644 libs/gui/include/gui/bufferqueue/2.0/types.h (limited to 'libs/nativewindow/AHardwareBuffer.cpp') diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 8b663bc8ec..4c2e6532ff 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -31,44 +31,7 @@ cc_library_shared { "-Werror", ], cppflags: [ - "-Weverything", - - // The static constructors and destructors in this library have not been noted to - // introduce significant overheads - "-Wno-exit-time-destructors", - "-Wno-global-constructors", - - // We only care about compiling as C++14 - "-Wno-c++98-compat-pedantic", - - // We don't need to enumerate every case in a switch as long as a default case - // is present - "-Wno-switch-enum", - - // Allow calling variadic macros without a __VA_ARGS__ list - "-Wno-gnu-zero-variadic-macro-arguments", - - // Don't warn about struct padding - "-Wno-padded", - - // We are aware of the risks inherent in comparing floats for equality - "-Wno-float-equal", - - // Pure abstract classes trigger this warning - "-Wno-weak-vtables", - - // Allow four-character integer literals - "-Wno-four-char-constants", - - // Allow documentation warnings - "-Wno-documentation", - - // Allow implicit instantiation for templated class function - "-Wno-undefined-func-template", - - // Allow explicitly marking struct as packed even when unnecessary - "-Wno-packed", - + "-Wextra", "-DDEBUG_ONLY_CODE=0", ], @@ -121,30 +84,38 @@ cc_library_shared { "view/Surface.cpp", "bufferqueue/1.0/B2HProducerListener.cpp", "bufferqueue/1.0/H2BGraphicBufferProducer.cpp", + "bufferqueue/1.0/H2BProducerListener.cpp", + "bufferqueue/2.0/B2HGraphicBufferProducer.cpp", + "bufferqueue/2.0/B2HProducerListener.cpp", + "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", + "bufferqueue/2.0/H2BProducerListener.cpp", + "bufferqueue/2.0/types.cpp", ], shared_libs: [ "android.frameworks.bufferhub@1.0", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hidl.token@1.0-utils", "libbase", - "libsync", "libbinder", - "libhwbinder", "libbufferhub", "libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui. - "libpdx_default_transport", "libcutils", "libEGL", "libGLESv2", - "libui", - "libutils", - "libnativewindow", - "liblog", - "libinput", "libhidlbase", "libhidltransport", - "android.hidl.token@1.0-utils", - "android.hardware.graphics.bufferqueue@1.0", + "libhwbinder", + "libinput", + "liblog", + "libnativewindow", + "libpdx_default_transport", + "libsync", + "libui", + "libutils", "libvndksupport", ], @@ -163,16 +134,16 @@ cc_library_shared { "android.frameworks.bufferhub@1.0", "libbufferhub", "libbufferhubqueue", - "libpdx_default_transport", "libinput", + "libpdx_default_transport", ], }, }, header_libs: [ "libdvr_headers", - "libnativebase_headers", "libgui_headers", + "libnativebase_headers", "libpdx_headers", ], @@ -181,9 +152,11 @@ cc_library_shared { "libEGL", "libnativewindow", "libui", - "android.hidl.token@1.0-utils", "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", "android.hardware.graphics.common@1.1", + "android.hardware.graphics.common@1.2", + "android.hidl.token@1.0-utils", ], export_header_lib_headers: [ diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 8907de4b5d..9dde15dd0e 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -30,16 +30,21 @@ #ifndef NO_BUFFERHUB #include #endif + +#include +#include #include #include #include -#include - namespace android { // ---------------------------------------------------------------------------- -using ::android::hardware::graphics::bufferqueue::V1_0::utils:: +using H2BGraphicBufferProducerV1_0 = + ::android::hardware::graphics::bufferqueue::V1_0::utils:: + H2BGraphicBufferProducer; +using H2BGraphicBufferProducerV2_0 = + ::android::hardware::graphics::bufferqueue::V2_0::utils:: H2BGraphicBufferProducer; enum { @@ -534,7 +539,9 @@ public: BpGraphicBufferProducer::~BpGraphicBufferProducer() {} class HpGraphicBufferProducer : public HpInterface< - BpGraphicBufferProducer, H2BGraphicBufferProducer> { + BpGraphicBufferProducer, + H2BGraphicBufferProducerV1_0, + H2BGraphicBufferProducerV2_0> { public: explicit HpGraphicBufferProducer(const sp& base) : PBase(base) {} diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp index 62abfa81c4..936063a5bd 100644 --- a/libs/gui/IProducerListener.cpp +++ b/libs/gui/IProducerListener.cpp @@ -15,7 +15,8 @@ */ #include - +#include +#include #include namespace android { @@ -61,7 +62,24 @@ public: // translation unit (see clang warning -Wweak-vtables) BpProducerListener::~BpProducerListener() {} -IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener") +class HpProducerListener : public HpInterface< + BpProducerListener, + hardware::graphics::bufferqueue::V1_0::utils::H2BProducerListener, + hardware::graphics::bufferqueue::V2_0::utils::H2BProducerListener> { +public: + explicit HpProducerListener(const sp& base) : PBase{base} {} + + virtual void onBufferReleased() override { + mBase->onBufferReleased(); + } + + virtual bool needsReleaseNotify() override { + return mBase->needsReleaseNotify(); + } +}; + +IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener, + "android.gui.IProducerListener") status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp new file mode 100644 index 0000000000..2712f42c89 --- /dev/null +++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "H2BProducerListener@1.0" + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V1_0 { +namespace utils { + +using ::android::hardware::Return; + +H2BProducerListener::H2BProducerListener(sp const& base) + : CBase{base} { +} + +void H2BProducerListener::onBufferReleased() { + if (!mBase->onBufferReleased().isOk()) { + LOG(ERROR) << "onBufferReleased: transaction failed."; + } +} + +bool H2BProducerListener::needsReleaseNotify() { + Return transResult = mBase->needsReleaseNotify(); + if (!transResult.isOk()) { + LOG(ERROR) << "needsReleaseNotify: transaction failed."; + return false; + } + return static_cast(transResult); +} + +} // namespace utils +} // namespace V1_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp new file mode 100644 index 0000000000..e0395939e9 --- /dev/null +++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp @@ -0,0 +1,331 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "H2BGraphicBufferProducer@2.0" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +// B2HGraphicBufferProducer +// ======================== + +B2HGraphicBufferProducer::B2HGraphicBufferProducer( + sp const& base) + : mBase{base} { +} + +Return B2HGraphicBufferProducer::setMaxDequeuedBufferCount( + int32_t maxDequeuedBuffers) { + HStatus hStatus{}; + bool converted = b2h( + mBase->setMaxDequeuedBufferCount( + static_cast(maxDequeuedBuffers)), + &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::requestBuffer( + int32_t slot, + requestBuffer_cb _hidl_cb) { + sp bBuffer; + HStatus hStatus{}; + HardwareBuffer hBuffer{}; + uint32_t hGenerationNumber{}; + bool converted = + b2h(mBase->requestBuffer( + static_cast(slot), &bBuffer), + &hStatus) && + b2h(bBuffer, &hBuffer, &hGenerationNumber); + _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, + hBuffer, hGenerationNumber); + return {}; +} + +Return B2HGraphicBufferProducer::setAsyncMode(bool async) { + HStatus hStatus{}; + bool converted = b2h(mBase->setAsyncMode(async), &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::dequeueBuffer( + DequeueBufferInput const& input, + dequeueBuffer_cb _hidl_cb) { + int bSlot{}; + sp bFence; + HStatus hStatus{}; + DequeueBufferOutput hOutput{}; + HFenceWrapper hFenceWrapper; + bool converted = + b2h(mBase->dequeueBuffer( + &bSlot, + &bFence, + input.width, + input.height, + static_cast(input.format), + input.usage, + &hOutput.bufferAge, + nullptr /* outTimestamps */), + &hStatus, + &hOutput.bufferNeedsReallocation, + &hOutput.releaseAllBuffers) && + b2h(bFence, &hFenceWrapper); + hOutput.fence = hFenceWrapper.getHandle(); + _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, + static_cast(bSlot), + hOutput); + return {}; +} + +Return B2HGraphicBufferProducer::detachBuffer(int32_t slot) { + HStatus hStatus{}; + bool converted = b2h( + mBase->detachBuffer(static_cast(slot)), &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::detachNextBuffer( + detachNextBuffer_cb _hidl_cb) { + sp bBuffer; + sp bFence; + HStatus hStatus{}; + HardwareBuffer hBuffer{}; + HFenceWrapper hFenceWrapper; + bool converted = + b2h(mBase->detachNextBuffer(&bBuffer, &bFence), &hStatus) && + b2h(bBuffer, &hBuffer) && + b2h(bFence, &hFenceWrapper); + _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, + hBuffer, + hFenceWrapper.getHandle()); + return {}; +} + +Return B2HGraphicBufferProducer::attachBuffer( + HardwareBuffer const& hBuffer, + uint32_t generationNumber, + attachBuffer_cb _hidl_cb) { + sp bBuffer; + if (!h2b(hBuffer, &bBuffer) || !bBuffer) { + _hidl_cb(HStatus::UNKNOWN_ERROR, + static_cast(SlotIndex::INVALID), + false); + return {}; + } + bBuffer->setGenerationNumber(generationNumber); + + int bSlot{}; + HStatus hStatus{}; + bool releaseAllBuffers{}; + bool converted = b2h( + mBase->attachBuffer(&bSlot, bBuffer), &hStatus, + nullptr /* bufferNeedsReallocation */, + &releaseAllBuffers); + _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, + static_cast(bSlot), + releaseAllBuffers); + return {}; +} + +Return B2HGraphicBufferProducer::queueBuffer( + int32_t slot, + QueueBufferInput const& hInput, + queueBuffer_cb _hidl_cb) { + using HOutput = QueueBufferOutput; + using BInput = BGraphicBufferProducer::QueueBufferInput; + using BOutput = BGraphicBufferProducer::QueueBufferOutput; + + BInput bInput{ + hInput.timestamp, + hInput.isAutoTimestamp, + static_cast(hInput.dataSpace), + {}, /* crop */ + 0 /* scalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE */, + static_cast(hInput.transform), + {}, /* fence */ + static_cast(hInput.stickyTransform), + false /* getFrameTimestamps */}; + + // Convert crop. + if (!h2b(hInput.crop, &bInput.crop)) { + _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{}); + return {}; + } + + // Convert surfaceDamage. + if (!h2b(hInput.surfaceDamage, &bInput.surfaceDamage)) { + _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{}); + return {}; + } + + // Convert fence. + if (!h2b(hInput.fence, &bInput.fence)) { + _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{}); + return {}; + } + + BOutput bOutput{}; + HStatus hStatus{}; + bool converted = b2h( + mBase->queueBuffer(static_cast(slot), bInput, &bOutput), + &hStatus); + + _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, + HOutput{bOutput.width, + bOutput.height, + static_cast(bOutput.transformHint), + bOutput.numPendingBuffers, + bOutput.nextFrameNumber, + bOutput.bufferReplaced}); + return {}; +} + +Return B2HGraphicBufferProducer::cancelBuffer( + int32_t slot, + hidl_handle const& fence) { + sp bFence; + if (!h2b(fence.getNativeHandle(), &bFence)) { + return {HStatus::UNKNOWN_ERROR}; + } + HStatus hStatus{}; + bool converted = b2h( + mBase->cancelBuffer(static_cast(slot), bFence), + &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) { + int value{}; + int result = mBase->query(static_cast(what), &value); + _hidl_cb(static_cast(result), static_cast(value)); + return {}; +} + +Return B2HGraphicBufferProducer::connect( + sp const& hListener, + HConnectionType hConnectionType, + bool producerControlledByApp, + connect_cb _hidl_cb) { + using BOutput = BGraphicBufferProducer::QueueBufferOutput; + using HOutput = HGraphicBufferProducer::QueueBufferOutput; + sp bListener = new H2BProducerListener(hListener); + if (!bListener) { + _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{}); + return {}; + } + int bConnectionType; + if (!h2b(hConnectionType, &bConnectionType)) { + _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{}); + return {}; + } + BOutput bOutput{}; + HStatus hStatus{}; + bool converted = b2h( + mBase->connect(bListener, + bConnectionType, + producerControlledByApp, + &bOutput), + &hStatus); + _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, + HOutput{bOutput.width, + bOutput.height, + static_cast(bOutput.transformHint), + bOutput.numPendingBuffers, + bOutput.nextFrameNumber, + bOutput.bufferReplaced}); + return {}; +} + +Return B2HGraphicBufferProducer::disconnect( + HConnectionType hConnectionType) { + int bConnectionType; + if (!h2b(hConnectionType, &bConnectionType)) { + return {HStatus::UNKNOWN_ERROR}; + } + HStatus hStatus{}; + bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::allocateBuffers( + uint32_t width, uint32_t height, + uint32_t format, uint64_t usage) { + mBase->allocateBuffers( + width, height, static_cast(format), usage); + return {HStatus::OK}; +} + +Return B2HGraphicBufferProducer::allowAllocation(bool allow) { + HStatus hStatus{}; + bool converted = b2h(mBase->allowAllocation(allow), &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::setGenerationNumber( + uint32_t generationNumber) { + HStatus hStatus{}; + bool converted = b2h( + mBase->setGenerationNumber(generationNumber), + &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::setDequeueTimeout( + int64_t timeoutNs) { + HStatus hStatus{}; + bool converted = b2h( + mBase->setDequeueTimeout(static_cast(timeoutNs)), + &hStatus); + return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; +} + +Return B2HGraphicBufferProducer::getUniqueId() { + uint64_t outId{}; + HStatus hStatus{}; + bool converted = b2h(mBase->getUniqueId(&outId), &hStatus); + return {converted ? outId : 0}; +} + +Return B2HGraphicBufferProducer::getConsumerName( + getConsumerName_cb _hidl_cb) { + _hidl_cb(hidl_string{mBase->getConsumerName().c_str()}); + return {}; +} + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + diff --git a/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp new file mode 100644 index 0000000000..c4c96eba50 --- /dev/null +++ b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +// B2HProducerListener +B2HProducerListener::B2HProducerListener(sp const& base) + : mBase{base}, + mNeedsReleaseNotify{base ? base->needsReleaseNotify() : false} { +} + +Return B2HProducerListener::onBuffersReleased(uint32_t count) { + if (mNeedsReleaseNotify) { + for (; count > 0; --count) { + mBase->onBufferReleased(); + } + } + return {}; +} + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + diff --git a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp new file mode 100644 index 0000000000..1023ef108a --- /dev/null +++ b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp @@ -0,0 +1,514 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "H2BGraphicBufferProducer@2.0" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace android { + +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +// H2BGraphicBufferProducer +// ======================== + +status_t H2BGraphicBufferProducer::requestBuffer(int slot, + sp* bBuffer) { + bool converted{}; + status_t bStatus{}; + Return transResult = mBase->requestBuffer(slot, + [&converted, &bStatus, bBuffer]( + HStatus hStatus, + HardwareBuffer const& hBuffer, + uint32_t generationNumber) { + converted = + h2b(hStatus, &bStatus) && + h2b(hBuffer, bBuffer); + if (*bBuffer) { + (*bBuffer)->setGenerationNumber(generationNumber); + } + }); + if (!transResult.isOk()) { + LOG(ERROR) << "requestBuffer: transaction failed."; + return FAILED_TRANSACTION; + } + if (!converted) { + LOG(ERROR) << "requestBuffer: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount( + int maxDequeuedBuffers) { + status_t bStatus{}; + Return transResult = mBase->setMaxDequeuedBufferCount( + static_cast(maxDequeuedBuffers)); + if (!transResult.isOk()) { + LOG(ERROR) << "setMaxDequeuedBufferCount: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "setMaxDequeuedBufferCount: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::setAsyncMode(bool async) { + status_t bStatus{}; + Return transResult = mBase->setAsyncMode(async); + if (!transResult.isOk()) { + LOG(ERROR) << "setAsyncMode: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "setAsyncMode: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::dequeueBuffer( + int* slot, sp* fence, + uint32_t w, uint32_t h, + PixelFormat format, uint64_t usage, + uint64_t* outBufferAge, FrameEventHistoryDelta* /* outTimestamps */) { + + using HInput = HGraphicBufferProducer::DequeueBufferInput; + HInput input{w, h, static_cast(format), usage}; + + using HOutput = HGraphicBufferProducer::DequeueBufferOutput; + bool converted{}; + status_t bStatus{}; + Return transResult = mBase->dequeueBuffer(input, + [&converted, &bStatus, slot, fence, outBufferAge] ( + HStatus hStatus, int32_t hSlot, HOutput const& hOutput) { + converted = h2b(hStatus, &bStatus); + if (!converted || bStatus != OK) { + return; + } + *slot = hSlot; + *outBufferAge = hOutput.bufferAge; + bStatus = + (hOutput.bufferNeedsReallocation ? + BUFFER_NEEDS_REALLOCATION : 0) | + (hOutput.releaseAllBuffers ? + RELEASE_ALL_BUFFERS : 0); + converted = h2b(hOutput.fence, fence); + }); + if (!transResult.isOk()) { + LOG(ERROR) << "dequeueBuffer: transaction failed."; + return FAILED_TRANSACTION; + } + if (!converted) { + LOG(ERROR) << "dequeueBuffer: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::detachBuffer(int slot) { + status_t bStatus{}; + Return transResult = mBase->detachBuffer( + static_cast(slot)); + if (!transResult.isOk()) { + LOG(ERROR) << "detachBuffer: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "detachBuffer: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::detachNextBuffer( + sp* outBuffer, sp* outFence) { + bool converted{}; + status_t bStatus{}; + Return transResult = mBase->detachNextBuffer( + [&converted, &bStatus, outBuffer, outFence] ( + HStatus hStatus, + HardwareBuffer const& hBuffer, + hidl_handle const& hFence) { + converted = h2b(hStatus, &bStatus) && + h2b(hBuffer, outBuffer) && + h2b(hFence, outFence); + }); + if (!transResult.isOk()) { + LOG(ERROR) << "detachNextBuffer: transaction failed."; + return FAILED_TRANSACTION; + } + if (!converted) { + LOG(ERROR) << "detachNextBuffer: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::attachBuffer( + int* outSlot, sp const& buffer) { + HardwareBuffer hBuffer{}; + uint32_t hGenerationNumber{}; + if (!b2h(buffer, &hBuffer, &hGenerationNumber)) { + LOG(ERROR) << "attachBuffer: invalid input buffer."; + return BAD_VALUE; + } + + bool converted{}; + status_t bStatus{}; + Return transResult = mBase->attachBuffer(hBuffer, hGenerationNumber, + [&converted, &bStatus, outSlot]( + HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) { + converted = h2b(hStatus, &bStatus); + *outSlot = static_cast(hSlot); + if (converted && releaseAllBuffers && bStatus == OK) { + bStatus = IGraphicBufferProducer::RELEASE_ALL_BUFFERS; + } + }); + if (!transResult.isOk()) { + LOG(ERROR) << "attachBuffer: transaction failed."; + return FAILED_TRANSACTION; + } + if (!converted) { + LOG(ERROR) << "attachBuffer: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::queueBuffer( + int slot, + QueueBufferInput const& input, + QueueBufferOutput* output) { + HRect hCrop{}; + (void)b2h(input.crop, &hCrop); + + using HInput = HGraphicBufferProducer::QueueBufferInput; + HInput hInput{ + input.timestamp, + static_cast(input.isAutoTimestamp), + static_cast(input.dataSpace), + {}, // crop + static_cast(input.transform), + static_cast(input.stickyTransform), + {}, // fence + {} // surfaceDamage + }; + + // Convert crop. + if (!b2h(input.crop, &hInput.crop)) { + LOG(ERROR) << "queueBuffer: corrupted input crop rectangle."; + return UNKNOWN_ERROR; + } + + // Convert surfaceDamage. + size_t numRects; + Rect const* rectArray = input.surfaceDamage.getArray(&numRects); + hInput.surfaceDamage.resize(numRects); + for (size_t i = 0; i < numRects; ++i) { + if (!b2h(rectArray[i], &hInput.surfaceDamage[i])) { + LOG(ERROR) << "queueBuffer: corrupted input surface damage."; + return UNKNOWN_ERROR; + } + } + + // Convert fence. + HFenceWrapper hFenceWrapper; + if (!b2h(input.fence, &hFenceWrapper)) { + LOG(ERROR) << "queueBuffer: corrupted input fence."; + return UNKNOWN_ERROR; + } + hInput.fence = hFenceWrapper.getHandle(); + + using HOutput = HGraphicBufferProducer::QueueBufferOutput; + bool converted{}; + status_t bStatus{}; + Return transResult = mBase->queueBuffer( + static_cast(slot), + hInput, + [&converted, &bStatus, output]( + HStatus hStatus, + HOutput const& hOutput) { + converted = h2b(hStatus, &bStatus); + output->width = hOutput.width; + output->height = hOutput.height; + output->transformHint = + static_cast(hOutput.transformHint); + output->numPendingBuffers = hOutput.numPendingBuffers; + output->nextFrameNumber = hOutput.nextFrameNumber; + output->bufferReplaced = hOutput.bufferReplaced; + }); + + if (!transResult.isOk()) { + LOG(ERROR) << "queueBuffer: transaction failed."; + return FAILED_TRANSACTION; + } + if (!converted) { + LOG(ERROR) << "queueBuffer: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::cancelBuffer(int slot, sp const& fence) { + HFenceWrapper hFenceWrapper; + if (!b2h(fence, &hFenceWrapper)) { + LOG(ERROR) << "cancelBuffer: corrupted input fence."; + return UNKNOWN_ERROR; + } + status_t bStatus{}; + Return transResult = mBase->cancelBuffer( + static_cast(slot), + hFenceWrapper.getHandle()); + if (!transResult.isOk()) { + LOG(ERROR) << "cancelBuffer: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "cancelBuffer: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +int H2BGraphicBufferProducer::query(int what, int* value) { + int result{}; + Return transResult = mBase->query( + static_cast(what), + [&result, value](int32_t r, int32_t v) { + result = static_cast(r); + *value = static_cast(v); + }); + if (!transResult.isOk()) { + LOG(ERROR) << "query: transaction failed."; + return FAILED_TRANSACTION; + } + return result; +} + +status_t H2BGraphicBufferProducer::connect( + sp const& listener, int api, + bool producerControlledByApp, QueueBufferOutput* output) { + HConnectionType hConnectionType; + if (!b2h(api, &hConnectionType)) { + LOG(ERROR) << "connect: corrupted input connection type."; + return UNKNOWN_ERROR; + } + sp hListener = nullptr; + if (listener && listener->needsReleaseNotify()) { + hListener = new B2HProducerListener(listener); + if (!hListener) { + LOG(ERROR) << "connect: failed to wrap listener."; + return UNKNOWN_ERROR; + } + } + + using HOutput = HGraphicBufferProducer::QueueBufferOutput; + bool converted{}; + status_t bStatus{}; + Return transResult = mBase->connect( + hListener, + hConnectionType, + producerControlledByApp, + [&converted, &bStatus, output]( + HStatus hStatus, + HOutput hOutput) { + converted = h2b(hStatus, &bStatus); + output->width = hOutput.width; + output->height = hOutput.height; + output->transformHint = + static_cast(hOutput.transformHint); + output->numPendingBuffers = hOutput.numPendingBuffers; + output->nextFrameNumber = hOutput.nextFrameNumber; + output->bufferReplaced = hOutput.bufferReplaced; + }); + if (!transResult.isOk()) { + LOG(ERROR) << "connect: transaction failed."; + return FAILED_TRANSACTION; + } + if (!converted) { + LOG(ERROR) << "connect: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; + +} + +status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) { + HConnectionType hConnectionType; + if (mode == DisconnectMode::AllLocal) { + hConnectionType = HConnectionType::CURRENTLY_CONNECTED; + } else if (!b2h(api, &hConnectionType)) { + LOG(ERROR) << "connect: corrupted input connection type."; + return UNKNOWN_ERROR; + } + + status_t bStatus{}; + Return transResult = mBase->disconnect(hConnectionType); + if (!transResult.isOk()) { + LOG(ERROR) << "disconnect: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "disconnect: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::setSidebandStream( + sp const& stream) { + if (stream) { + LOG(INFO) << "setSidebandStream: not supported."; + return INVALID_OPERATION; + } + return OK; +} + +void H2BGraphicBufferProducer::allocateBuffers( + uint32_t width, uint32_t height, + PixelFormat format, uint64_t usage) { + status_t bStatus{}; + Return transResult = mBase->allocateBuffers( + width, height, static_cast(format), usage); + if (!transResult.isOk()) { + LOG(ERROR) << "allocateBuffer: transaction failed."; + return; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "allocateBuffer: corrupted transaction."; + return; + } +} + +status_t H2BGraphicBufferProducer::allowAllocation(bool allow) { + status_t bStatus{}; + Return transResult = mBase->allowAllocation(allow); + if (!transResult.isOk()) { + LOG(ERROR) << "allowAllocation: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "allowAllocation: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::setGenerationNumber( + uint32_t generationNumber) { + status_t bStatus{}; + Return transResult = mBase->setGenerationNumber(generationNumber); + if (!transResult.isOk()) { + LOG(ERROR) << "setGenerationNumber: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "setGenerationNumber: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +String8 H2BGraphicBufferProducer::getConsumerName() const { + String8 bName; + Return transResult = mBase->getConsumerName( + [&bName](hidl_string const& name) { + bName = name.c_str(); + }); + return bName; +} + +status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) { + if (sharedBufferMode) { + LOG(INFO) << "setSharedBufferMode: not supported."; + return INVALID_OPERATION; + } + return OK; +} + +status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) { + if (autoRefresh) { + LOG(INFO) << "setAutoRefresh: not supported."; + return INVALID_OPERATION; + } + return OK; +} + +status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) { + status_t bStatus{}; + Return transResult = mBase->setDequeueTimeout( + static_cast(timeout)); + if (!transResult.isOk()) { + LOG(ERROR) << "setDequeueTimeout: transaction failed."; + return FAILED_TRANSACTION; + } + if (!h2b(static_cast(transResult), &bStatus)) { + LOG(ERROR) << "setDequeueTimeout: corrupted transaction."; + return FAILED_TRANSACTION; + } + return bStatus; +} + +status_t H2BGraphicBufferProducer::getLastQueuedBuffer( + sp*, + sp*, + float[16]) { + LOG(INFO) << "getLastQueuedBuffer: not supported."; + return INVALID_OPERATION; +} + +void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta*) { + LOG(INFO) << "getFrameTimestamps: not supported."; +} + +status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const { + Return transResult = mBase->getUniqueId(); + if (!transResult.isOk()) { + LOG(ERROR) << "getUniqueId: transaction failed."; + return FAILED_TRANSACTION; + } + *outId = static_cast(transResult); + return OK; +} + +status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t*) const { + LOG(INFO) << "getConsumerUsage: not supported."; + return INVALID_OPERATION; +} + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android diff --git a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp new file mode 100644 index 0000000000..b81a357d63 --- /dev/null +++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp @@ -0,0 +1,57 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "H2BProducerListener@2.0" + +#include + +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +using ::android::hardware::Return; + +H2BProducerListener::H2BProducerListener(sp const& base) + : CBase{base} { +} + +void H2BProducerListener::onBufferReleased() { + if (mBase) { + Return transResult = mBase->onBuffersReleased(1); + if (!transResult.isOk()) { + LOG(ERROR) << "onBuffersReleased: transaction failed."; + } + } +} + +bool H2BProducerListener::needsReleaseNotify() { + return static_cast(mBase); +} + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + diff --git a/libs/gui/bufferqueue/2.0/types.cpp b/libs/gui/bufferqueue/2.0/types.cpp new file mode 100644 index 0000000000..a11051739f --- /dev/null +++ b/libs/gui/bufferqueue/2.0/types.cpp @@ -0,0 +1,301 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +// Status +// ====== + +bool b2h(status_t from, HStatus* to, + bool* bufferNeedsReallocation, bool* releaseAllBuffers) { + switch (from) { + case OK: + *to = HStatus::OK; break; + case NO_MEMORY: + *to = HStatus::NO_MEMORY; break; + case NO_INIT: + *to = HStatus::NO_INIT; break; + case BAD_VALUE: + *to = HStatus::BAD_VALUE; break; + case DEAD_OBJECT: + *to = HStatus::DEAD_OBJECT; break; + case INVALID_OPERATION: + *to = HStatus::INVALID_OPERATION; break; + case TIMED_OUT: + *to = HStatus::TIMED_OUT; break; + case WOULD_BLOCK: + *to = HStatus::WOULD_BLOCK; break; + case UNKNOWN_ERROR: + *to = HStatus::UNKNOWN_ERROR; break; + default: + using BGBP = ::android::IGraphicBufferProducer; + status_t mask = + (bufferNeedsReallocation ? BGBP::BUFFER_NEEDS_REALLOCATION : 0) + | (releaseAllBuffers ? BGBP::RELEASE_ALL_BUFFERS : 0); + if (from & ~mask) { + *to = static_cast(from); + } else { + *to = HStatus::OK; + if (bufferNeedsReallocation) { + *bufferNeedsReallocation = from & BGBP::BUFFER_NEEDS_REALLOCATION; + } + if (releaseAllBuffers) { + *releaseAllBuffers = from & BGBP::RELEASE_ALL_BUFFERS; + } + } + } + return true; +} + +bool h2b(HStatus from, status_t* to) { + switch (from) { + case HStatus::OK: + *to = OK; break; + case HStatus::NO_MEMORY: + *to = NO_MEMORY; break; + case HStatus::NO_INIT: + *to = NO_INIT; break; + case HStatus::BAD_VALUE: + *to = BAD_VALUE; break; + case HStatus::DEAD_OBJECT: + *to = DEAD_OBJECT; break; + case HStatus::INVALID_OPERATION: + *to = INVALID_OPERATION; break; + case HStatus::TIMED_OUT: + *to = TIMED_OUT; break; + case HStatus::WOULD_BLOCK: + *to = WOULD_BLOCK; break; + case HStatus::UNKNOWN_ERROR: + *to = UNKNOWN_ERROR; break; + default: + *to = static_cast(from); + } + return true; +} + +// Fence +// ===== + +HFenceWrapper::HFenceWrapper(native_handle_t* h) : mHandle{h} { +} + +HFenceWrapper::~HFenceWrapper() { + native_handle_delete(mHandle); +} + +HFenceWrapper& HFenceWrapper::set(native_handle_t* h) { + native_handle_delete(mHandle); + mHandle = h; + return *this; +} + +HFenceWrapper& HFenceWrapper::operator=(native_handle_t* h) { + return set(h); +} + +hidl_handle HFenceWrapper::getHandle() const { + return hidl_handle{mHandle}; +} + +HFenceWrapper::operator hidl_handle() const { + return getHandle(); +} + +bool b2h(sp const& from, HFenceWrapper* to) { + if (!from) { + to->set(nullptr); + return true; + } + int fenceFd = from->get(); + if (fenceFd == -1) { + to->set(nullptr); + return true; + } + native_handle_t* nh = native_handle_create(1, 0); + if (!nh) { + return false; + } + nh->data[0] = fenceFd; + to->set(nh); + return true; +} + +bool h2b(native_handle_t const* from, sp* to) { + if (!from || from->numFds == 0) { + *to = new ::android::Fence(); + return true; + } + if (from->numFds != 1 || from->numInts != 0) { + return false; + } + *to = new BFence(dup(from->data[0])); + return true; +} + +// ConnectionType +// ============== + +bool b2h(int from, HConnectionType* to) { + *to = static_cast(from); + switch (from) { + case BufferQueueCore::CURRENTLY_CONNECTED_API: + *to = HConnectionType::CURRENTLY_CONNECTED; break; + case NATIVE_WINDOW_API_EGL: + *to = HConnectionType::EGL; break; + case NATIVE_WINDOW_API_CPU: + *to = HConnectionType::CPU; break; + case NATIVE_WINDOW_API_MEDIA: + *to = HConnectionType::MEDIA; break; + case NATIVE_WINDOW_API_CAMERA: + *to = HConnectionType::CAMERA; break; + } + return true; +} + +bool h2b(HConnectionType from, int* to) { + *to = static_cast(from); + switch (from) { + case HConnectionType::CURRENTLY_CONNECTED: + *to = BufferQueueCore::CURRENTLY_CONNECTED_API; break; + case HConnectionType::EGL: + *to = NATIVE_WINDOW_API_EGL; break; + case HConnectionType::CPU: + *to = NATIVE_WINDOW_API_CPU; break; + case HConnectionType::MEDIA: + *to = NATIVE_WINDOW_API_MEDIA; break; + case HConnectionType::CAMERA: + *to = NATIVE_WINDOW_API_CAMERA; break; + } + return true; +} + +// Rect +// ==== + +bool b2h(BRect const& from, HRect* to) { + BRect* dst = reinterpret_cast(to->data()); + dst->left = from.left; + dst->top = from.top; + dst->right = from.right; + dst->bottom = from.bottom; + return true; +} + +bool h2b(HRect const& from, BRect* to) { + BRect const* src = reinterpret_cast(from.data()); + to->left = src->left; + to->top = src->top; + to->right = src->right; + to->bottom = src->bottom; + return true; +} + +// Region +// ====== + +bool b2h(BRegion const& from, HRegion* to) { + size_t numRects; + BRect const* rectArray = from.getArray(&numRects); + to->resize(numRects); + for (size_t i = 0; i < numRects; ++i) { + if (!b2h(rectArray[i], &(*to)[i])) { + return false; + } + } + return true; +} + +bool h2b(HRegion const& from, BRegion* to) { + if (from.size() > 0) { + BRect bRect; + if (!h2b(from[0], &bRect)) { + return false; + } + to->set(bRect); + for (size_t i = 1; i < from.size(); ++i) { + if (!h2b(from[i], &bRect)) { + return false; + } + to->addRectUnchecked( + static_cast(bRect.left), + static_cast(bRect.top), + static_cast(bRect.right), + static_cast(bRect.bottom)); + } + } else { + to->clear(); + } + return true; +} + +// GraphicBuffer +// ============= + +// The handle is not cloned. Its lifetime is tied to the original GraphicBuffer. +bool b2h(sp const& from, HardwareBuffer* to, + uint32_t* toGenerationNumber) { + if (!from) { + return false; + } + AHardwareBuffer* hwBuffer = from->toAHardwareBuffer(); + to->nativeHandle.setTo( + const_cast( + AHardwareBuffer_getNativeHandle(hwBuffer)), + false); + AHardwareBuffer_describe( + hwBuffer, + reinterpret_cast(to->description.data())); + if (toGenerationNumber) { + *toGenerationNumber = from->getGenerationNumber(); + } + return true; +} + +// The handle is cloned. +bool h2b(HardwareBuffer const& from, sp* to) { + AHardwareBuffer_Desc const* desc = + reinterpret_cast( + from.description.data()); + native_handle_t const* handle = from.nativeHandle; + AHardwareBuffer* hwBuffer; + if (AHardwareBuffer_createFromHandle( + desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, + &hwBuffer) != OK) { + return false; + } + *to = GraphicBuffer::fromAHardwareBuffer(hwBuffer); + return true; +} + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 8ff8d81cf6..2f538adebc 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -35,6 +35,7 @@ #include #include +#include namespace android { // ---------------------------------------------------------------------------- @@ -42,8 +43,6 @@ namespace android { class IProducerListener; class NativeHandle; class Surface; -typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer - HGraphicBufferProducer; /* * This class defines the Binder IPC interface for the producer side of @@ -62,7 +61,16 @@ typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer class IGraphicBufferProducer : public IInterface { public: - DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer) + using HGraphicBufferProducerV1_0 = + ::android::hardware::graphics::bufferqueue::V1_0:: + IGraphicBufferProducer; + using HGraphicBufferProducerV2_0 = + ::android::hardware::graphics::bufferqueue::V2_0:: + IGraphicBufferProducer; + + DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, + HGraphicBufferProducerV1_0, + HGraphicBufferProducerV2_0) enum { // A flag returned by dequeueBuffer when the client needs to call @@ -366,7 +374,6 @@ public: const HdrMetadata& getHdrMetadata() const { return hdrMetadata; } void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; } - private: int64_t timestamp{0}; int isAutoTimestamp{0}; android_dataspace dataSpace{HAL_DATASPACE_UNKNOWN}; diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h index e808bd3bc3..a13d8e4945 100644 --- a/libs/gui/include/gui/IProducerListener.h +++ b/libs/gui/include/gui/IProducerListener.h @@ -17,8 +17,10 @@ #ifndef ANDROID_GUI_IPRODUCERLISTENER_H #define ANDROID_GUI_IPRODUCERLISTENER_H +#include +#include #include - +#include #include namespace android { @@ -47,7 +49,14 @@ public: class IProducerListener : public ProducerListener, public IInterface { public: - DECLARE_META_INTERFACE(ProducerListener) + using HProducerListener1 = + ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener; + using HProducerListener2 = + ::android::hardware::graphics::bufferqueue::V2_0::IProducerListener; + DECLARE_HYBRID_META_INTERFACE( + ProducerListener, + HProducerListener1, + HProducerListener2) }; class BnProducerListener : public BnInterface diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h new file mode 100644 index 0000000000..211fdd5351 --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V1_0 { +namespace utils { + +using HProducerListener = ::android::hardware::graphics::bufferqueue::V1_0:: + IProducerListener; + +using BProducerListener = ::android::IProducerListener; + +class H2BProducerListener + : public H2BConverter { +public: + H2BProducerListener(sp const& base); + virtual void onBufferReleased() override; + virtual bool needsReleaseNotify() override; +}; + +} // namespace utils +} // namespace V1_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H + diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h new file mode 100644 index 0000000000..1c58167752 --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h @@ -0,0 +1,121 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H + +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +using HGraphicBufferProducer = + ::android::hardware::graphics::bufferqueue::V2_0:: + IGraphicBufferProducer; +using BGraphicBufferProducer = + ::android:: + IGraphicBufferProducer; +using HProducerListener = + ::android::hardware::graphics::bufferqueue::V2_0:: + IProducerListener; + +using ::android::hardware::Return; +using ::android::hardware::hidl_handle; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; + +using ::android::hardware::graphics::common::V1_2::HardwareBuffer; + +class B2HGraphicBufferProducer : public HGraphicBufferProducer { +public: + B2HGraphicBufferProducer(sp const& base); + + virtual Return setMaxDequeuedBufferCount( + int32_t maxDequeuedBuffers) override; + + virtual Return requestBuffer( + int32_t slot, + requestBuffer_cb _hidl_cb) override; + + virtual Return setAsyncMode(bool async) override; + + virtual Return dequeueBuffer( + DequeueBufferInput const& input, + dequeueBuffer_cb _hidl_cb) override; + + virtual Return detachBuffer(int32_t slot) override; + + virtual Return detachNextBuffer( + detachNextBuffer_cb _hidl_cb) override; + + virtual Return attachBuffer( + HardwareBuffer const& buffer, + uint32_t generationNumber, + attachBuffer_cb _hidl_cb) override; + + virtual Return queueBuffer( + int32_t slot, + QueueBufferInput const& input, + queueBuffer_cb _hidl_cb) override; + + virtual Return cancelBuffer( + int32_t slot, + hidl_handle const& fence) override; + + virtual Return query(int32_t what, query_cb _hidl_cb) override; + + virtual Return connect( + sp const& listener, + HConnectionType api, + bool producerControlledByApp, + connect_cb _hidl_cb) override; + + virtual Return disconnect(HConnectionType api) override; + + virtual Return allocateBuffers( + uint32_t width, uint32_t height, + uint32_t format, uint64_t usage) override; + + virtual Return allowAllocation(bool allow) override; + + virtual Return setGenerationNumber(uint32_t generationNumber) override; + + virtual Return setDequeueTimeout(int64_t timeoutNs) override; + + virtual Return getUniqueId() override; + + virtual Return getConsumerName(getConsumerName_cb _hidl_cb) override; + +protected: + sp mBase; +}; + + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h new file mode 100644 index 0000000000..b48a4736ad --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h @@ -0,0 +1,57 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H + +#include +#include +#include +#include + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +using ::android::hardware::Return; + +using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0:: + IProducerListener; + +using BProducerListener = ::android::IProducerListener; + +struct B2HProducerListener : public HProducerListener { + explicit B2HProducerListener(sp const& base); + Return onBuffersReleased(uint32_t count) override; +protected: + sp mBase; + bool mNeedsReleaseNotify; +}; + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H + diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h new file mode 100644 index 0000000000..7dd16172cf --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h @@ -0,0 +1,107 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H + +#include +#include +#include +#include + +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +using ::android::BnGraphicBufferProducer; +using ::android::IProducerListener; +using Fence = ::android::Fence; + +using HGraphicBufferProducer = + ::android::hardware::graphics::bufferqueue::V2_0:: + IGraphicBufferProducer; +using HProducerListener = + ::android::hardware::graphics::bufferqueue::V2_0:: + IProducerListener; +using BGraphicBufferProducer = + ::android::IGraphicBufferProducer; + +struct H2BGraphicBufferProducer + : public ::android::H2BConverter { + explicit H2BGraphicBufferProducer( + sp const& base) : CBase(base) {} + + virtual status_t requestBuffer(int slot, sp* buf) override; + virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override; + virtual status_t setAsyncMode(bool async) override; + virtual status_t dequeueBuffer( + int* slot, sp* fence, + uint32_t width, uint32_t height, + PixelFormat format, uint64_t usage, + uint64_t* outBufferAge, + FrameEventHistoryDelta* outTimestamps) override; + virtual status_t detachBuffer(int slot) override; + virtual status_t detachNextBuffer( + sp* outBuffer, + sp* outFence) override; + virtual status_t attachBuffer( + int* outSlot, + sp const& buffer) override; + virtual status_t queueBuffer( + int slot, + QueueBufferInput const& input, + QueueBufferOutput* output) override; + virtual status_t cancelBuffer(int slot, sp const& fence) override; + virtual int query(int what, int* value) override; + virtual status_t connect( + sp const& listener, + int api, + bool producerControlledByApp, + QueueBufferOutput* output) override; + virtual status_t disconnect( + int api, + DisconnectMode mode = DisconnectMode::Api) override; + virtual status_t setSidebandStream(sp const& stream) override; + virtual void allocateBuffers( + uint32_t width, uint32_t height, + PixelFormat format, uint64_t usage) override; + virtual status_t allowAllocation(bool allow) override; + virtual status_t setGenerationNumber(uint32_t generationNumber) override; + virtual String8 getConsumerName() const override; + virtual status_t setSharedBufferMode(bool sharedBufferMode) override; + virtual status_t setAutoRefresh(bool autoRefresh) override; + virtual status_t setDequeueTimeout(nsecs_t timeout) override; + virtual status_t getLastQueuedBuffer(sp* outBuffer, + sp* outFence, float outTransformMatrix[16]) override; + virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override; + virtual status_t getUniqueId(uint64_t* outId) const override; + virtual status_t getConsumerUsage(uint64_t* outUsage) const override; +}; + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h new file mode 100644 index 0000000000..898920bf8a --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H + +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0:: + IProducerListener; + +using BProducerListener = ::android::IProducerListener; + +class H2BProducerListener + : public H2BConverter { +public: + H2BProducerListener(sp const& base); + virtual void onBufferReleased() override; + virtual bool needsReleaseNotify() override; +}; + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H + diff --git a/libs/gui/include/gui/bufferqueue/2.0/types.h b/libs/gui/include/gui/bufferqueue/2.0/types.h new file mode 100644 index 0000000000..62176ce2ef --- /dev/null +++ b/libs/gui/include/gui/bufferqueue/2.0/types.h @@ -0,0 +1,129 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H +#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H + +#include +#include +#include +#include +#include + +namespace android { +namespace hardware { +namespace graphics { +namespace bufferqueue { +namespace V2_0 { +namespace utils { + +// Status +// ====== + +using HStatus = ::android::hardware::graphics::bufferqueue::V2_0:: + Status; + +// A status_t value may have flags encoded. These flags are decoded into boolean +// values if their corresponding output pointers are not null. +bool b2h(status_t from, HStatus* to, + bool* bufferNeedsReallocation = nullptr, + bool* releaseAllBuffers = nullptr); +// Simple 1-to-1 mapping. If BUFFER_NEEDS_REALLOCATION or RELEASE_ALL_BUFFERS +// needs to be added, it must be done manually afterwards. +bool h2b(HStatus from, status_t* to); + +// Fence +// ===== + +using BFence = ::android::Fence; +// This class manages the lifetime of a copied handle. Its destructor calls +// native_handle_delete() but not native_handle_close(). +struct HFenceWrapper { + HFenceWrapper() = default; + // Sets mHandle to a new value. + HFenceWrapper(native_handle_t* h); + // Deletes mHandle without closing. + ~HFenceWrapper(); + // Deletes mHandle without closing, then sets mHandle to a new value. + HFenceWrapper& set(native_handle_t* h); + HFenceWrapper& operator=(native_handle_t* h); + // Returns a non-owning hidl_handle pointing to mHandle. + hidl_handle getHandle() const; + operator hidl_handle() const; +protected: + native_handle_t* mHandle{nullptr}; +}; + +// Does not clone the fd---only copy the fd. The returned HFenceWrapper should +// not outlive the input Fence object. +bool b2h(sp const& from, HFenceWrapper* to); +// Clones the fd and puts it in a new Fence object. +bool h2b(native_handle_t const* from, sp* to); + +// ConnectionType +// ============== + +using HConnectionType = ::android::hardware::graphics::bufferqueue::V2_0:: + ConnectionType; + +bool b2h(int from, HConnectionType* to); +bool h2b(HConnectionType from, int* to); + +// Rect +// ==== + +using BRect = ::android::Rect; +using HRect = ::android::hardware::graphics::common::V1_2::Rect; + +bool b2h(BRect const& from, HRect* to); +bool h2b(HRect const& from, BRect* to); + +// Region +// ====== + +using BRegion = ::android::Region; +using HRegion = ::android::hardware::hidl_vec; + +bool b2h(BRegion const& from, HRegion* to); +bool h2b(HRegion const& from, BRegion* to); + +// GraphicBuffer +// ============= + +using HardwareBuffer = ::android::hardware::graphics::common::V1_2:: + HardwareBuffer; +using HardwareBufferDescription = ::android::hardware::graphics::common::V1_2:: + HardwareBufferDescription; + +// Does not clone the handle. The returned HardwareBuffer should not outlive the +// input GraphicBuffer. Note that HardwareBuffer does not carry the generation +// number, so this function needs another output argument. +bool b2h(sp const& from, HardwareBuffer* to, + uint32_t* toGenerationNumber = nullptr); +// Clones the handle and creates a new GraphicBuffer from the cloned handle. +// Note that the generation number of the GraphicBuffer has to be set manually +// afterwards because HardwareBuffer does not have such information. +bool h2b(HardwareBuffer const& from, sp* to); + +} // namespace utils +} // namespace V2_0 +} // namespace bufferqueue +} // namespace graphics +} // namespace hardware +} // namespace android + +#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H + diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 994e953e76..52fc9d5bad 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -636,11 +636,11 @@ uint64_t AHardwareBuffer_convertFromGrallocUsageBits(uint64_t usage) { } const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer) { - return reinterpret_cast(buffer); + return GraphicBuffer::fromAHardwareBuffer(buffer); } GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer) { - return reinterpret_cast(buffer); + return GraphicBuffer::fromAHardwareBuffer(buffer); } const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer) { @@ -652,7 +652,7 @@ ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(AHardwareBuffer* buf } AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) { - return reinterpret_cast(buffer); + return buffer->toAHardwareBuffer(); } } // namespace android diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index d8478848cb..27ab482676 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -24,7 +24,7 @@ ndk_headers { cc_library_headers { name: "libnativewindow_headers", export_include_dirs: ["include"], - vendor_available: false, + vendor_available: true, } ndk_library { diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 4ca1781be1..e521b613a0 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -124,7 +124,6 @@ cc_library_shared { exclude_header_libs: [ "libbufferhub_headers", "libdvr_headers", - "libnativewindow_headers", ], exclude_shared_libs: [ "android.frameworks.bufferhub@1.0", @@ -152,6 +151,7 @@ cc_library_shared { export_header_lib_headers: [ "libbase_headers", "libnativebase_headers", + "libnativewindow_headers", "libhardware_headers", "libui_headers", ], diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 79958ece9e..f800627ef7 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -49,6 +49,22 @@ sp GraphicBuffer::from(ANativeWindowBuffer* anwb) { return static_cast(anwb); } +GraphicBuffer* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer* buffer) { + return reinterpret_cast(buffer); +} + +GraphicBuffer const* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer const* buffer) { + return reinterpret_cast(buffer); +} + +AHardwareBuffer* GraphicBuffer::toAHardwareBuffer() { + return reinterpret_cast(this); +} + +AHardwareBuffer const* GraphicBuffer::toAHardwareBuffer() const { + return reinterpret_cast(this); +} + GraphicBuffer::GraphicBuffer() : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()), mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0) diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h index ec67fa972c..6efecd3c0e 100644 --- a/libs/ui/include/ui/Fence.h +++ b/libs/ui/include/ui/Fence.h @@ -99,6 +99,12 @@ public: // be returned and errno will indicate the problem. int dup() const; + // Return the underlying file descriptor without giving up ownership. The + // returned file descriptor is only valid for as long as the owning Fence + // object lives. (If the situation is unclear, dup() is always a safer + // option.) + int get() const { return mFenceFd.get(); } + // getSignalTime returns the system monotonic clock time at which the // fence transitioned to the signaled state. If the fence is not signaled // then SIGNAL_TIME_PENDING is returned. If the fence is invalid or if an diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 4d4ee68194..e0c655813d 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -22,6 +22,7 @@ #include +#include #include #include #include @@ -78,6 +79,10 @@ public: static sp from(ANativeWindowBuffer *); + static GraphicBuffer* fromAHardwareBuffer(AHardwareBuffer*); + static GraphicBuffer const* fromAHardwareBuffer(AHardwareBuffer const*); + AHardwareBuffer* toAHardwareBuffer(); + AHardwareBuffer const* toAHardwareBuffer() const; // Create a GraphicBuffer to be unflatten'ed into or be reallocated. GraphicBuffer(); -- cgit v1.2.3-59-g8ed1b From d2f4dafa520baef942ed2937f8a328018f3fc72d Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Fri, 15 Feb 2019 13:49:00 -0800 Subject: Adding lock function that obtains bytesPerPixel and bytesPerStride Bug: 123423521 Test: build, boot, manual Change-Id: I480d60fe4975c5ffee6d6c253c37ffd20cea79c3 --- libs/nativewindow/AHardwareBuffer.cpp | 53 +++++++++++++++++++++- .../nativewindow/include/android/hardware_buffer.h | 12 +++++ libs/nativewindow/libnativewindow.map.txt | 1 + libs/ui/GraphicBufferMapper.cpp | 3 ++ libs/ui/include/ui/GraphicBuffer.h | 5 ++ libs/ui/include/ui/GraphicBufferMapper.h | 8 ++++ 6 files changed, 80 insertions(+), 2 deletions(-) (limited to 'libs/nativewindow/AHardwareBuffer.cpp') diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 52fc9d5bad..bf80481c44 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -93,8 +93,57 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, outDesc->rfu1 = 0; } +int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage, + int32_t fence, const ARect* rect, void** outVirtualAddress, + int32_t* outBytesPerPixel, int32_t* outBytesPerStride) { + if (!buffer) return BAD_VALUE; + + 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"); + return BAD_VALUE; + } + + usage = AHardwareBuffer_convertToGrallocUsageBits(usage); + GraphicBuffer* gbuffer = AHardwareBuffer_to_GraphicBuffer(buffer); + + //Mapper implementations before 3.0 will not return bytes per pixel or + //bytes per stride information. + if (gbuffer->getBufferMapperVersion() == GraphicBufferMapper::Version::GRALLOC_2) { + ALOGE("Mapper versions before 3.0 cannot retrieve bytes per pixel and bytes per stride info"); + return INVALID_OPERATION; + } + + 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())); + } else { + bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom)); + } + int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, outBytesPerPixel, outBytesPerStride); + + // if hardware returns -1 for bytes per pixel or bytes per stride, we fail + // and unlock the buffer + if (*outBytesPerPixel == -1 || *outBytesPerStride == -1) { + gbuffer->unlock(); + return INVALID_OPERATION; + } + + return result; +} + int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, - int32_t fence, const ARect* rect, void** outVirtualAddress) { + int32_t fence, const ARect* rect, void** outVirtualAddress) { + int32_t bytesPerPixel; + int32_t bytesPerStride; + if (!buffer) return BAD_VALUE; if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK | @@ -119,7 +168,7 @@ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, } 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, &bytesPerPixel, &bytesPerStride); } int AHardwareBuffer_lockPlanes(AHardwareBuffer* buffer, uint64_t usage, diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h index 02c7c1b934..165b75a218 100644 --- a/libs/nativewindow/include/android/hardware_buffer.h +++ b/libs/nativewindow/include/android/hardware_buffer.h @@ -421,6 +421,18 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26); +/** + * Lock an AHardwareBuffer for direct CPU access. + * + * This function is the same as the above lock function, but passes back + * additional information about the bytes per pixel and the bytes per stride + * of the locked buffer. If the bytes per pixel or bytes per stride are unknown + * or variable, or if the underlying mapper implementation does not support returning + * additional information, then this call will fail with INVALID_OPERATION + */ +int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage, + int32_t fence, const ARect* rect, void** outVirtualAddress, + int32_t* outBytesPerPixel, int32_t* outBytesPerStride) __INTRODUCED_IN(29); /** * Lock a potentially multi-planar AHardwareBuffer for direct CPU access. * diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index a796e97e29..23a05f3dca 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -7,6 +7,7 @@ LIBNATIVEWINDOW { AHardwareBuffer_getNativeHandle; # vndk AHardwareBuffer_isSupported; # introduced=29 AHardwareBuffer_lock; + AHardwareBuffer_lockAndGetInfo; # introduced=29 AHardwareBuffer_recvHandleFromUnixSocket; AHardwareBuffer_release; AHardwareBuffer_sendHandleToUnixSocket; diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp index 06981c39a5..25b7247b1b 100644 --- a/libs/ui/GraphicBufferMapper.cpp +++ b/libs/ui/GraphicBufferMapper.cpp @@ -53,6 +53,9 @@ GraphicBufferMapper::GraphicBufferMapper() { mMapper = std::make_unique(); if (!mMapper->isLoaded()) { mMapper = std::make_unique(); + mMapperVersion = Version::GRALLOC_2; + } else { + mMapperVersion = Version::GRALLOC_3; } if (!mMapper->isLoaded()) { diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index e0c655813d..1c88777961 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -214,6 +215,10 @@ public: status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); + GraphicBufferMapper::Version getBufferMapperVersion() const { + return mBufferMapper.getMapperVersion(); + } + #ifndef LIBUI_IN_VNDK // Returns whether this GraphicBuffer is backed by BufferHubBuffer. bool isBufferHubBuffer() const; diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h index 77c99ccd07..24614549be 100644 --- a/libs/ui/include/ui/GraphicBufferMapper.h +++ b/libs/ui/include/ui/GraphicBufferMapper.h @@ -41,6 +41,10 @@ class Rect; class GraphicBufferMapper : public Singleton { public: + enum Version { + GRALLOC_2, + GRALLOC_3, + }; static void preloadHal(); static inline GraphicBufferMapper& get() { return getInstance(); } @@ -85,12 +89,16 @@ public: return reinterpret_cast(*mMapper); } + Version getMapperVersion() const { return mMapperVersion; } + private: friend class Singleton; GraphicBufferMapper(); std::unique_ptr mMapper; + + Version mMapperVersion; }; // --------------------------------------------------------------------------- -- cgit v1.2.3-59-g8ed1b From 12d2d640765f54149dac22a570f2f687033ca4e5 Mon Sep 17 00:00:00 2001 From: Valerie Hau Date: Fri, 22 Mar 2019 08:47:00 -0700 Subject: Setting bpp and bps to -1 whenever returning error Bug: 123423521 Test: build, boot, android.hardware.nativehardware.cts.AHardwareBufferNativeTests Change-Id: If8aa16ff48c04cff829e0bb1eb897bb643cd6fb1 --- libs/nativewindow/AHardwareBuffer.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'libs/nativewindow/AHardwareBuffer.cpp') diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index bf80481c44..9bd30955f3 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -96,7 +96,12 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer, int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage, int32_t fence, const ARect* rect, void** outVirtualAddress, int32_t* outBytesPerPixel, int32_t* outBytesPerStride) { - if (!buffer) return BAD_VALUE; + if (outBytesPerPixel) *outBytesPerPixel = -1; + if (outBytesPerStride) *outBytesPerStride = -1; + + if (!buffer) { + return BAD_VALUE; + } if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK | AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) { @@ -127,15 +132,19 @@ int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage, } else { bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom)); } - int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, outBytesPerPixel, outBytesPerStride); + int32_t bytesPerPixel; + int32_t bytesPerStride; + int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride); // if hardware returns -1 for bytes per pixel or bytes per stride, we fail // and unlock the buffer - if (*outBytesPerPixel == -1 || *outBytesPerStride == -1) { + if (bytesPerPixel == -1 || bytesPerStride == -1) { gbuffer->unlock(); return INVALID_OPERATION; } + if (outBytesPerPixel) *outBytesPerPixel = bytesPerPixel; + if (outBytesPerStride) *outBytesPerStride = bytesPerStride; return result; } -- cgit v1.2.3-59-g8ed1b