Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ce2425d7 authored by Krzysztof Kosiński's avatar Krzysztof Kosiński Committed by Android (Google) Code Review
Browse files

Merge "Add AHardwareBuffer_isSupported."

parents f2acf820 a5c54bc6
Loading
Loading
Loading
Loading
+98 −37
Original line number Diff line number Diff line
@@ -41,32 +41,10 @@ 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);
    sp<GraphicBuffer> gbuffer(new GraphicBuffer(
            desc->width, desc->height, format, desc->layers, usage,
@@ -127,14 +105,21 @@ int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
    }

    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;
    }

static inline bool containsBits(uint64_t mask, uint64_t bitsToCheck) {
    return (mask & bitsToCheck) == bitsToCheck && bitsToCheck;
    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;
    }

    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");
+5 −0
Original line number Diff line number Diff line
@@ -28,10 +28,15 @@
#include <stdint.h>

struct AHardwareBuffer;
struct AHardwareBuffer_Desc;
struct ANativeWindowBuffer;

namespace android {

// Validates whether the passed description does not have conflicting
// parameters. Note: this does not verify any platform-specific contraints.
bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log);

// whether this AHardwareBuffer format is valid
bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format);

+122 −53
Original line number Diff line number Diff line
@@ -102,8 +102,10 @@ enum AHardwareBuffer_Format {
    AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM        = 0x2b,

    /**
     * An opaque binary blob format that must have height 1, with width equal to
     * the buffer size in bytes.
     * Opaque binary blob format.
     * Must have height 1 and one layer, with width equal to the buffer
     * size in bytes. Corresponds to Vulkan buffers and OpenGL buffer
     * objects. Can be bound to the latter using GL_EXT_external_buffer.
     */
    AHARDWAREBUFFER_FORMAT_BLOB                     = 0x21,

@@ -195,20 +197,25 @@ enum AHardwareBuffer_UsageFlags {
    /// The buffer will be written to by the GPU as a framebuffer attachment.
    AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER        = 1UL << 9,
    /**
     * The buffer will be written to by the GPU as a framebuffer attachment.
     * Note that the name of this flag is somewhat misleading: it does not imply
     * that the buffer contains a color format. A buffer with depth or stencil
     * format that will be used as a framebuffer attachment should also have
     * this flag.
     * The buffer will be written to by the GPU as a framebuffer
     * attachment.
     *
     * Note that the name of this flag is somewhat misleading: it does
     * not imply that the buffer contains a color format. A buffer with
     * depth or stencil format that will be used as a framebuffer
     * attachment should also have this flag. Use the equivalent flag
     * AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER to avoid this confusion.
     */
    AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT       = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER,
    /**
     * The buffer is protected from direct CPU access or being read by non-secure
     * hardware, such as video encoders. This flag is incompatible with CPU
     * read and write flags. It is mainly used when handling DRM video.
     * Refer to the EGL extension EGL_EXT_protected_content and GL extension
     * EXT_protected_textures for more information on how these buffers are expected
     * to behave.
     * The buffer is protected from direct CPU access or being read by
     * non-secure hardware, such as video encoders.
     *
     * This flag is incompatible with CPU read and write flags. It is
     * mainly used when handling DRM video. Refer to the EGL extension
     * EGL_EXT_protected_content and GL extension
     * GL_EXT_protected_textures for more information on how these
     * buffers are expected to behave.
     */
    AHARDWAREBUFFER_USAGE_PROTECTED_CONTENT      = 1UL << 14,
    /// The buffer will be read by a hardware video encoder.
@@ -225,11 +232,17 @@ enum AHardwareBuffer_UsageFlags {
    AHARDWAREBUFFER_USAGE_GPU_DATA_BUFFER        = 1UL << 24,
    /**
     * The buffer will be used as a cube map texture.
     * When this flag is present, the buffer must have a layer count that is
     * a multiple of 6.
     * When this flag is present, the buffer must have a layer count
     * that is a multiple of 6. Note that buffers with this flag must be
     * bound to OpenGL textures using the extension
     * GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
     */
    AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP               = 1UL << 25,
    /// The buffer contains a complete mipmap hierarchy.
    /**
     * The buffer contains a complete mipmap hierarchy.
     * Note that buffers with this flag must be bound to OpenGL textures using
     * the extension GL_EXT_EGL_image_storage instead of GL_KHR_EGL_image.
     */
    AHARDWAREBUFFER_USAGE_GPU_MIPMAP_COMPLETE        = 1UL << 26,

    AHARDWAREBUFFER_USAGE_VENDOR_0  = 1ULL << 28,
@@ -255,13 +268,21 @@ enum AHardwareBuffer_UsageFlags {
};

/**
 * Buffer description. Used for allocating new buffers and querying parameters
 * of existing ones.
 * Buffer description. Used for allocating new buffers and querying
 * parameters of existing ones.
 */
typedef struct AHardwareBuffer_Desc {
    uint32_t    width;      ///< Width in pixels.
    uint32_t    height;     ///< Height in pixels.
    uint32_t    layers;     ///< Number of images in an image array.
    /**
     * Number of images in an image array. AHardwareBuffers with one
     * layer correspond to regular 2D textures. AHardwareBuffers with
     * more than layer correspond to texture arrays. If the layer count
     * is a multiple of 6 and the usage flag
     * AHARDWAREBUFFER_USAGE_GPU_CUBE_MAP is present, the buffer is
     * a cube map or a cube map array.
     */
    uint32_t    layers;
    uint32_t    format;     ///< One of AHardwareBuffer_Format.
    uint64_t    usage;      ///< Combination of AHardwareBuffer_UsageFlags.
    uint32_t    stride;     ///< Row stride in pixels, ignored for AHardwareBuffer_allocate()
@@ -290,8 +311,10 @@ typedef struct AHardwareBuffer AHardwareBuffer;
int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
        AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
/**
 * Acquire a reference on the given AHardwareBuffer object.  This prevents the
 * object from being deleted until the last reference is removed.
 * Acquire a reference on the given AHardwareBuffer object.
 * 
 * This prevents the object from being deleted until the last reference
 * is removed.
 */
void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);

@@ -309,50 +332,73 @@ void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
        AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);

/**
 * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
 * passed.  This call may block if the hardware needs to finish rendering or if
 * CPU caches need to be synchronized, or possibly for other implementation-
 * specific reasons.  If fence is not negative, then it specifies a fence file
 * descriptor that will be signaled when the buffer is locked, otherwise the
 * caller will block until the buffer is available.
 * Lock the AHardwareBuffer for direct CPU access.
 *
 * If \a rect is not NULL, the caller promises to modify only data in the area
 * specified by rect. If rect is NULL, the caller may modify the contents of the
 * entire buffer.
 * This function can lock the buffer for either reading or writing.
 * It may block if the hardware needs to finish rendering, if CPU caches
 * need to be synchronized, or possibly for other implementation-
 * specific reasons.
 *
 * The content of the buffer outside of the specified rect is NOT modified
 * by this call.
 * The passed AHardwareBuffer must have one layer, otherwise the call
 * will fail.
 *
 * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*. If set,
 * then outVirtualAddress is filled with the address of the buffer in virtual
 * memory.
 * If \a fence is not negative, it specifies a fence file descriptor on
 * which to wait before locking the buffer. If it's negative, the caller
 * is responsible for ensuring that writes to the buffer have completed
 * before calling this function.  Using this parameter is more efficient
 * than waiting on the fence and then calling this function.
 *
 * The \a usage parameter may only specify AHARDWAREBUFFER_USAGE_CPU_*.
 * If set, then outVirtualAddress is filled with the address of the
 * buffer in virtual memory. The flags must also be compatible with
 * usage flags specified at buffer creation: if a read flag is passed,
 * the buffer must have been created with
 * AHARDWAREBUFFER_USAGE_CPU_READ_RARELY or
 * AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN. If a write flag is passed, it
 * must have been created with AHARDWAREBUFFER_USAGE_CPU_WRITE_RARELY or
 * AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN.
 *
 * THREADING CONSIDERATIONS:
 * If \a rect is not NULL, the caller promises to modify only data in
 * the area specified by rect. If rect is NULL, the caller may modify
 * the contents of the entire buffer. The content of the buffer outside
 * of the specified rect is NOT modified by this call.
 *
 * It is legal for several different threads to lock a buffer for read access;
 * none of the threads are blocked.
 * It is legal for several different threads to lock a buffer for read
 * access; none of the threads are blocked.
 *
 * Locking a buffer simultaneously for write or read/write is undefined, but
 * will neither terminate the process nor block the caller; AHardwareBuffer_lock
 * may return an error or leave the buffer's content into an indeterminate
 * state.
 * Locking a buffer simultaneously for write or read/write is undefined,
 * but will neither terminate the process nor block the caller.
 * AHardwareBuffer_lock may return an error or leave the buffer's
 * content in an indeterminate state.
 *
 * If the buffer has AHARDWAREBUFFER_FORMAT_BLOB, it is legal lock it
 * for reading and writing in multiple threads and/or processes
 * simultaneously, and the contents of the buffer behave like shared
 * memory.
 *
 * \return 0 on success, -EINVAL if \a buffer is NULL or if the usage
 * flags are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or an error
 * number of the lock fails for any reason.
 * \return 0 on success. -EINVAL if \a buffer is NULL, the usage flags
 * are not a combination of AHARDWAREBUFFER_USAGE_CPU_*, or the buffer
 * has more than one layer. Error number if the lock fails for any other
 * reason.
 */
int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
        int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);

/**
 * Unlock the AHardwareBuffer; must be called after all changes to the buffer
 * are completed by the caller. If fence is not NULL then it will be set to a
 * file descriptor that is signaled when all pending work on the buffer is
 * completed. The caller is responsible for closing the fence when it is no
 * longer needed.
 * Unlock the AHardwareBuffer from direct CPU access.
 *
 * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
 * number if the unlock fails for any reason.
 * Must be called after all changes to the buffer are completed by the
 * caller.  If \a fence is NULL, the function will block until all work
 * is completed.  Otherwise, \a fence will be set either to a valid file
 * descriptor or to -1.  The file descriptor will become signaled once
 * the unlocking is complete and buffer contents are updated.
 * The caller is responsible for closing the file descriptor once it's
 * no longer needed.  The value -1 indicates that unlocking has already
 * completed before the function returned and no further operations are
 * necessary.
 *
 * \return 0 on success. -EINVAL if \a buffer is NULL. Error number if
 * the unlock fails for any reason.
 */
int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26);

@@ -365,7 +411,7 @@ int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED
int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26);

/**
 * Receive the AHardwareBuffer from an AF_UNIX socket.
 * Receive an AHardwareBuffer from an AF_UNIX socket.
 *
 * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
 * number if the operation fails for any reason.
@@ -374,6 +420,29 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out

#endif // __ANDROID_API__ >= 26

#if __ANDROID_API__ >= 29

/**
 * Test whether the given format and usage flag combination is
 * allocatable.
 *
 * If this function returns true, it means that a buffer with the given
 * description can be allocated on this implementation, unless resource
 * exhaustion occurs. If this function returns false, it means that the
 * allocation of the given description will never succeed.
 *
 * The return value of this function may depend on all fields in the
 * description, except stride, which is always ignored. For example,
 * some implementations have implementation-defined limits on texture
 * size and layer count.
 *
 * \return 1 if the format and usage flag combination is allocatable,
 *     0 otherwise.
 */
int AHardwareBuffer_isSupported(const AHardwareBuffer_Desc* desc) __INTRODUCED_IN(29);

#endif // __ANDROID_API__ >= 29

__END_DECLS

#endif // ANDROID_HARDWARE_BUFFER_H
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ LIBNATIVEWINDOW {
    AHardwareBuffer_createFromHandle; # vndk
    AHardwareBuffer_describe;
    AHardwareBuffer_getNativeHandle; # vndk
    AHardwareBuffer_isSupported; # introduced=29
    AHardwareBuffer_lock;
    AHardwareBuffer_recvHandleFromUnixSocket;
    AHardwareBuffer_release;