Merge "graphics: revise gralloc interfaces" into oc-dev

This commit is contained in:
Chia-I Wu
2017-04-11 01:08:37 +00:00
committed by Android (Google) Code Review
45 changed files with 2460 additions and 2455 deletions

View File

@@ -23,7 +23,6 @@
#include <android/log.h>
#include <cutils/native_handle.h>
#include <ui/GraphicBufferMapper.h>
#include <ui/GraphicBuffer.h>
#include <algorithm> // std::min
@@ -135,11 +134,7 @@ Return<void> FrameHandler::deliverFrame(const BufferDesc& bufferArg) {
// Local flag we use to keep track of when the stream is stopping
bool timeToStop = false;
// TODO: Why do we get a gralloc crash if we don't clone the buffer here?
BufferDesc buffer(bufferArg);
ALOGD("Clone the received frame as %p", buffer.memHandle.getNativeHandle());
if (buffer.memHandle.getNativeHandle() == nullptr) {
if (bufferArg.memHandle.getNativeHandle() == nullptr) {
// Signal that the last frame has been received and the stream is stopped
timeToStop = true;
} else {
@@ -157,13 +152,8 @@ Return<void> FrameHandler::deliverFrame(const BufferDesc& bufferArg) {
printf("Didn't get target buffer - frame lost\n");
ALOGE("Didn't get requested output buffer -- skipping this frame.");
} else {
// In order for the handles passed through HIDL and stored in the BufferDesc to
// be lockable, we must register them with GraphicBufferMapper
registerBufferHelper(tgtBuffer);
registerBufferHelper(buffer);
// Copy the contents of the of buffer.memHandle into tgtBuffer
copyBufferContents(tgtBuffer, buffer);
copyBufferContents(tgtBuffer, bufferArg);
// Send the target buffer back for display
Return <EvsResult> result = mDisplay->returnTargetBufferForDisplay(tgtBuffer);
@@ -183,10 +173,6 @@ Return<void> FrameHandler::deliverFrame(const BufferDesc& bufferArg) {
mFramesDisplayed++;
mLock.unlock();
}
// Now tell GraphicBufferMapper we won't be using these handles anymore
unregisterBufferHelper(tgtBuffer);
unregisterBufferHelper(buffer);
}
}
@@ -233,24 +219,22 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer,
const unsigned height = std::min(tgtBuffer.height,
srcBuffer.height);
android::GraphicBufferMapper &mapper = android::GraphicBufferMapper::get();
sp<android::GraphicBuffer> tgt = new android::GraphicBuffer(
tgtBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
tgtBuffer.width, tgtBuffer.height, tgtBuffer.format, 1, tgtBuffer.usage,
tgtBuffer.stride);
sp<android::GraphicBuffer> src = new android::GraphicBuffer(
srcBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE,
srcBuffer.width, srcBuffer.height, srcBuffer.format, 1, srcBuffer.usage,
srcBuffer.stride);
// Lock our source buffer for reading
unsigned char* srcPixels = nullptr;
mapper.registerBuffer(srcBuffer.memHandle);
mapper.lock(srcBuffer.memHandle,
GRALLOC_USAGE_SW_READ_OFTEN,
android::Rect(width, height),
(void **) &srcPixels);
src->lock(GRALLOC_USAGE_SW_READ_OFTEN, (void**)&srcPixels);
// Lock our target buffer for writing
unsigned char* tgtPixels = nullptr;
mapper.registerBuffer(tgtBuffer.memHandle);
mapper.lock(tgtBuffer.memHandle,
GRALLOC_USAGE_SW_WRITE_OFTEN,
android::Rect(width, height),
(void **) &tgtPixels);
tgt->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)&tgtPixels);
if (srcPixels && tgtPixels) {
for (unsigned row = 0; row < height; row++) {
@@ -267,45 +251,11 @@ bool FrameHandler::copyBufferContents(const BufferDesc& tgtBuffer,
}
if (srcPixels) {
mapper.unlock(srcBuffer.memHandle);
src->unlock();
}
if (tgtPixels) {
mapper.unlock(tgtBuffer.memHandle);
tgt->unlock();
}
mapper.unregisterBuffer(srcBuffer.memHandle);
mapper.unregisterBuffer(tgtBuffer.memHandle);
return success;
}
void FrameHandler::registerBufferHelper(const BufferDesc& buffer)
{
// In order for the handles passed through HIDL and stored in the BufferDesc to
// be lockable, we must register them with GraphicBufferMapper.
// If the device upon which we're running supports gralloc1, we could just call
// registerBuffer directly with the handle. But that call is broken for gralloc0 devices
// (which we care about, at least for now). As a result, we have to synthesize a GraphicBuffer
// object around the buffer handle in order to make a call to the overloaded alternate
// version of the registerBuffer call that does happen to work on gralloc0 devices.
#if REGISTER_BUFFER_ALWAYS_WORKS
android::GraphicBufferMapper::get().registerBuffer(buffer.memHandle);
#else
android::sp<android::GraphicBuffer> pGfxBuff = new android::GraphicBuffer(
buffer.width, buffer.height, buffer.format,
1, /* we always use exactly one layer */
buffer.usage, buffer.stride,
const_cast<native_handle_t*>(buffer.memHandle.getNativeHandle()),
false /* GraphicBuffer should not try to free the handle */
);
android::GraphicBufferMapper::get().registerBuffer(pGfxBuff.get());
#endif
}
void FrameHandler::unregisterBufferHelper(const BufferDesc& buffer)
{
// Now tell GraphicBufferMapper we won't be using these handles anymore
android::GraphicBufferMapper::get().unregisterBuffer(buffer.memHandle);
}

View File

@@ -68,8 +68,6 @@ private:
// Local implementation details
bool copyBufferContents(const BufferDesc& tgtBuffer, const BufferDesc& srcBuffer);
void registerBufferHelper(const BufferDesc& buffer);
void unregisterBufferHelper(const BufferDesc& buffer);
// Values initialized as startup
android::sp <IEvsCamera> mCamera;

View File

@@ -66,7 +66,6 @@ cc_library_shared {
"libutils",
"libcutils",
"android.hardware.camera.common@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
@@ -76,7 +75,6 @@ cc_library_shared {
"libhwbinder",
"libutils",
"android.hardware.camera.common@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],

View File

@@ -17,7 +17,6 @@
package android.hardware.camera.device@1.0;
import android.hardware.camera.common@1.0::types;
import android.hardware.graphics.allocator@2.0::types;
import android.hardware.graphics.common@1.0::types;
/**
@@ -89,7 +88,7 @@ interface ICameraDevicePreviewCallback {
*
* @return Status The status code for this operation.
*/
setUsage(ProducerUsage usage) generates (Status status);
setUsage(BufferUsage usage) generates (Status status);
/**
* Set the expected buffering mode for the preview output.

View File

@@ -30,7 +30,7 @@ namespace device {
namespace V1_0 {
namespace implementation {
using ::android::hardware::graphics::allocator::V2_0::ProducerUsage;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
HandleImporter& CameraDevice::sHandleImporter = HandleImporter::getInstance();
@@ -259,7 +259,7 @@ int CameraDevice::sSetUsage(struct preview_stream_ops* w, int usage) {
}
object->cleanUpCirculatingBuffers();
return getStatusT(object->mPreviewCallback->setUsage((ProducerUsage) usage));
return getStatusT(object->mPreviewCallback->setUsage((BufferUsage)usage));
}
int CameraDevice::sSetSwapInterval(struct preview_stream_ops *w, int interval) {

View File

@@ -66,7 +66,6 @@ cc_library_shared {
"libutils",
"libcutils",
"android.hardware.camera.common@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
@@ -76,7 +75,6 @@ cc_library_shared {
"libhwbinder",
"libutils",
"android.hardware.camera.common@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],

View File

@@ -650,7 +650,8 @@ Return<void> CameraDeviceSession::configureStreams(
mVideoStreamIds.clear();
for (const auto& stream : requestedConfiguration.streams) {
if (stream.streamType == StreamType::OUTPUT &&
stream.usage & graphics::allocator::V2_0::ConsumerUsage::VIDEO_ENCODER) {
stream.usage &
graphics::common::V1_0::BufferUsage::VIDEO_ENCODER) {
mVideoStreamIds.push_back(stream.id);
}
}

View File

@@ -28,8 +28,7 @@ namespace implementation {
using ::android::hardware::graphics::common::V1_0::Dataspace;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
using ::android::hardware::camera::device::V3_2::ConsumerUsageFlags;
using ::android::hardware::camera::device::V3_2::ProducerUsageFlags;
using ::android::hardware::camera::device::V3_2::BufferUsageFlags;
bool convertFromHidl(const CameraMetadata &src, const camera_metadata_t** dst) {
if (src.size() == 0) {
@@ -78,11 +77,11 @@ void convertToHidl(const Camera3Stream* src, HalStream* dst) {
dst->overrideFormat = (PixelFormat) src->format;
dst->maxBuffers = src->max_buffers;
if (src->stream_type == CAMERA3_STREAM_OUTPUT) {
dst->consumerUsage = (ConsumerUsageFlags) 0;
dst->producerUsage = (ProducerUsageFlags) src->usage;
dst->consumerUsage = (BufferUsageFlags)0;
dst->producerUsage = (BufferUsageFlags)src->usage;
} else if (src->stream_type == CAMERA3_STREAM_INPUT) {
dst->producerUsage = (ProducerUsageFlags) 0;
dst->consumerUsage = (ConsumerUsageFlags) src->usage;
dst->producerUsage = (BufferUsageFlags)0;
dst->consumerUsage = (BufferUsageFlags)src->usage;
} else {
//Should not reach here per current HIDL spec, but we might end up adding
// bi-directional stream to HIDL.

View File

@@ -16,12 +16,10 @@
package android.hardware.camera.device@3.2;
import android.hardware.graphics.allocator@2.0::types;
import android.hardware.graphics.common@1.0::types;
typedef vec<uint8_t> CameraMetadata;
typedef bitfield<ProducerUsage> ProducerUsageFlags;
typedef bitfield<ConsumerUsage> ConsumerUsageFlags;
typedef bitfield<BufferUsage> BufferUsageFlags;
typedef bitfield<Dataspace> DataspaceFlags;
/**
@@ -255,7 +253,7 @@ struct Stream {
* with ILLEGAL_ARGUMENT if the combined flags cannot be supported due to
* imcompatible buffer format, dataSpace, or other hardware limitations.
*/
ConsumerUsageFlags usage;
BufferUsageFlags usage;
/**
* A field that describes the contents of the buffer. The format and buffer
@@ -373,8 +371,8 @@ struct HalStream {
* consumerUsage must be set. For other types, producerUsage must be set,
* and consumerUsage must be 0.
*/
ProducerUsageFlags producerUsage;
ConsumerUsageFlags consumerUsage;
BufferUsageFlags producerUsage;
BufferUsageFlags consumerUsage;
/**
* The maximum number of buffers the HAL device may need to have dequeued at

View File

@@ -57,7 +57,6 @@ cc_library_shared {
"android.hardware.camera.common@1.0",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
@@ -69,7 +68,6 @@ cc_library_shared {
"android.hardware.camera.common@1.0",
"android.hardware.camera.device@1.0",
"android.hardware.camera.device@3.2",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],

View File

@@ -52,8 +52,8 @@ using ::android::BufferQueue;
using ::android::BufferItemConsumer;
using ::android::Surface;
using ::android::CameraParameters;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
using ::android::hardware::graphics::allocator::V2_0::ProducerUsage;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::common::V1_0::CameraDeviceStatus;
using ::android::hardware::camera::common::V1_0::TorchMode;
@@ -233,7 +233,7 @@ struct PreviewWindowCb : public ICameraDevicePreviewCallback {
Return<Status> setCrop(int32_t left, int32_t top,
int32_t right, int32_t bottom) override;
Return<Status> setUsage(ProducerUsage usage) override;
Return<Status> setUsage(BufferUsage usage) override;
Return<Status> setSwapInterval(int32_t interval) override;
@@ -408,7 +408,7 @@ Return<Status> PreviewWindowCb::setCrop(int32_t left, int32_t top,
return mapToStatus(rc);
}
Return<Status> PreviewWindowCb::setUsage(ProducerUsage usage) {
Return<Status> PreviewWindowCb::setUsage(BufferUsage usage) {
auto rc = native_window_set_usage(mAnw.get(), static_cast<int>(usage));
if (rc == ::android::OK) {
mPreviewUsage = static_cast<int>(usage);

View File

@@ -2,7 +2,6 @@
subdirs = [
"allocator/2.0",
"allocator/2.0/default",
"allocator/2.0/vts/functional",
"bufferqueue/1.0",
"common/1.0",
"composer/2.1",

View File

@@ -3,9 +3,7 @@
filegroup {
name: "android.hardware.graphics.allocator@2.0_hal",
srcs: [
"types.hal",
"IAllocator.hal",
"IAllocatorClient.hal",
],
}
@@ -17,9 +15,7 @@ genrule {
":android.hardware.graphics.allocator@2.0_hal",
],
out: [
"android/hardware/graphics/allocator/2.0/types.cpp",
"android/hardware/graphics/allocator/2.0/AllocatorAll.cpp",
"android/hardware/graphics/allocator/2.0/AllocatorClientAll.cpp",
],
}
@@ -31,18 +27,11 @@ genrule {
":android.hardware.graphics.allocator@2.0_hal",
],
out: [
"android/hardware/graphics/allocator/2.0/types.h",
"android/hardware/graphics/allocator/2.0/hwtypes.h",
"android/hardware/graphics/allocator/2.0/IAllocator.h",
"android/hardware/graphics/allocator/2.0/IHwAllocator.h",
"android/hardware/graphics/allocator/2.0/BnHwAllocator.h",
"android/hardware/graphics/allocator/2.0/BpHwAllocator.h",
"android/hardware/graphics/allocator/2.0/BsAllocator.h",
"android/hardware/graphics/allocator/2.0/IAllocatorClient.h",
"android/hardware/graphics/allocator/2.0/IHwAllocatorClient.h",
"android/hardware/graphics/allocator/2.0/BnHwAllocatorClient.h",
"android/hardware/graphics/allocator/2.0/BpHwAllocatorClient.h",
"android/hardware/graphics/allocator/2.0/BsAllocatorClient.h",
],
}
@@ -59,6 +48,7 @@ cc_library_shared {
"libutils",
"libcutils",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.mapper@2.0",
"android.hidl.base@1.0",
],
export_shared_lib_headers: [
@@ -67,6 +57,7 @@ cc_library_shared {
"libhwbinder",
"libutils",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.mapper@2.0",
"android.hidl.base@1.0",
],
}

View File

@@ -16,38 +16,9 @@
package android.hardware.graphics.allocator@2.0;
import IAllocatorClient;
import android.hardware.graphics.mapper@2.0;
interface IAllocator {
enum Capability : int32_t {
/** reserved */
INVALID = 0,
/**
* IAllocatorClient::testAllocate must always return UNDEFINED unless
* this capability is supported.
*/
TEST_ALLOCATE = 1,
/**
* IAllocatorClient::BufferDescriptorInfo::layerCount must be 1 unless
* this capability is supported.
*/
LAYERED_BUFFERS = 2,
};
/**
* Provides a list of supported capabilities (as described in the
* definition of Capability above). This list must not change after
* initialization.
*
* @return capabilities is a list of supported capabilities.
*/
@entry
@exit
@callflow(next="*")
getCapabilities() generates (vec<Capability> capabilities);
/**
* Retrieves implementation-defined debug information, which will be
* displayed during, for example, `dumpsys SurfaceFlinger`.
@@ -60,15 +31,27 @@ interface IAllocator {
dumpDebugInfo() generates (string debugInfo);
/**
* Creates a client of the allocator. All resources created by the client
* are owned by the client and are only visible to the client, unless they
* are exported by exportHandle.
* Allocates buffers with the properties specified by the descriptor.
*
* @param descriptor specifies the properties of the buffers to allocate.
* @param count is the number of buffers to allocate.
* @return error is NONE upon success. Otherwise,
* NO_RESOURCES when no more client can currently be created.
* @return client is the newly created client.
* BAD_DESCRIPTOR when the descriptor is invalid.
* NO_RESOURCES when the allocation cannot be fulfilled at this
* time.
* UNSUPPORTED when any of the property encoded in the descriptor
* is not supported.
* @return stride is the number of pixels between two consecutive rows of
* the buffers, when the concept of consecutive rows is defined.
* Otherwise, it has no meaning.
* @return buffers is an array of raw handles to the newly allocated
* buffers.
*/
@entry
@exit
@callflow(next="*")
createClient() generates (Error error, IAllocatorClient client);
allocate(BufferDescriptor descriptor, uint32_t count)
generates (Error error,
uint32_t stride,
vec<handle> buffers);
};

View File

@@ -1,165 +0,0 @@
/*
* Copyright (C) 2016 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.
*/
package android.hardware.graphics.allocator@2.0;
import android.hardware.graphics.common@1.0::PixelFormat;
interface IAllocatorClient {
struct BufferDescriptorInfo {
/**
* The width specifies how many columns of pixels must be in the
* allocated buffer, but does not necessarily represent the offset in
* columns between the same column in adjacent rows. The rows may be
* padded.
*/
uint32_t width;
/**
* The height specifies how many rows of pixels must be in the
* allocated buffer.
*/
uint32_t height;
/**
* The number of image layers that must be in the allocated buffer.
*/
uint32_t layerCount;
/** Buffer pixel format. */
PixelFormat format;
/**
* Buffer producer usage mask; valid flags can be found in the
* definition of ProducerUsage.
*/
uint64_t producerUsageMask;
/**
* Buffer consumer usage mask; valid flags can be found in the
* definition of ConsumerUsage.
*/
uint64_t consumerUsageMask;
};
/**
* Creates a new, opaque buffer descriptor.
*
* @param descriptorInfo specifies the attributes of the buffer
* descriptor.
* @return error is NONE upon success. Otherwise,
* BAD_VALUE when any attribute in descriptorInfo is invalid.
* NO_RESOURCES when no more descriptors can currently be created.
* @return descriptor is the newly created buffer descriptor.
*/
@entry
@callflow(next="*")
createDescriptor(BufferDescriptorInfo descriptorInfo)
generates (Error error,
BufferDescriptor descriptor);
/**
* Destroys an existing buffer descriptor.
*
* @param descriptor is the descriptor to destroy.
* @return error is either NONE or BAD_DESCRIPTOR.
*/
@exit
@callflow(next="*")
destroyDescriptor(BufferDescriptor descriptor) generates (Error error);
/**
* Tests whether a buffer allocation can succeed, ignoring potential
* resource contention which might lead to a NO_RESOURCES error.
*
* @param descriptors is a list of buffer descriptors.
* @return error is NONE or NOT_SHARED upon success;
* NONE when buffers can be created and share a backing store.
* NOT_SHARED when buffers can be created but require more than a
* backing store.
* Otherwise,
* BAD_DESCRIPTOR when any of the descriptors is invalid.
* UNSUPPORTED when any of the descriptors can never be satisfied.
* UNDEFINED when TEST_ALLOCATE is not listed in getCapabilities.
*/
@callflow(next="allocate")
testAllocate(vec<BufferDescriptor> descriptors) generates (Error error);
/**
* Attempts to allocate a list of buffers sharing a backing store.
*
* Each buffer must correspond to one of the descriptors passed into the
* function and must hold a reference to its backing store. If the device
* is unable to share the backing store between the buffers, it must
* attempt to allocate the buffers with different backing stores and
* return NOT_SHARED if it is successful.
*
* @param descriptors is the buffer descriptors to attempt to allocate.
* @return error is NONE or NOT_SHARED upon success;
* NONE when buffers can be created and share a backing store.
* NOT_SHARED when buffers can be created but require more than a
* backing store.
* Otherwise,
* BAD_DESCRIPTOR when any of the descriptors is invalid.
* UNSUPPORTED when any of the descriptors can never be satisfied.
* NO_RESOURCES when any of the buffers cannot be created at this
* time.
* @return buffers is the allocated buffers.
*/
@callflow(next="exportHandle")
allocate(vec<BufferDescriptor> descriptors)
generates (Error error,
vec<Buffer> buffers);
/**
* Frees a buffer.
*
* @param buffer is the buffer to be freed.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer is invalid.
*/
@exit
@callflow(next="*")
free(Buffer buffer) generates (Error error);
/**
* Exports a buffer for use in other client libraries or for cross-process
* sharing.
*
* The exported handle is a handle to the backing store of the buffer, not
* to the buffer itself. It however may not hold any reference to the
* backing store and may be considered invalid by client libraries. To use
* it and, in most cases, to save it for later use, a client must make a
* clone of the handle and have the cloned handle hold a reference to the
* backing store. Such a cloned handle will stay valid even after the
* original buffer is freed. Refer to native_handle_clone and IMapper for
* how a handle is cloned and how a reference is added.
*
* @param descriptor is the descriptor used to allocate the buffer.
* @param buffer is the buffer to be exported.
* @return error is NONE upon success. Otherwise,
* BAD_DESCRIPTOR when the descriptor is invalid.
* BAD_BUFFER when the buffer is invalid.
* BAD_VALUE when descriptor and buffer do not match.
* NO_RESOURCES when the buffer cannot be exported at this time.
* @return bufferHandle is the exported handle.
*/
@callflow(next="free")
exportHandle(BufferDescriptor descriptor,
Buffer buffer)
generates (Error error,
handle bufferHandle);
};

View File

@@ -3,7 +3,7 @@ cc_library_shared {
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["Gralloc.cpp"],
srcs: ["Gralloc.cpp", "Gralloc0Allocator.cpp", "Gralloc1Allocator.cpp"],
cppflags: ["-Wall", "-Wextra"],
shared_libs: [
"android.hardware.graphics.allocator@2.0",
@@ -15,6 +15,7 @@ cc_library_shared {
"liblog",
"libutils",
],
static_libs: ["libgrallocmapperincludes"],
}
cc_binary {

View File

@@ -16,17 +16,11 @@
#define LOG_TAG "GrallocPassthrough"
#include <mutex>
#include <type_traits>
#include <unordered_set>
#include <vector>
#include <string.h>
#include <hardware/gralloc1.h>
#include <log/log.h>
#include "Gralloc.h"
#include "Gralloc0Allocator.h"
#include "Gralloc1Allocator.h"
#include <log/log.h>
namespace android {
namespace hardware {
@@ -35,417 +29,6 @@ namespace allocator {
namespace V2_0 {
namespace implementation {
class GrallocHal : public IAllocator {
public:
GrallocHal(const hw_module_t* module);
virtual ~GrallocHal();
// IAllocator interface
Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
Return<void> createClient(createClient_cb hidl_cb) override;
Error createDescriptor(
const IAllocatorClient::BufferDescriptorInfo& descriptorInfo,
BufferDescriptor* outDescriptor);
Error destroyDescriptor(BufferDescriptor descriptor);
Error testAllocate(const hidl_vec<BufferDescriptor>& descriptors);
Error allocate(const hidl_vec<BufferDescriptor>& descriptors,
hidl_vec<Buffer>* outBuffers);
Error free(Buffer buffer);
Error exportHandle(Buffer buffer, const native_handle_t** outHandle);
private:
void initCapabilities();
template<typename T>
void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
void initDispatch();
bool hasCapability(Capability capability) const;
gralloc1_device_t* mDevice;
std::unordered_set<Capability> mCapabilities;
struct {
GRALLOC1_PFN_DUMP dump;
GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor;
GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor;
GRALLOC1_PFN_SET_DIMENSIONS setDimensions;
GRALLOC1_PFN_SET_FORMAT setFormat;
GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount;
GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage;
GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage;
GRALLOC1_PFN_ALLOCATE allocate;
GRALLOC1_PFN_RELEASE release;
} mDispatch;
};
class GrallocClient : public IAllocatorClient {
public:
GrallocClient(GrallocHal& hal);
virtual ~GrallocClient();
// IAllocatorClient interface
Return<void> createDescriptor(const BufferDescriptorInfo& descriptorInfo,
createDescriptor_cb hidl_cb) override;
Return<Error> destroyDescriptor(BufferDescriptor descriptor) override;
Return<Error> testAllocate(
const hidl_vec<BufferDescriptor>& descriptors) override;
Return<void> allocate(const hidl_vec<BufferDescriptor>& descriptors,
allocate_cb hidl_cb) override;
Return<Error> free(Buffer buffer) override;
Return<void> exportHandle(BufferDescriptor descriptor,
Buffer buffer, exportHandle_cb hidl_cb) override;
private:
GrallocHal& mHal;
std::mutex mMutex;
std::unordered_set<BufferDescriptor> mDescriptors;
std::unordered_set<Buffer> mBuffers;
};
GrallocHal::GrallocHal(const hw_module_t* module)
: mDevice(nullptr), mDispatch()
{
int status = gralloc1_open(module, &mDevice);
if (status) {
LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
strerror(-status));
}
initCapabilities();
initDispatch();
}
GrallocHal::~GrallocHal()
{
gralloc1_close(mDevice);
}
void GrallocHal::initCapabilities()
{
uint32_t count = 0;
mDevice->getCapabilities(mDevice, &count, nullptr);
std::vector<Capability> caps(count);
mDevice->getCapabilities(mDevice, &count, reinterpret_cast<
std::underlying_type<Capability>::type*>(caps.data()));
caps.resize(count);
mCapabilities.insert(caps.cbegin(), caps.cend());
}
template<typename T>
void GrallocHal::initDispatch(gralloc1_function_descriptor_t desc, T* outPfn)
{
auto pfn = mDevice->getFunction(mDevice, desc);
if (!pfn) {
LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
}
*outPfn = reinterpret_cast<T>(pfn);
}
void GrallocHal::initDispatch()
{
initDispatch(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump);
initDispatch(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR,
&mDispatch.createDescriptor);
initDispatch(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR,
&mDispatch.destroyDescriptor);
initDispatch(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions);
initDispatch(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat);
if (hasCapability(Capability::LAYERED_BUFFERS)) {
initDispatch(GRALLOC1_FUNCTION_SET_LAYER_COUNT,
&mDispatch.setLayerCount);
}
initDispatch(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE,
&mDispatch.setConsumerUsage);
initDispatch(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE,
&mDispatch.setProducerUsage);
initDispatch(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate);
initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
}
bool GrallocHal::hasCapability(Capability capability) const
{
return (mCapabilities.count(capability) > 0);
}
Return<void> GrallocHal::getCapabilities(getCapabilities_cb hidl_cb)
{
std::vector<Capability> caps(
mCapabilities.cbegin(), mCapabilities.cend());
hidl_vec<Capability> reply;
reply.setToExternal(caps.data(), caps.size());
hidl_cb(reply);
return Void();
}
Return<void> GrallocHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb)
{
uint32_t len = 0;
mDispatch.dump(mDevice, &len, nullptr);
std::vector<char> buf(len + 1);
mDispatch.dump(mDevice, &len, buf.data());
buf.resize(len + 1);
buf[len] = '\0';
hidl_string reply;
reply.setToExternal(buf.data(), len);
hidl_cb(reply);
return Void();
}
Return<void> GrallocHal::createClient(createClient_cb hidl_cb)
{
sp<IAllocatorClient> client = new GrallocClient(*this);
hidl_cb(Error::NONE, client);
return Void();
}
Error GrallocHal::createDescriptor(
const IAllocatorClient::BufferDescriptorInfo& descriptorInfo,
BufferDescriptor* outDescriptor)
{
gralloc1_buffer_descriptor_t descriptor;
int32_t err = mDispatch.createDescriptor(mDevice, &descriptor);
if (err != GRALLOC1_ERROR_NONE) {
return static_cast<Error>(err);
}
err = mDispatch.setDimensions(mDevice, descriptor,
descriptorInfo.width, descriptorInfo.height);
if (err == GRALLOC1_ERROR_NONE) {
err = mDispatch.setFormat(mDevice, descriptor,
static_cast<int32_t>(descriptorInfo.format));
}
if (err == GRALLOC1_ERROR_NONE) {
if (hasCapability(Capability::LAYERED_BUFFERS)) {
err = mDispatch.setLayerCount(mDevice, descriptor,
descriptorInfo.layerCount);
} else if (descriptorInfo.layerCount != 1) {
err = GRALLOC1_ERROR_BAD_VALUE;
}
}
if (err == GRALLOC1_ERROR_NONE) {
uint64_t producerUsageMask = descriptorInfo.producerUsageMask;
if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN) {
producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
}
if (producerUsageMask & GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN) {
producerUsageMask |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
}
err = mDispatch.setProducerUsage(mDevice, descriptor,
descriptorInfo.producerUsageMask);
}
if (err == GRALLOC1_ERROR_NONE) {
uint64_t consumerUsageMask = descriptorInfo.consumerUsageMask;
if (consumerUsageMask & GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN) {
consumerUsageMask |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
}
err = mDispatch.setConsumerUsage(mDevice, descriptor,
consumerUsageMask);
}
if (err == GRALLOC1_ERROR_NONE) {
*outDescriptor = descriptor;
} else {
mDispatch.destroyDescriptor(mDevice, descriptor);
}
return static_cast<Error>(err);
}
Error GrallocHal::destroyDescriptor(BufferDescriptor descriptor)
{
int32_t err = mDispatch.destroyDescriptor(mDevice, descriptor);
return static_cast<Error>(err);
}
Error GrallocHal::testAllocate(const hidl_vec<BufferDescriptor>& descriptors)
{
if (!hasCapability(Capability::TEST_ALLOCATE)) {
return Error::UNDEFINED;
}
int32_t err = mDispatch.allocate(mDevice, descriptors.size(),
descriptors.data(), nullptr);
return static_cast<Error>(err);
}
Error GrallocHal::allocate(const hidl_vec<BufferDescriptor>& descriptors,
hidl_vec<Buffer>* outBuffers)
{
std::vector<buffer_handle_t> buffers(descriptors.size());
int32_t err = mDispatch.allocate(mDevice, descriptors.size(),
descriptors.data(), buffers.data());
if (err == GRALLOC1_ERROR_NONE || err == GRALLOC1_ERROR_NOT_SHARED) {
outBuffers->resize(buffers.size());
for (size_t i = 0; i < outBuffers->size(); i++) {
(*outBuffers)[i] = static_cast<Buffer>(
reinterpret_cast<uintptr_t>(buffers[i]));
}
}
return static_cast<Error>(err);
}
Error GrallocHal::free(Buffer buffer)
{
buffer_handle_t handle = reinterpret_cast<buffer_handle_t>(
static_cast<uintptr_t>(buffer));
int32_t err = mDispatch.release(mDevice, handle);
return static_cast<Error>(err);
}
Error GrallocHal::exportHandle(Buffer buffer,
const native_handle_t** outHandle)
{
// we rely on the caller to validate buffer here
*outHandle = reinterpret_cast<buffer_handle_t>(
static_cast<uintptr_t>(buffer));
return Error::NONE;
}
GrallocClient::GrallocClient(GrallocHal& hal)
: mHal(hal)
{
}
GrallocClient::~GrallocClient()
{
if (!mBuffers.empty()) {
ALOGW("client destroyed with valid buffers");
for (auto buf : mBuffers) {
mHal.free(buf);
}
}
if (!mDescriptors.empty()) {
ALOGW("client destroyed with valid buffer descriptors");
for (auto desc : mDescriptors) {
mHal.destroyDescriptor(desc);
}
}
}
Return<void> GrallocClient::createDescriptor(
const BufferDescriptorInfo& descriptorInfo,
createDescriptor_cb hidl_cb)
{
BufferDescriptor descriptor = 0;
Error err = mHal.createDescriptor(descriptorInfo, &descriptor);
if (err == Error::NONE) {
std::lock_guard<std::mutex> lock(mMutex);
auto result = mDescriptors.insert(descriptor);
if (!result.second) {
ALOGW("duplicated buffer descriptor id returned");
mHal.destroyDescriptor(descriptor);
err = Error::NO_RESOURCES;
}
}
hidl_cb(err, descriptor);
return Void();
}
Return<Error> GrallocClient::destroyDescriptor(BufferDescriptor descriptor)
{
{
std::lock_guard<std::mutex> lock(mMutex);
if (!mDescriptors.erase(descriptor)) {
return Error::BAD_DESCRIPTOR;
}
}
return mHal.destroyDescriptor(descriptor);
}
Return<Error> GrallocClient::testAllocate(
const hidl_vec<BufferDescriptor>& descriptors)
{
return mHal.testAllocate(descriptors);
}
Return<void> GrallocClient::allocate(
const hidl_vec<BufferDescriptor>& descriptors,
allocate_cb hidl_cb) {
hidl_vec<Buffer> buffers;
Error err = mHal.allocate(descriptors, &buffers);
if (err == Error::NONE || err == Error::NOT_SHARED) {
std::lock_guard<std::mutex> lock(mMutex);
for (size_t i = 0; i < buffers.size(); i++) {
auto result = mBuffers.insert(buffers[i]);
if (!result.second) {
ALOGW("duplicated buffer id returned");
for (size_t j = 0; j < buffers.size(); j++) {
if (j < i) {
mBuffers.erase(buffers[i]);
}
mHal.free(buffers[i]);
}
buffers = hidl_vec<Buffer>();
err = Error::NO_RESOURCES;
break;
}
}
}
hidl_cb(err, buffers);
return Void();
}
Return<Error> GrallocClient::free(Buffer buffer)
{
{
std::lock_guard<std::mutex> lock(mMutex);
if (!mBuffers.erase(buffer)) {
return Error::BAD_BUFFER;
}
}
return mHal.free(buffer);
}
Return<void> GrallocClient::exportHandle(BufferDescriptor /*descriptor*/,
Buffer buffer, exportHandle_cb hidl_cb)
{
const native_handle_t* handle = nullptr;
{
std::lock_guard<std::mutex> lock(mMutex);
if (mBuffers.count(buffer) == 0) {
hidl_cb(Error::BAD_BUFFER, handle);
return Void();
}
}
Error err = mHal.exportHandle(buffer, &handle);
hidl_cb(err, handle);
return Void();
}
IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
const hw_module_t* module = nullptr;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
@@ -455,12 +38,15 @@ IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
}
uint8_t major = (module->module_api_version >> 8) & 0xff;
if (major != 1) {
ALOGE("unknown gralloc module major version %d", major);
return nullptr;
switch (major) {
case 1:
return new Gralloc1Allocator(module);
case 0:
return new Gralloc0Allocator(module);
default:
ALOGE("unknown gralloc module major version %d", major);
return nullptr;
}
return new GrallocHal(module);
}
} // namespace implementation

View File

@@ -0,0 +1,144 @@
/*
* Copyright 2016 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_TAG "Gralloc0Allocator"
#include "Gralloc0Allocator.h"
#include "GrallocBufferDescriptor.h"
#include <vector>
#include <string.h>
#include <log/log.h>
namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::mapper::V2_0::implementation::
grallocDecodeBufferDescriptor;
Gralloc0Allocator::Gralloc0Allocator(const hw_module_t* module) {
int result = gralloc_open(module, &mDevice);
if (result) {
LOG_ALWAYS_FATAL("failed to open gralloc0 device: %s",
strerror(-result));
}
}
Gralloc0Allocator::~Gralloc0Allocator() {
gralloc_close(mDevice);
}
Return<void> Gralloc0Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
char buf[4096] = {};
if (mDevice->dump) {
mDevice->dump(mDevice, buf, sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
}
hidl_cb(hidl_string(buf));
return Void();
}
Return<void> Gralloc0Allocator::allocate(const BufferDescriptor& descriptor,
uint32_t count, allocate_cb hidl_cb) {
IMapper::BufferDescriptorInfo descriptorInfo;
if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
hidl_cb(Error::BAD_DESCRIPTOR, 0, hidl_vec<hidl_handle>());
return Void();
}
Error error = Error::NONE;
uint32_t stride = 0;
std::vector<hidl_handle> buffers;
buffers.reserve(count);
// allocate the buffers
for (uint32_t i = 0; i < count; i++) {
buffer_handle_t tmpBuffer;
uint32_t tmpStride;
error = allocateOne(descriptorInfo, &tmpBuffer, &tmpStride);
if (error != Error::NONE) {
break;
}
if (stride == 0) {
stride = tmpStride;
} else if (stride != tmpStride) {
// non-uniform strides
mDevice->free(mDevice, tmpBuffer);
stride = 0;
error = Error::UNSUPPORTED;
break;
}
buffers.emplace_back(hidl_handle(tmpBuffer));
}
// return the buffers
hidl_vec<hidl_handle> hidl_buffers;
if (error == Error::NONE) {
hidl_buffers.setToExternal(buffers.data(), buffers.size());
}
hidl_cb(error, stride, hidl_buffers);
// free the buffers
for (const auto& buffer : buffers) {
mDevice->free(mDevice, buffer.getNativeHandle());
}
return Void();
}
Error Gralloc0Allocator::allocateOne(const IMapper::BufferDescriptorInfo& info,
buffer_handle_t* outBuffer,
uint32_t* outStride) {
if (info.layerCount > 1 || (info.usage >> 32) != 0) {
return Error::BAD_VALUE;
}
buffer_handle_t buffer = nullptr;
int stride = 0;
int result = mDevice->alloc(mDevice, info.width, info.height,
static_cast<int>(info.format), info.usage,
&buffer, &stride);
if (result) {
switch (result) {
case -EINVAL:
return Error::BAD_VALUE;
default:
return Error::NO_RESOURCES;
}
}
*outBuffer = buffer;
*outStride = stride;
return Error::NONE;
}
} // namespace implementation
} // namespace V2_0
} // namespace allocator
} // namespace graphics
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2016 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_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <hardware/gralloc.h>
namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::mapper::V2_0::IMapper;
using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
using android::hardware::graphics::mapper::V2_0::Error;
class Gralloc0Allocator : public IAllocator {
public:
Gralloc0Allocator(const hw_module_t* module);
virtual ~Gralloc0Allocator();
// IAllocator interface
Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
allocate_cb hidl_cb) override;
private:
Error allocateOne(const IMapper::BufferDescriptorInfo& info,
buffer_handle_t* outBuffer, uint32_t* outStride);
alloc_device_t* mDevice;
};
} // namespace implementation
} // namespace V2_0
} // namespace allocator
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H

View File

@@ -0,0 +1,321 @@
/*
* Copyright 2016 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_TAG "Gralloc1Allocator"
#include "Gralloc1Allocator.h"
#include "GrallocBufferDescriptor.h"
#include <vector>
#include <string.h>
#include <log/log.h>
namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::mapper::V2_0::implementation::
grallocDecodeBufferDescriptor;
Gralloc1Allocator::Gralloc1Allocator(const hw_module_t* module)
: mDevice(nullptr), mCapabilities(), mDispatch() {
int result = gralloc1_open(module, &mDevice);
if (result) {
LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
strerror(-result));
}
initCapabilities();
initDispatch();
}
Gralloc1Allocator::~Gralloc1Allocator() {
gralloc1_close(mDevice);
}
void Gralloc1Allocator::initCapabilities() {
uint32_t count = 0;
mDevice->getCapabilities(mDevice, &count, nullptr);
std::vector<int32_t> capabilities(count);
mDevice->getCapabilities(mDevice, &count, capabilities.data());
capabilities.resize(count);
for (auto capability : capabilities) {
if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
mCapabilities.layeredBuffers = true;
break;
}
}
}
template <typename T>
void Gralloc1Allocator::initDispatch(gralloc1_function_descriptor_t desc,
T* outPfn) {
auto pfn = mDevice->getFunction(mDevice, desc);
if (!pfn) {
LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
}
*outPfn = reinterpret_cast<T>(pfn);
}
void Gralloc1Allocator::initDispatch() {
initDispatch(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump);
initDispatch(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR,
&mDispatch.createDescriptor);
initDispatch(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR,
&mDispatch.destroyDescriptor);
initDispatch(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions);
initDispatch(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat);
if (mCapabilities.layeredBuffers) {
initDispatch(GRALLOC1_FUNCTION_SET_LAYER_COUNT,
&mDispatch.setLayerCount);
}
initDispatch(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE,
&mDispatch.setConsumerUsage);
initDispatch(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE,
&mDispatch.setProducerUsage);
initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride);
initDispatch(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate);
initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
}
Return<void> Gralloc1Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
uint32_t len = 0;
mDispatch.dump(mDevice, &len, nullptr);
std::vector<char> buf(len + 1);
mDispatch.dump(mDevice, &len, buf.data());
buf.resize(len + 1);
buf[len] = '\0';
hidl_string reply;
reply.setToExternal(buf.data(), len);
hidl_cb(reply);
return Void();
}
Return<void> Gralloc1Allocator::allocate(const BufferDescriptor& descriptor,
uint32_t count, allocate_cb hidl_cb) {
IMapper::BufferDescriptorInfo descriptorInfo;
if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
hidl_cb(Error::BAD_DESCRIPTOR, 0, hidl_vec<hidl_handle>());
return Void();
}
gralloc1_buffer_descriptor_t desc;
Error error = createDescriptor(descriptorInfo, &desc);
if (error != Error::NONE) {
hidl_cb(error, 0, hidl_vec<hidl_handle>());
return Void();
}
uint32_t stride = 0;
std::vector<hidl_handle> buffers;
buffers.reserve(count);
// allocate the buffers
for (uint32_t i = 0; i < count; i++) {
buffer_handle_t tmpBuffer;
uint32_t tmpStride;
error = allocateOne(desc, &tmpBuffer, &tmpStride);
if (error != Error::NONE) {
break;
}
if (stride == 0) {
stride = tmpStride;
} else if (stride != tmpStride) {
// non-uniform strides
mDispatch.release(mDevice, tmpBuffer);
stride = 0;
error = Error::UNSUPPORTED;
break;
}
buffers.emplace_back(hidl_handle(tmpBuffer));
}
mDispatch.destroyDescriptor(mDevice, desc);
// return the buffers
hidl_vec<hidl_handle> hidl_buffers;
if (error == Error::NONE) {
hidl_buffers.setToExternal(buffers.data(), buffers.size());
}
hidl_cb(error, stride, hidl_buffers);
// free the buffers
for (const auto& buffer : buffers) {
mDispatch.release(mDevice, buffer.getNativeHandle());
}
return Void();
}
Error Gralloc1Allocator::toError(int32_t error) {
switch (error) {
case GRALLOC1_ERROR_NONE:
return Error::NONE;
case GRALLOC1_ERROR_BAD_DESCRIPTOR:
return Error::BAD_DESCRIPTOR;
case GRALLOC1_ERROR_BAD_HANDLE:
return Error::BAD_BUFFER;
case GRALLOC1_ERROR_BAD_VALUE:
return Error::BAD_VALUE;
case GRALLOC1_ERROR_NOT_SHARED:
return Error::NONE; // this is fine
case GRALLOC1_ERROR_NO_RESOURCES:
return Error::NO_RESOURCES;
case GRALLOC1_ERROR_UNDEFINED:
case GRALLOC1_ERROR_UNSUPPORTED:
default:
return Error::UNSUPPORTED;
}
}
uint64_t Gralloc1Allocator::toProducerUsage(uint64_t usage) {
// this is potentially broken as we have no idea which private flags
// should be filtered out
uint64_t producerUsage =
usage &
~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK |
BufferUsage::CPU_WRITE_MASK);
switch (usage & BufferUsage::CPU_WRITE_MASK) {
case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
break;
case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
break;
default:
break;
}
switch (usage & BufferUsage::CPU_READ_MASK) {
case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
break;
case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
break;
default:
break;
}
return producerUsage;
}
uint64_t Gralloc1Allocator::toConsumerUsage(uint64_t usage) {
// this is potentially broken as we have no idea which private flags
// should be filtered out
uint64_t consumerUsage =
usage &
~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK |
BufferUsage::CPU_WRITE_MASK);
switch (usage & BufferUsage::CPU_READ_MASK) {
case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
break;
case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
break;
default:
break;
}
return consumerUsage;
}
Error Gralloc1Allocator::createDescriptor(
const IMapper::BufferDescriptorInfo& info,
gralloc1_buffer_descriptor_t* outDescriptor) {
gralloc1_buffer_descriptor_t descriptor;
int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);
if (error == GRALLOC1_ERROR_NONE) {
error = mDispatch.setDimensions(mDevice, descriptor, info.width,
info.height);
}
if (error == GRALLOC1_ERROR_NONE) {
error = mDispatch.setFormat(mDevice, descriptor,
static_cast<int32_t>(info.format));
}
if (error == GRALLOC1_ERROR_NONE) {
if (mCapabilities.layeredBuffers) {
error =
mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
} else if (info.layerCount > 1) {
error = GRALLOC1_ERROR_UNSUPPORTED;
}
}
if (error == GRALLOC1_ERROR_NONE) {
error = mDispatch.setProducerUsage(mDevice, descriptor,
toProducerUsage(info.usage));
}
if (error == GRALLOC1_ERROR_NONE) {
error = mDispatch.setConsumerUsage(mDevice, descriptor,
toConsumerUsage(info.usage));
}
if (error == GRALLOC1_ERROR_NONE) {
*outDescriptor = descriptor;
} else {
mDispatch.destroyDescriptor(mDevice, descriptor);
}
return toError(error);
}
Error Gralloc1Allocator::allocateOne(gralloc1_buffer_descriptor_t descriptor,
buffer_handle_t* outBuffer,
uint32_t* outStride) {
buffer_handle_t buffer = nullptr;
int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
return toError(error);
}
uint32_t stride = 0;
error = mDispatch.getStride(mDevice, buffer, &stride);
if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
mDispatch.release(mDevice, buffer);
return toError(error);
}
*outBuffer = buffer;
*outStride = stride;
return Error::NONE;
}
} // namespace implementation
} // namespace V2_0
} // namespace allocator
} // namespace graphics
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2016 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_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <hardware/gralloc1.h>
namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::mapper::V2_0::IMapper;
using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
using android::hardware::graphics::mapper::V2_0::Error;
class Gralloc1Allocator : public IAllocator {
public:
Gralloc1Allocator(const hw_module_t* module);
virtual ~Gralloc1Allocator();
// IAllocator interface
Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
allocate_cb hidl_cb) override;
private:
void initCapabilities();
template <typename T>
void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
void initDispatch();
static Error toError(int32_t error);
static uint64_t toProducerUsage(uint64_t usage);
static uint64_t toConsumerUsage(uint64_t usage);
Error createDescriptor(const IMapper::BufferDescriptorInfo& info,
gralloc1_buffer_descriptor_t* outDescriptor);
Error allocateOne(gralloc1_buffer_descriptor_t descriptor,
buffer_handle_t* outBuffer, uint32_t* outStride);
gralloc1_device_t* mDevice;
struct {
bool layeredBuffers;
} mCapabilities;
struct {
GRALLOC1_PFN_DUMP dump;
GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor;
GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor;
GRALLOC1_PFN_SET_DIMENSIONS setDimensions;
GRALLOC1_PFN_SET_FORMAT setFormat;
GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount;
GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage;
GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage;
GRALLOC1_PFN_GET_STRIDE getStride;
GRALLOC1_PFN_ALLOCATE allocate;
GRALLOC1_PFN_RELEASE release;
} mDispatch;
};
} // namespace implementation
} // namespace V2_0
} // namespace allocator
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H

View File

@@ -1,148 +0,0 @@
/*
* Copyright (C) 2016 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.
*/
package android.hardware.graphics.allocator@2.0;
enum Error : int32_t {
NONE = 0, /** no error */
BAD_DESCRIPTOR = 1, /** invalid BufferDescriptor */
BAD_BUFFER = 2, /** invalid Buffer */
BAD_VALUE = 3, /** invalid width, height, etc. */
NOT_SHARED = 4, /** buffers not sharing backing store */
NO_RESOURCES = 5, /** temporary failure due to resource contention */
UNDEFINED = 6, /** an operation has no defined meaning */
UNSUPPORTED = 7, /** permanent failure */
};
enum ProducerUsage : uint64_t {
/** bit 0 is reserved */
/** buffer is read by CPU occasionally */
CPU_READ = 1ULL << 1,
/** buffer is read by CPU frequently */
CPU_READ_OFTEN = 1ULL << 2,
/** bit 3 is reserved */
/** bit 4 is reserved */
/** buffer is written by CPU occasionally */
CPU_WRITE = 1ULL << 5,
/** buffer is written by CPU frequently */
CPU_WRITE_OFTEN = 1ULL << 6,
/** bit 7 is reserved */
/** bit 8 is reserved */
/** buffer is used as a GPU render target */
GPU_RENDER_TARGET = 1ULL << 9,
/** bit 10 is reserved */
/** bit 11 is reserved */
/** bit 12 is reserved */
/** bit 13 is reserved */
/**
* Buffer is allocated with hardware-level protection against copying the
* contents (or information derived from the contents) into unprotected
* memory.
*/
PROTECTED = 1ULL << 14,
/** bit 15 is reserved */
/** bit 16 is reserved */
/** buffer is used as a camera HAL output */
CAMERA = 1ULL << 17,
/** bit 18 is reserved */
/** bit 19 is reserved */
/** bit 20 is reserved */
/** bit 21 is reserved */
/** buffer is used as a video decoder output */
VIDEO_DECODER = 1ULL << 22,
/** buffer is used as a sensor direct report output */
SENSOR_DIRECT_DATA = 1ULL << 23,
/** bits 24-27 are reserved for future versions */
/** bits 28-31 are reserved for vendor extensions */
/** bits 32-47 are reserved for future versions */
/** bits 48-63 are reserved for vendor extensions */
};
enum ConsumerUsage : uint64_t {
/** bit 0 is reserved */
/** buffer is read by CPU occasionally */
CPU_READ = 1ULL << 1,
/** buffer is read by CPU frequently */
CPU_READ_OFTEN = 1ULL << 2,
/** bit 3 is reserved */
/** bit 4 is reserved */
/** bit 5 is reserved */
/** bit 6 is reserved */
/** bit 7 is reserved */
/** buffer is used as a GPU texture */
GPU_TEXTURE = 1ULL << 8,
/** bit 9 is reserved */
/** bit 10 is reserved */
/** buffer is used by hwcomposer HAL */
HWCOMPOSER = 1ULL << 11,
/** buffer is a hwcomposer HAL client target */
CLIENT_TARGET = 1ULL << 12,
/** bit 13 is reserved */
/** bit 14 is reserved */
/** buffer is used as a hwcomposer HAL cursor */
CURSOR = 1ULL << 15,
/** buffer is used as a video encoder input */
VIDEO_ENCODER = 1ULL << 16,
/** bit 17 is reserved */
/** buffer is used as a camera HAL input */
CAMERA = 1ULL << 18,
/** bit 19 is reserved */
/** buffer is used as a renderscript allocation */
RENDERSCRIPT = 1ULL << 20,
/** bit 21 is reserved */
/** bit 22 is reserved */
/**
* buffer is used as as an OpenGL shader storage or uniform
buffer object */
GPU_DATA_BUFFER = 1ULL << 23,
/** bits 24-27 are reserved for future versions */
/** bits 28-31 are reserved for vendor extensions */
/** bits 32-47 are reserved for future versions */
/** bits 48-63 are reserved for vendor extensions */
};
typedef uint64_t BufferDescriptor;
typedef uint64_t Buffer;

View File

@@ -1,62 +0,0 @@
//
// Copyright (C) 2016 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.
//
cc_library_static {
name: "libVtsHalGraphicsAllocatorTestUtils",
defaults: ["hidl_defaults"],
srcs: ["VtsHalGraphicsAllocatorTestUtils.cpp"],
shared_libs: [
"android.hardware.graphics.allocator@2.0",
],
static_libs: [
"VtsHalHidlTargetTestBase",
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
"-O0",
"-g",
],
export_include_dirs: ["."],
}
cc_test {
name: "VtsHalGraphicsAllocatorV2_0TargetTest",
defaults: ["hidl_defaults"],
srcs: ["VtsHalGraphicsAllocatorV2_0TargetTest.cpp"],
shared_libs: [
"libbase",
"liblog",
"libcutils",
"libhidlbase",
"libhidltransport",
"libnativehelper",
"libutils",
"android.hardware.graphics.allocator@2.0",
],
static_libs: [
"libVtsHalGraphicsAllocatorTestUtils",
"VtsHalHidlTargetTestBase",
],
cflags: [
"-Wall",
"-Wextra",
"-Werror",
"-O0",
"-g",
]
}

View File

@@ -1,183 +0,0 @@
/*
* Copyright (C) 2017 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 <VtsHalHidlTargetTestBase.h>
#include "VtsHalGraphicsAllocatorTestUtils.h"
namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace tests {
Allocator::Allocator() { init(); }
void Allocator::init() {
mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>();
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
std::vector<IAllocator::Capability> capabilities = getCapabilities();
mCapabilities.insert(capabilities.begin(), capabilities.end());
}
sp<IAllocator> Allocator::getRaw() const { return mAllocator; }
bool Allocator::hasCapability(IAllocator::Capability capability) const {
return mCapabilities.count(capability) > 0;
}
std::vector<IAllocator::Capability> Allocator::getCapabilities() {
std::vector<IAllocator::Capability> capabilities;
mAllocator->getCapabilities(
[&](const auto& tmpCapabilities) { capabilities = tmpCapabilities; });
return capabilities;
}
std::string Allocator::dumpDebugInfo() {
std::string debugInfo;
mAllocator->dumpDebugInfo(
[&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
return debugInfo;
}
std::unique_ptr<AllocatorClient> Allocator::createClient() {
std::unique_ptr<AllocatorClient> client;
mAllocator->createClient([&](const auto& tmpError, const auto& tmpClient) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
client = std::make_unique<AllocatorClient>(tmpClient);
});
return client;
}
AllocatorClient::AllocatorClient(const sp<IAllocatorClient>& client)
: mClient(client) {}
AllocatorClient::~AllocatorClient() {
for (auto buffer : mBuffers) {
EXPECT_EQ(Error::NONE, mClient->free(buffer))
<< "failed to free buffer " << buffer;
}
mBuffers.clear();
for (auto descriptor : mDescriptors) {
EXPECT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor))
<< "failed to destroy descriptor " << descriptor;
}
mDescriptors.clear();
}
sp<IAllocatorClient> AllocatorClient::getRaw() const { return mClient; }
BufferDescriptor AllocatorClient::createDescriptor(
const IAllocatorClient::BufferDescriptorInfo& info) {
BufferDescriptor descriptor = 0;
mClient->createDescriptor(
info, [&](const auto& tmpError, const auto& tmpDescriptor) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
descriptor = tmpDescriptor;
EXPECT_TRUE(mDescriptors.insert(descriptor).second)
<< "duplicated descriptor id " << descriptor;
});
return descriptor;
}
void AllocatorClient::destroyDescriptor(BufferDescriptor descriptor) {
ASSERT_EQ(Error::NONE, mClient->destroyDescriptor(descriptor))
<< "failed to destroy descriptor " << descriptor;
mDescriptors.erase(descriptor);
}
Error AllocatorClient::testAllocate(
const std::vector<BufferDescriptor>& descriptors) {
return mClient->testAllocate(descriptors);
}
bool AllocatorClient::testAllocate(BufferDescriptor descriptor) {
std::vector<BufferDescriptor> descriptors(1, descriptor);
Error error = testAllocate(descriptors);
return (error == Error::NONE || error == Error::NOT_SHARED);
}
Error AllocatorClient::allocate(
const std::vector<BufferDescriptor>& descriptors,
std::vector<Buffer>& buffers) {
Error error = Error::NO_RESOURCES;
mClient->allocate(descriptors, [&](const auto& tmpError,
const auto& tmpBuffers) {
ASSERT_TRUE(tmpError == Error::NONE || tmpError == Error::NOT_SHARED)
<< "failed to allocate buffer";
ASSERT_EQ(descriptors.size(), tmpBuffers.size()) << "invalid buffer count";
error = tmpError;
buffers = tmpBuffers;
for (auto buffer : buffers) {
EXPECT_TRUE(mBuffers.insert(buffer).second)
<< "duplicated buffer id " << buffer;
}
});
return error;
}
Buffer AllocatorClient::allocate(BufferDescriptor descriptor) {
std::vector<BufferDescriptor> descriptors(1, descriptor);
std::vector<Buffer> buffers;
allocate(descriptors, buffers);
if (::testing::Test::HasFatalFailure()) {
return 0;
}
return buffers[0];
}
void AllocatorClient::free(Buffer buffer) {
ASSERT_EQ(Error::NONE, mClient->free(buffer))
<< "failed to free buffer " << buffer;
mBuffers.erase(buffer);
}
native_handle_t* AllocatorClient::exportHandle(BufferDescriptor descriptor,
Buffer buffer) {
native_handle_t* handle;
mClient->exportHandle(
descriptor, buffer, [&](const auto& tmpError, const auto& tmpHandle) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to export buffer handle";
ASSERT_NE(nullptr, tmpHandle.getNativeHandle())
<< "invalid buffer handle";
handle = native_handle_clone(tmpHandle.getNativeHandle());
ASSERT_NE(nullptr, handle) << "failed to clone handle";
});
return handle;
}
} // namespace tests
} // namespace V2_0
} // namespace allocator
} // namespace graphics
} // namespace hardware
} // namespace android

View File

@@ -1,98 +0,0 @@
/*
* Copyright (C) 2017 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 VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
#define VTS_HAL_GRAPHICS_ALLOCATOR_UTILS
#include <memory>
#include <string>
#include <unordered_set>
#include <vector>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <utils/StrongPointer.h>
namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace tests {
class AllocatorClient;
// A wrapper to IAllocator.
class Allocator {
public:
Allocator();
sp<IAllocator> getRaw() const;
// Returns true when the allocator supports the specified capability.
bool hasCapability(IAllocator::Capability capability) const;
std::vector<IAllocator::Capability> getCapabilities();
std::string dumpDebugInfo();
std::unique_ptr<AllocatorClient> createClient();
private:
void init();
sp<IAllocator> mAllocator;
std::unordered_set<IAllocator::Capability> mCapabilities;
};
// A wrapper to IAllocatorClient.
class AllocatorClient {
public:
AllocatorClient(const sp<IAllocatorClient>& client);
~AllocatorClient();
sp<IAllocatorClient> getRaw() const;
BufferDescriptor createDescriptor(
const IAllocatorClient::BufferDescriptorInfo& info);
void destroyDescriptor(BufferDescriptor descriptor);
Error testAllocate(const std::vector<BufferDescriptor>& descriptors);
bool testAllocate(BufferDescriptor descriptor);
Error allocate(const std::vector<BufferDescriptor>& descriptors,
std::vector<Buffer>& buffers);
Buffer allocate(BufferDescriptor descriptor);
void free(Buffer buffer);
// Returns a handle to the buffer. The ownership of the handle is
// transferred to the caller.
native_handle_t* exportHandle(BufferDescriptor descriptor, Buffer buffer);
private:
sp<IAllocatorClient> mClient;
// Keep track of all descriptors and buffers. When a test fails with
// ASSERT_*, the destructor will clean up the resources for the test.
std::unordered_set<BufferDescriptor> mDescriptors;
std::unordered_set<Buffer> mBuffers;
};
} // namespace tests
} // namespace V2_0
} // namespace allocator
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // VTS_HAL_GRAPHICS_ALLOCATOR_UTILS

View File

@@ -1,186 +0,0 @@
/*
* Copyright (C) 2016 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_TAG "graphics_allocator_hidl_hal_test"
#include <android-base/logging.h>
#include <VtsHalHidlTargetTestBase.h>
#include "VtsHalGraphicsAllocatorTestUtils.h"
namespace android {
namespace hardware {
namespace graphics {
namespace allocator {
namespace V2_0 {
namespace tests {
namespace {
using android::hardware::graphics::common::V1_0::PixelFormat;
#define CHECK_FEATURE_OR_SKIP(FEATURE_NAME) \
do { \
if (!mAllocator->hasCapability(FEATURE_NAME)) { \
std::cout << "[ SKIPPED ] Feature " << #FEATURE_NAME \
<< " not supported" << std::endl; \
return; \
} \
} while (0)
class GraphicsAllocatorHidlTest : public ::testing::VtsHalHidlTargetTestBase {
protected:
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
ASSERT_NO_FATAL_FAILURE(mClient = mAllocator->createClient());
mDummyDescriptorInfo.width = 64;
mDummyDescriptorInfo.height = 64;
mDummyDescriptorInfo.layerCount = 1;
mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
mDummyDescriptorInfo.producerUsageMask =
static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
mDummyDescriptorInfo.consumerUsageMask =
static_cast<uint64_t>(ConsumerUsage::CPU_READ);
}
void TearDown() override {}
std::unique_ptr<Allocator> mAllocator;
std::unique_ptr<AllocatorClient> mClient;
IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
};
TEST_F(GraphicsAllocatorHidlTest, GetCapabilities) {
auto capabilities = mAllocator->getCapabilities();
for (auto cap : capabilities) {
EXPECT_NE(IAllocator::Capability::INVALID, cap);
}
}
TEST_F(GraphicsAllocatorHidlTest, DumpDebugInfo) {
mAllocator->dumpDebugInfo();
}
TEST_F(GraphicsAllocatorHidlTest, CreateDestroyDescriptor) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor =
mClient->createDescriptor(mDummyDescriptorInfo));
mClient->destroyDescriptor(descriptor);
}
/**
* Test testAllocate with a single buffer descriptor.
*/
TEST_F(GraphicsAllocatorHidlTest, TestAllocateBasic) {
CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor =
mClient->createDescriptor(mDummyDescriptorInfo));
ASSERT_TRUE(mClient->testAllocate(descriptor));
}
/**
* Test testAllocate with two buffer descriptors.
*/
TEST_F(GraphicsAllocatorHidlTest, TestAllocateArray) {
CHECK_FEATURE_OR_SKIP(IAllocator::Capability::TEST_ALLOCATE);
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor =
mClient->createDescriptor(mDummyDescriptorInfo));
hidl_vec<BufferDescriptor> descriptors;
descriptors.resize(2);
descriptors[0] = descriptor;
descriptors[1] = descriptor;
auto error = mClient->testAllocate(descriptors);
ASSERT_TRUE(error == Error::NONE || error == Error::NOT_SHARED);
}
/**
* Test allocate/free with a single buffer descriptor.
*/
TEST_F(GraphicsAllocatorHidlTest, AllocateFreeBasic) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor =
mClient->createDescriptor(mDummyDescriptorInfo));
Buffer buffer;
ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor));
mClient->free(buffer);
}
/**
* Test allocate/free with an array of buffer descriptors.
*/
TEST_F(GraphicsAllocatorHidlTest, AllocateFreeArray) {
BufferDescriptor descriptor1;
ASSERT_NO_FATAL_FAILURE(descriptor1 =
mClient->createDescriptor(mDummyDescriptorInfo));
BufferDescriptor descriptor2;
ASSERT_NO_FATAL_FAILURE(descriptor2 =
mClient->createDescriptor(mDummyDescriptorInfo));
hidl_vec<BufferDescriptor> descriptors;
descriptors.resize(3);
descriptors[0] = descriptor1;
descriptors[1] = descriptor1;
descriptors[2] = descriptor2;
std::vector<Buffer> buffers;
ASSERT_NO_FATAL_FAILURE(mClient->allocate(descriptors, buffers));
for (auto buf : buffers) {
mClient->free(buf);
}
}
TEST_F(GraphicsAllocatorHidlTest, ExportHandle) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(descriptor =
mClient->createDescriptor(mDummyDescriptorInfo));
Buffer buffer;
ASSERT_NO_FATAL_FAILURE(buffer = mClient->allocate(descriptor));
native_handle_t* handle;
ASSERT_NO_FATAL_FAILURE(handle = mClient->exportHandle(descriptor, buffer));
native_handle_close(handle);
native_handle_delete(handle);
}
} // namespace anonymous
} // namespace tests
} // namespace V2_0
} // namespace allocator
} // namespace graphics
} // namespace hardware
} // namespace android
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
int status = RUN_ALL_TESTS();
LOG(INFO) << "Test result = " << status;
return status;
}

View File

@@ -12,6 +12,25 @@ intermediates := $(call local-generated-sources-dir, COMMON)
HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
#
# Build types.hal (BufferUsage)
#
GEN := $(intermediates)/android/hardware/graphics/common/V1_0/BufferUsage.java
$(GEN): $(HIDL)
$(GEN): PRIVATE_HIDL := $(HIDL)
$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
$(GEN): PRIVATE_CUSTOM_TOOL = \
$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-Ljava \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
android.hardware.graphics.common@1.0::types.BufferUsage
$(GEN): $(LOCAL_PATH)/types.hal
$(transform-generated-source)
LOCAL_GENERATED_SOURCES += $(GEN)
#
# Build types.hal (ColorMode)
#
@@ -138,6 +157,25 @@ intermediates := $(call local-generated-sources-dir, COMMON)
HIDL := $(HOST_OUT_EXECUTABLES)/hidl-gen$(HOST_EXECUTABLE_SUFFIX)
#
# Build types.hal (BufferUsage)
#
GEN := $(intermediates)/android/hardware/graphics/common/V1_0/BufferUsage.java
$(GEN): $(HIDL)
$(GEN): PRIVATE_HIDL := $(HIDL)
$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
$(GEN): PRIVATE_CUSTOM_TOOL = \
$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-Ljava \
-randroid.hardware:hardware/interfaces \
-randroid.hidl:system/libhidl/transport \
android.hardware.graphics.common@1.0::types.BufferUsage
$(GEN): $(LOCAL_PATH)/types.hal
$(transform-generated-source)
LOCAL_GENERATED_SOURCES += $(GEN)
#
# Build types.hal (ColorMode)
#

View File

@@ -449,6 +449,90 @@ enum PixelFormat : int32_t {
JPEG = 0x100,
};
/**
* Buffer usage definitions.
*/
enum BufferUsage : uint64_t {
/** bit 0-3 is an enum */
CPU_READ_MASK = 0xfULL,
/** buffer is never read by CPU */
CPU_READ_NEVER = 0,
/** buffer is rarely read by CPU */
CPU_READ_RARELY = 2,
/** buffer is often read by CPU */
CPU_READ_OFTEN = 3,
/** bit 4-7 is an enum */
CPU_WRITE_MASK = 0xfULL << 4,
/** buffer is never written by CPU */
CPU_WRITE_NEVER = 0 << 4,
/** buffer is rarely written by CPU */
CPU_WRITE_RARELY = 2 << 4,
/** buffer is often written by CPU */
CPU_WRITE_OFTEN = 3 << 4,
/** buffer is used as a GPU texture */
GPU_TEXTURE = 1ULL << 8,
/** buffer is used as a GPU render target */
GPU_RENDER_TARGET = 1ULL << 9,
/** bit 10 must be zero */
/** buffer is used as a composer HAL overlay layer */
COMPOSER_OVERLAY = 1ULL << 11,
/** buffer is used as a composer HAL client target */
COMPOSER_CLIENT_TARGET = 1ULL << 12,
/** bit 13 must be zero */
/**
* Buffer is allocated with hardware-level protection against copying the
* contents (or information derived from the contents) into unprotected
* memory.
*/
PROTECTED = 1ULL << 14,
/** buffer is used as a hwcomposer HAL cursor layer */
COMPOSER_CURSOR = 1ULL << 15,
/** buffer is used as a video encoder input */
VIDEO_ENCODER = 1ULL << 16,
/** buffer is used as a camera HAL output */
CAMERA_OUTPUT = 1ULL << 17,
/** buffer is used as a camera HAL input */
CAMERA_INPUT = 1ULL << 18,
/** bit 19 must be zero */
/** buffer is used as a renderscript allocation */
RENDERSCRIPT = 1ULL << 20,
/** bit 21 must be zero */
/** buffer is used as a video decoder output */
VIDEO_DECODER = 1ULL << 22,
/** buffer is used as a sensor direct report output */
SENSOR_DIRECT_DATA = 1ULL << 23,
/**
* buffer is used as as an OpenGL shader storage or uniform
* buffer object
*/
GPU_DATA_BUFFER = 1ULL << 24,
/** bits 25-27 must be zero and are reserved for future versions */
/** bits 28-31 are reserved for vendor extensions */
VENDOR_MASK = 0xfULL << 28,
/** bits 32-47 must be zero and are reserved for future versions */
/** bits 48-63 are reserved for vendor extensions */
VENDOR_MASK_HI = 0xffffULL << 48,
};
/**
* Transformation definitions
*

View File

@@ -52,7 +52,6 @@ cc_test {
],
static_libs: [
"libhwcomposer-command-buffer",
"libVtsHalGraphicsAllocatorTestUtils",
"libVtsHalGraphicsComposerTestUtils",
"libVtsHalGraphicsMapperTestUtils",
"VtsHalHidlTargetTestBase",

View File

@@ -18,7 +18,6 @@
#include <IComposerCommandBuffer.h>
#include <android-base/logging.h>
#include "VtsHalGraphicsAllocatorTestUtils.h"
#include "VtsHalGraphicsComposerTestUtils.h"
#include "VtsHalGraphicsMapperTestUtils.h"
@@ -40,22 +39,15 @@ namespace V2_1 {
namespace tests {
namespace {
using android::hardware::graphics::allocator::V2_0::Buffer;
using android::hardware::graphics::allocator::V2_0::BufferDescriptor;
using android::hardware::graphics::allocator::V2_0::ConsumerUsage;
using android::hardware::graphics::allocator::V2_0::IAllocator;
using android::hardware::graphics::allocator::V2_0::IAllocatorClient;
using android::hardware::graphics::allocator::V2_0::ProducerUsage;
using android::hardware::graphics::allocator::V2_0::tests::Allocator;
using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient;
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::ColorMode;
using android::hardware::graphics::common::V1_0::ColorTransform;
using android::hardware::graphics::common::V1_0::Dataspace;
using android::hardware::graphics::common::V1_0::PixelFormat;
using android::hardware::graphics::common::V1_0::Transform;
using android::hardware::graphics::mapper::V2_0::IMapper;
using android::hardware::graphics::mapper::V2_0::tests::Mapper;
using GrallocError = android::hardware::graphics::allocator::V2_0::Error;
using android::hardware::graphics::mapper::V2_0::tests::Gralloc;
using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
// IComposerCallback to be installed with IComposerClient::registerCallback.
class GraphicsComposerCallback : public IComposerCallback {
@@ -409,9 +401,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient());
ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>());
ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
mWriter = std::make_unique<CommandWriterBase>(1024);
mReader = std::make_unique<CommandReader>();
@@ -422,15 +412,15 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
}
const native_handle_t* allocate() {
IAllocatorClient::BufferDescriptorInfo info{};
info.width = 64;
info.height = 64;
info.layerCount = 1;
info.format = PixelFormat::RGBA_8888;
info.producerUsageMask = static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
info.consumerUsageMask = static_cast<uint64_t>(ConsumerUsage::CPU_READ);
IMapper::BufferDescriptorInfo info{};
info.width = 64;
info.height = 64;
info.layerCount = 1;
info.format = PixelFormat::RGBA_8888;
info.usage = static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::CPU_READ_OFTEN);
return mMapper->allocate(mAllocatorClient, info);
return mGralloc->allocate(info);
}
void execute() {
@@ -507,9 +497,7 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
std::unique_ptr<CommandReader> mReader;
private:
std::unique_ptr<Allocator> mAllocator;
std::unique_ptr<AllocatorClient> mAllocatorClient;
std::unique_ptr<Mapper> mMapper;
std::unique_ptr<Gralloc> mGralloc;
};
/**

View File

@@ -51,7 +51,6 @@ cc_library_shared {
"liblog",
"libutils",
"libcutils",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],
@@ -60,7 +59,6 @@ cc_library_shared {
"libhidltransport",
"libhwbinder",
"libutils",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.common@1.0",
"android.hidl.base@1.0",
],

View File

@@ -16,10 +16,39 @@
package android.hardware.graphics.mapper@2.0;
import android.hardware.graphics.common@1.0::PixelFormat;
import android.hardware.graphics.allocator@2.0;
import android.hardware.graphics.common@1.0;
interface IMapper {
struct BufferDescriptorInfo {
/**
* The width specifies how many columns of pixels must be in the
* allocated buffer, but does not necessarily represent the offset in
* columns between the same column in adjacent rows. The rows may be
* padded.
*/
uint32_t width;
/**
* The height specifies how many rows of pixels must be in the
* allocated buffer.
*/
uint32_t height;
/**
* The number of image layers that must be in the allocated buffer.
*/
uint32_t layerCount;
/** Buffer pixel format. */
PixelFormat format;
/**
* Buffer usage mask; valid flags can be found in the definition of
* BufferUsage.
*/
bitfield<BufferUsage> usage;
};
struct Rect {
int32_t left;
int32_t top;
@@ -28,170 +57,76 @@ interface IMapper {
};
/**
* Adds a reference to the given buffer handle.
* Creates a buffer descriptor. The descriptor can be used with IAllocator
* to allocate buffers.
*
* A buffer handle received from a remote process or exported by
* IAllocator::exportHandle is unknown to the mapper. There is also no
* guarantee that the buffer's backing store will stay alive. This
* function must be called at least once in both cases to intrdouce the
* buffer handle to the mapper and to secure the backing store. It may
* also be called more than once to increase the reference count if two
* components in the same process want to interact with the buffer
* independently.
* Since the buffer descriptor fully describes a buffer, any device
* dependent or device independent checks must be performed here whenever
* possible. Specifically, when layered buffers are not supported, this
* function must return UNSUPPORTED if layerCount is great than 1.
*
* @param bufferHandle is the buffer to which a reference must be added.
* @param descriptorInfo specifies the attributes of the descriptor.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid
* NO_RESOURCES when it is not possible to add a
* reference to this buffer at this time
* BAD_VALUE when any of the specified attributes is
* invalid or conflicting.
* NO_RESOURCES when the creation cannot be fullfilled at
* this time.
* UNSUPPORTED when any of the specified attributes is
* not supported.
* @return descriptor is the newly created buffer descriptor.
*/
@entry
@callflow(next="*")
retain(handle bufferHandle) generates (Error error);
createDescriptor(BufferDescriptorInfo descriptorInfo)
generates (Error error,
BufferDescriptor descriptor);
/**
* Removes a reference from the given buffer buffer.
* Imports a raw buffer handle to create an imported buffer handle for use
* with the rest of the mapper or with other in-process libraries.
*
* If no references remain, the buffer handle must be freed with
* native_handle_close/native_handle_delete by the mapper. When the last
* buffer handle referring to a particular backing store is freed, that
* backing store must also be freed.
* A buffer handle is considered raw when it is cloned or when it is
* received from another HAL or another process. A raw buffer handle must
* not be used to access the underlying graphics buffer. It must be
* imported to create an imported handle first.
*
* @param bufferHandle is the buffer from which a reference must be
* removed.
* This function must at least validate the raw handle before creating the
* imported handle. It must also support importing the same raw handle
* multiple times to create multiple imported handles. The imported handle
* must be considered valid everywhere in the process, including in
* another instance of the mapper.
*
* @param rawHandle is the raw buffer handle to import.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* BAD_BUFFER when the raw handle is invalid.
* NO_RESOURCES when the raw handle cannot be imported at
* this time.
* @return buffer is the imported buffer handle and has the type
* buffer_handle_t.
*/
@entry
@callflow(next="*")
importBuffer(handle rawHandle) generates (Error error, pointer buffer);
/**
* Frees a buffer handle. Buffer handles returned by importBuffer must be
* freed with this function when no longer needed.
*
* This function must free up all resources allocated by importBuffer for
* the imported handle. For example, if the imported handle was created
* with native_handle_create, this function must call native_handle_close
* and native_handle_delete.
*
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer is invalid.
*/
@exit
release(handle bufferHandle) generates (Error error);
/**
* Gets the width and height of the buffer in pixels.
*
* See IAllocator::BufferDescriptorInfo for more information.
*
* @param bufferHandle is the buffer from which to get the dimensions.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* @return width is the width of the buffer in pixels.
* @return height is the height of the buffer in pixels.
*/
@callflow(next="*")
getDimensions(handle bufferHandle)
generates (Error error,
uint32_t width,
uint32_t height);
/**
* Gets the format of the buffer.
*
* See IAllocator::BufferDescriptorInfo for more information.
*
* @param bufferHandle is the buffer from which to get format.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* @return format is the format of the buffer.
*/
@callflow(next="*")
getFormat(handle bufferHandle)
generates (Error error,
PixelFormat format);
/**
* Gets the number of layers of the buffer.
*
* See IAllocator::BufferDescriptorInfo for more information.
*
* @param bufferHandle is the buffer from which to get format.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* @return layerCount is the number of layers of the buffer.
*/
@callflow(next="*")
getLayerCount(handle bufferHandle)
generates (Error error,
uint32_t layerCount);
/**
* Gets the producer usage flags which were used to allocate this buffer.
*
* See IAllocator::BufferDescriptorInfo for more information.
*
* @param bufferHandle is the buffer from which to get the producer usage
* flags.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* @return usageMask contains the producer usage flags of the buffer.
*/
@callflow(next="*")
getProducerUsageMask(handle bufferHandle)
generates (Error error,
uint64_t usageMask);
/**
* Gets the consumer usage flags which were used to allocate this buffer.
*
* See IAllocator::BufferDescriptorInfo for more information.
*
* @param bufferHandle is the buffer from which to get the consumer usage
* flags.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* @return usageMask contains the consumer usage flags of the buffer.
*/
@callflow(next="*")
getConsumerUsageMask(handle bufferHandle)
generates (Error error,
uint64_t usageMask);
/**
* Gets a value that uniquely identifies the backing store of the given
* buffer.
*
* Buffers which share a backing store should return the same value from
* this function. If the buffer is present in more than one process, the
* backing store value for that buffer is not required to be the same in
* every process.
*
* @param device is the mapper device.
* @param bufferHandle is the buffer from which to get the backing store
* identifier.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* @return store is the backing store identifier for this buffer.
*/
@callflow(next="*")
getBackingStore(handle bufferHandle)
generates (Error error,
BackingStore store);
/**
* Gets the stride of the buffer in pixels.
*
* The stride is the offset in pixel-sized elements between the same
* column in two adjacent rows of pixels. This may not be equal to the
* width of the buffer.
*
* @param device is the mapper device.
* @param bufferHandle is the buffer from which to get the stride.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* UNDEFINED when the notion of a stride is not
* meaningful for the buffer format.
* @return store is the stride in pixels.
*/
@callflow(next="*")
getStride(handle bufferHandle)
generates (Error error,
uint32_t stride);
freeBuffer(pointer buffer) generates (Error error);
/**
* Locks the given buffer for the specified CPU usage.
*
* Exactly one of producerUsageMask and consumerUsageMask must be 0. The
* usage which is not 0 must be one of the *Usage::CPU* values, as
* applicable. Locking a buffer for a non-CPU usage is not supported.
*
* Locking the same buffer simultaneously from multiple threads is
* permitted, but if any of the threads attempt to lock the buffer for
* writing, the behavior is undefined, except that it must not cause
@@ -209,39 +144,27 @@ interface IMapper {
* address will represent the top-left corner of the entire buffer, even
* if accessRegion does not begin at the top-left corner.
*
* acquireFence is a file descriptor referring to a acquire sync fence
* object, which will be signaled when it is safe for the device to access
* the contents of the buffer (prior to locking). If it is already safe to
* access the buffer contents, -1 may be passed instead.
*
* @param bufferHandle is the buffer to lock.
* @param producerUsageMask contains the producer usage flags to request;
* either this or consumerUsagemask must be 0, and the other must
* be a CPU usage.
* @param consumerUsageMask contains the consumer usage flags to request;
* either this or producerUsageMask must be 0, and the other must
* be a CPU usage.
* @param buffer is the buffer to lock.
* @param cpuUsage specifies one or more CPU usage flags to request.
* @param accessRegion is the portion of the buffer that the client
* intends to access.
* @param acquireFence is a sync fence file descriptor as described above.
* @param acquireFence, when non-empty, is a handle containing a file
* descriptor referring to a sync fence object, which will be
* signaled when it is safe for the mapper to lock the buffer. If
* it is already safe to lock, acquireFence is empty.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* BAD_VALUE when neither or both of producerUsageMask
* and consumerUsageMask were 0, or the usage
* which was not 0 was not a CPU usage.
* BAD_BUFFER when the buffer is invalid or is
* incompatible with this function.
* BAD_VALUE when cpuUsage is 0, contains non-CPU usage
* flags, or is incompatible with the buffer.
* NO_RESOURCES when the buffer cannot be locked at this
* time, but locking may succeed at a future
* time.
* UNSUPPORTED when the buffer cannot be locked with the
* given usage, and any future attempts at
* locking will also fail.
* @return data will be filled with a CPU-accessible pointer to the buffer
* data.
* @return data is a CPU-accessible pointer to the buffer data.
*/
@callflow(next="unlock")
lock(handle bufferHandle,
uint64_t producerUsageMask,
uint64_t consumerUsageMask,
lock(pointer buffer,
bitfield<BufferUsage> cpuUsage,
Rect accessRegion,
handle acquireFence)
generates (Error error,
@@ -249,7 +172,7 @@ interface IMapper {
/**
* This is largely the same as lock(), except that instead of returning a
* pointer directly to the buffer data, it returns an FlexLayout struct
* pointer directly to the buffer data, it returns an YCbCrLayout struct
* describing how to access the data planes.
*
* This function must work on buffers with PixelFormat::YCbCr_*_888 if
@@ -257,67 +180,46 @@ interface IMapper {
* multimedia codecs when they are configured with a
* flexible-YUV-compatible color format.
*
* This function may also be called on buffers of other formats, including
* non-YUV formats, but if the buffer format is not compatible with a
* flexible representation, it may return UNSUPPORTED.
*
* @param device is the mapper device.
* @param bufferHandle is the buffer to lock.
* @param producerUsageMask contains the producer usage flags to request;
* either this or consumerUsagemask must be 0, and the other must
* be a CPU usage.
* @param consumerUsageMask contains the consumer usage flags to request;
* either this or producerUsageMask must be 0, and the other must
* be a CPU usage.
* @param buffer is the buffer to lock.
* @param cpuUsage specifies one or more CPU usage flags to request.
* @param accessRegion is the portion of the buffer that the client
* intends to access.
* @param acquireFence is a sync fence file descriptor as described in
* lock().
* @param acquireFence, when non-empty, is a handle containing a file
* descriptor referring to a sync fence object, which will be
* signaled when it is safe for the mapper to lock the buffer. If
* it is already safe to lock, acquireFence is empty.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* BAD_VALUE when neither or both of producerUsageMask
* and consumerUsageMask were 0, or the usage
* which was not 0 was not a CPU usage.
* BAD_BUFFER when the buffer is invalid or is
* incompatible with this function.
* BAD_VALUE when cpuUsage is 0, contains non-CPU usage
* flags, or is incompatible with the buffer.
* NO_RESOURCES when the buffer cannot be locked at this
* time, but locking may succeed at a future
* time.
* UNSUPPORTED when the buffer cannot be locked with the
* given usage, and any future attempts at
* locking will also fail.
* @return flexLayout will be filled with the description of the planes in
* the buffer.
* @return layout is the data layout of the buffer.
*/
@callflow(next="unlock")
lockFlex(handle bufferHandle,
uint64_t producerUsageMask,
uint64_t consumerUsageMask,
Rect accessRegion,
handle acquireFence)
lockYCbCr(pointer buffer,
bitfield<BufferUsage> cpuUsage,
Rect accessRegion,
handle acquireFence)
generates (Error error,
FlexLayout layout);
YCbCrLayout layout);
/**
* This function indicates to the device that the client will be done with
* the buffer when releaseFence signals.
* Unlocks a buffer to indicate all CPU accesses to the buffer have
* completed.
*
* releaseFence will be filled with a file descriptor referring to a
* release sync fence object, which will be signaled when it is safe to
* access the contents of the buffer (after the buffer has been unlocked).
* If it is already safe to access the buffer contents, then -1 may be
* returned instead.
*
* This function is used to unlock both buffers locked by lock() and those
* locked by lockFlex().
*
* @param device is the mapper device.
* @param bufferHandle is the buffer to unlock.
* @param buffer is the buffer to unlock.
* @return error is NONE upon success. Otherwise,
* BAD_BUFFER when the buffer handle is invalid.
* @return releaseFence is a sync fence file descriptor as described
* above.
* BAD_BUFFER when the buffer is invalid or not locked.
* @return releaseFence, when non-empty, is a handle containing a file
* descriptor referring to a sync fence object. The sync fence
* object will be signaled when the mapper has completed any
* pending work.
*/
@callflow(next="*")
unlock(handle bufferHandle)
unlock(pointer buffer)
generates (Error error,
handle releaseFence);
};

View File

@@ -18,10 +18,9 @@ cc_library_shared {
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["GrallocMapper.cpp"],
srcs: ["GrallocMapper.cpp", "Gralloc0Mapper.cpp", "Gralloc1Mapper.cpp"],
cppflags: ["-Wall", "-Wextra"],
shared_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
"libbase",
"libcutils",
@@ -29,6 +28,12 @@ cc_library_shared {
"libhidlbase",
"libhidltransport",
"liblog",
"libsync",
"libutils",
],
}
cc_library_static {
name: "libgrallocmapperincludes",
export_include_dirs: ["."],
}

View File

@@ -0,0 +1,156 @@
/*
* Copyright 2016 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_TAG "Gralloc0Mapper"
#include "Gralloc0Mapper.h"
#include <log/log.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
Gralloc0Mapper::Gralloc0Mapper(const hw_module_t* module)
: mModule(reinterpret_cast<const gralloc_module_t*>(module)),
mMinor(module->module_api_version & 0xff) {
mCapabilities.highUsageBits = false;
mCapabilities.layeredBuffers = false;
mCapabilities.unregisterImplyDelete = false;
}
Error Gralloc0Mapper::registerBuffer(buffer_handle_t bufferHandle) {
int result = mModule->registerBuffer(mModule, bufferHandle);
return result ? Error::BAD_BUFFER : Error::NONE;
}
void Gralloc0Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
mModule->unregisterBuffer(mModule, bufferHandle);
}
Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) {
int result;
void* data = nullptr;
if (mMinor >= 3 && mModule->lockAsync) {
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
result = mModule->lockAsync(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width, accessRegion.height,
&data, fenceFd);
} else {
waitFenceFd(fenceFd, "Gralloc0Mapper::lock");
result = mModule->lock(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width, accessRegion.height, &data);
}
if (result) {
return Error::BAD_VALUE;
} else {
*outData = data;
return Error::NONE;
}
}
Error Gralloc0Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) {
int result;
android_ycbcr ycbcr = {};
if (mMinor >= 3 && mModule->lockAsync_ycbcr) {
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
result = mModule->lockAsync_ycbcr(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width,
accessRegion.height, &ycbcr, fenceFd);
} else {
waitFenceFd(fenceFd, "Gralloc0Mapper::lockYCbCr");
if (mModule->lock_ycbcr) {
result = mModule->lock_ycbcr(mModule, bufferHandle, cpuUsage,
accessRegion.left, accessRegion.top,
accessRegion.width,
accessRegion.height, &ycbcr);
} else {
result = -EINVAL;
}
}
if (result) {
return Error::BAD_VALUE;
} else {
outLayout->y = ycbcr.y;
outLayout->cb = ycbcr.cb;
outLayout->cr = ycbcr.cr;
outLayout->yStride = ycbcr.ystride;
outLayout->cStride = ycbcr.cstride;
outLayout->chromaStep = ycbcr.chroma_step;
return Error::NONE;
}
}
Error Gralloc0Mapper::unlockBuffer(buffer_handle_t bufferHandle,
int* outFenceFd) {
int result;
int fenceFd = -1;
if (mMinor >= 3 && mModule->unlockAsync) {
result = mModule->unlockAsync(mModule, bufferHandle, &fenceFd);
} else {
result = mModule->unlock(mModule, bufferHandle);
}
if (result) {
// we always own the fenceFd even when unlock failed
if (fenceFd >= 0) {
close(fenceFd);
}
return Error::BAD_VALUE;
} else {
*outFenceFd = fenceFd;
return Error::NONE;
}
}
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2016 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_MAPPER_V2_0_GRALLOC0MAPPER_H
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H
#include "GrallocMapper.h"
#include <hardware/gralloc.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
class Gralloc0Mapper : public GrallocMapper {
public:
Gralloc0Mapper(const hw_module_t* module);
private:
Error registerBuffer(buffer_handle_t bufferHandle) override;
void unregisterBuffer(buffer_handle_t bufferHandle) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) override;
Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
const gralloc_module_t* mModule;
uint8_t mMinor;
};
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC0MAPPER_H

View File

@@ -0,0 +1,273 @@
/*
* Copyright 2016 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_TAG "Gralloc1Mapper"
#include "Gralloc1Mapper.h"
#include <vector>
#include <log/log.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::common::V1_0::BufferUsage;
Gralloc1Mapper::Gralloc1Mapper(const hw_module_t* module)
: mDevice(nullptr), mDispatch() {
int result = gralloc1_open(module, &mDevice);
if (result) {
LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
strerror(-result));
}
initCapabilities();
initDispatch();
}
Gralloc1Mapper::~Gralloc1Mapper() {
gralloc1_close(mDevice);
}
void Gralloc1Mapper::initCapabilities() {
mCapabilities.highUsageBits = true;
mCapabilities.layeredBuffers = false;
mCapabilities.unregisterImplyDelete = false;
uint32_t count = 0;
mDevice->getCapabilities(mDevice, &count, nullptr);
std::vector<int32_t> capabilities(count);
mDevice->getCapabilities(mDevice, &count, capabilities.data());
capabilities.resize(count);
for (auto capability : capabilities) {
switch (capability) {
case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
mCapabilities.layeredBuffers = true;
break;
case GRALLOC1_CAPABILITY_RELEASE_IMPLY_DELETE:
mCapabilities.unregisterImplyDelete = true;
break;
}
}
}
template <typename T>
void Gralloc1Mapper::initDispatch(gralloc1_function_descriptor_t desc,
T* outPfn) {
auto pfn = mDevice->getFunction(mDevice, desc);
if (!pfn) {
LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
}
*outPfn = reinterpret_cast<T>(pfn);
}
void Gralloc1Mapper::initDispatch() {
initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain);
initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES,
&mDispatch.getNumFlexPlanes);
initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock);
initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex);
initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock);
}
Error Gralloc1Mapper::toError(int32_t error) {
switch (error) {
case GRALLOC1_ERROR_NONE:
return Error::NONE;
case GRALLOC1_ERROR_BAD_DESCRIPTOR:
return Error::BAD_DESCRIPTOR;
case GRALLOC1_ERROR_BAD_HANDLE:
return Error::BAD_BUFFER;
case GRALLOC1_ERROR_BAD_VALUE:
return Error::BAD_VALUE;
case GRALLOC1_ERROR_NOT_SHARED:
return Error::NONE; // this is fine
case GRALLOC1_ERROR_NO_RESOURCES:
return Error::NO_RESOURCES;
case GRALLOC1_ERROR_UNDEFINED:
case GRALLOC1_ERROR_UNSUPPORTED:
default:
return Error::UNSUPPORTED;
}
}
bool Gralloc1Mapper::toYCbCrLayout(const android_flex_layout& flex,
YCbCrLayout* outLayout) {
// must be YCbCr
if (flex.format != FLEX_FORMAT_YCbCr || flex.num_planes < 3) {
return false;
}
for (int i = 0; i < 3; i++) {
const auto& plane = flex.planes[i];
// must have 8-bit depth
if (plane.bits_per_component != 8 || plane.bits_used != 8) {
return false;
}
if (plane.component == FLEX_COMPONENT_Y) {
// Y must not be interleaved
if (plane.h_increment != 1) {
return false;
}
} else {
// Cb and Cr can be interleaved
if (plane.h_increment != 1 && plane.h_increment != 2) {
return false;
}
}
if (!plane.v_increment) {
return false;
}
}
if (flex.planes[0].component != FLEX_COMPONENT_Y ||
flex.planes[1].component != FLEX_COMPONENT_Cb ||
flex.planes[2].component != FLEX_COMPONENT_Cr) {
return false;
}
const auto& y = flex.planes[0];
const auto& cb = flex.planes[1];
const auto& cr = flex.planes[2];
if (cb.h_increment != cr.h_increment || cb.v_increment != cr.v_increment) {
return false;
}
outLayout->y = y.top_left;
outLayout->cb = cb.top_left;
outLayout->cr = cr.top_left;
outLayout->yStride = y.v_increment;
outLayout->cStride = cb.v_increment;
outLayout->chromaStep = cb.h_increment;
return true;
}
gralloc1_rect_t Gralloc1Mapper::asGralloc1Rect(const IMapper::Rect& rect) {
return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
}
Error Gralloc1Mapper::registerBuffer(buffer_handle_t bufferHandle) {
return toError(mDispatch.retain(mDevice, bufferHandle));
}
void Gralloc1Mapper::unregisterBuffer(buffer_handle_t bufferHandle) {
mDispatch.release(mDevice, bufferHandle);
}
Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) {
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
const uint64_t consumerUsage =
cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
const auto accessRect = asGralloc1Rect(accessRegion);
void* data = nullptr;
int32_t error = mDispatch.lock(mDevice, bufferHandle, cpuUsage,
consumerUsage, &accessRect, &data, fenceFd);
if (error == GRALLOC1_ERROR_NONE) {
*outData = data;
}
return toError(error);
}
Error Gralloc1Mapper::lockBuffer(buffer_handle_t bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) {
// prepare flex layout
android_flex_layout flex = {};
int32_t error =
mDispatch.getNumFlexPlanes(mDevice, bufferHandle, &flex.num_planes);
if (error != GRALLOC1_ERROR_NONE) {
return toError(error);
}
std::vector<android_flex_plane_t> flexPlanes(flex.num_planes);
flex.planes = flexPlanes.data();
// Dup fenceFd as it is going to be owned by gralloc. Note that it is
// gralloc's responsibility to close it, even on locking errors.
if (fenceFd >= 0) {
fenceFd = dup(fenceFd);
if (fenceFd < 0) {
return Error::NO_RESOURCES;
}
}
const uint64_t consumerUsage =
cpuUsage & ~static_cast<uint64_t>(BufferUsage::CPU_WRITE_MASK);
const auto accessRect = asGralloc1Rect(accessRegion);
error = mDispatch.lockFlex(mDevice, bufferHandle, cpuUsage, consumerUsage,
&accessRect, &flex, fenceFd);
if (error == GRALLOC1_ERROR_NONE && !toYCbCrLayout(flex, outLayout)) {
ALOGD("unable to convert android_flex_layout to YCbCrLayout");
// undo the lock
fenceFd = -1;
mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
if (fenceFd >= 0) {
close(fenceFd);
}
error = GRALLOC1_ERROR_BAD_HANDLE;
}
return toError(error);
}
Error Gralloc1Mapper::unlockBuffer(buffer_handle_t bufferHandle,
int* outFenceFd) {
int fenceFd = -1;
int32_t error = mDispatch.unlock(mDevice, bufferHandle, &fenceFd);
if (error == GRALLOC1_ERROR_NONE) {
*outFenceFd = fenceFd;
} else if (fenceFd >= 0) {
// we always own the fenceFd even when unlock failed
close(fenceFd);
}
return toError(error);
}
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,76 @@
/*
* Copyright 2016 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_MAPPER_V2_0_GRALLOC1MAPPER_H
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H
#include "GrallocMapper.h"
#include <hardware/gralloc1.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
class Gralloc1Mapper : public GrallocMapper {
public:
Gralloc1Mapper(const hw_module_t* module);
~Gralloc1Mapper();
private:
void initCapabilities();
template <typename T>
void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
void initDispatch();
static Error toError(int32_t error);
static bool toYCbCrLayout(const android_flex_layout& flex,
YCbCrLayout* outLayout);
static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect);
Error registerBuffer(buffer_handle_t bufferHandle) override;
void unregisterBuffer(buffer_handle_t bufferHandle) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) override;
Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) override;
Error unlockBuffer(buffer_handle_t bufferHandle, int* outFenceFd) override;
gralloc1_device_t* mDevice;
struct {
GRALLOC1_PFN_RETAIN retain;
GRALLOC1_PFN_RELEASE release;
GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
GRALLOC1_PFN_LOCK lock;
GRALLOC1_PFN_LOCK_FLEX lockFlex;
GRALLOC1_PFN_UNLOCK unlock;
} mDispatch;
};
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC1MAPPER_H

View File

@@ -0,0 +1,79 @@
/*
* Copyright 2016 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_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace implementation {
using android::hardware::graphics::common::V1_0::PixelFormat;
/**
* BufferDescriptor is created by IMapper and consumed by IAllocator. It is
* versioned so that IMapper and IAllocator can be updated independently.
*/
constexpr uint32_t grallocBufferDescriptorSize = 7;
constexpr uint32_t grallocBufferDescriptorMagicVersion = ((0x9487 << 16) | 0);
inline BufferDescriptor grallocEncodeBufferDescriptor(
const IMapper::BufferDescriptorInfo& descriptorInfo) {
BufferDescriptor descriptor;
descriptor.resize(grallocBufferDescriptorSize);
descriptor[0] = grallocBufferDescriptorMagicVersion;
descriptor[1] = descriptorInfo.width;
descriptor[2] = descriptorInfo.height;
descriptor[3] = descriptorInfo.layerCount;
descriptor[4] = static_cast<uint32_t>(descriptorInfo.format);
descriptor[5] = static_cast<uint32_t>(descriptorInfo.usage);
descriptor[6] = static_cast<uint32_t>(descriptorInfo.usage >> 32);
return descriptor;
}
inline bool grallocDecodeBufferDescriptor(
const BufferDescriptor& descriptor,
IMapper::BufferDescriptorInfo* outDescriptorInfo) {
if (descriptor.size() != grallocBufferDescriptorSize ||
descriptor[0] != grallocBufferDescriptorMagicVersion) {
return false;
}
*outDescriptorInfo = IMapper::BufferDescriptorInfo{
descriptor[1],
descriptor[2],
descriptor[3],
static_cast<PixelFormat>(descriptor[4]),
(static_cast<uint64_t>(descriptor[6]) << 32) | descriptor[5],
};
return true;
}
} // namespace implementation
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOCBUFFERDESCRIPTOR_H

View File

@@ -17,14 +17,14 @@
#include "GrallocMapper.h"
#include <mutex>
#include <vector>
#include <unordered_map>
#include "Gralloc0Mapper.h"
#include "Gralloc1Mapper.h"
#include "GrallocBufferDescriptor.h"
#include <string.h>
#include <inttypes.h>
#include <hardware/gralloc1.h>
#include <log/log.h>
#include <sync/sync.h>
namespace android {
namespace hardware {
@@ -33,374 +33,251 @@ namespace mapper {
namespace V2_0 {
namespace implementation {
namespace {
using android::hardware::graphics::allocator::V2_0::Error;
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::PixelFormat;
class GrallocMapperHal : public IMapper {
public:
GrallocMapperHal(const hw_module_t* module);
~GrallocMapperHal();
std::mutex GrallocMapper::mMutex;
std::unordered_set<buffer_handle_t> GrallocMapper::mRegisteredHandles;
// IMapper interface
Return<Error> retain(const hidl_handle& bufferHandle) override;
Return<Error> release(const hidl_handle& bufferHandle) override;
Return<void> getDimensions(const hidl_handle& bufferHandle,
getDimensions_cb hidl_cb) override;
Return<void> getFormat(const hidl_handle& bufferHandle,
getFormat_cb hidl_cb) override;
Return<void> getLayerCount(const hidl_handle& bufferHandle,
getLayerCount_cb hidl_cb) override;
Return<void> getProducerUsageMask(const hidl_handle& bufferHandle,
getProducerUsageMask_cb hidl_cb) override;
Return<void> getConsumerUsageMask(const hidl_handle& bufferHandle,
getConsumerUsageMask_cb hidl_cb) override;
Return<void> getBackingStore(const hidl_handle& bufferHandle,
getBackingStore_cb hidl_cb) override;
Return<void> getStride(const hidl_handle& bufferHandle,
getStride_cb hidl_cb) override;
Return<void> lock(const hidl_handle& bufferHandle,
uint64_t producerUsageMask, uint64_t consumerUsageMask,
const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
lock_cb hidl_cb) override;
Return<void> lockFlex(const hidl_handle& bufferHandle,
uint64_t producerUsageMask, uint64_t consumerUsageMask,
const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
lockFlex_cb hidl_cb) override;
Return<void> unlock(const hidl_handle& bufferHandle,
unlock_cb hidl_cb) override;
bool GrallocMapper::validateDescriptorInfo(
const BufferDescriptorInfo& descriptorInfo) const {
const uint64_t validUsageBits =
BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
BufferUsage::GPU_TEXTURE | BufferUsage::GPU_RENDER_TARGET |
BufferUsage::COMPOSER_OVERLAY | BufferUsage::COMPOSER_CLIENT_TARGET |
BufferUsage::PROTECTED | BufferUsage::COMPOSER_CURSOR |
BufferUsage::VIDEO_ENCODER | BufferUsage::CAMERA_OUTPUT |
BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT |
BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA |
BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK |
(mCapabilities.highUsageBits ? BufferUsage::VENDOR_MASK_HI
: static_cast<BufferUsage>(0));
private:
void initCapabilities();
template<typename T>
void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
void initDispatch();
static gralloc1_rect_t asGralloc1Rect(const IMapper::Rect& rect);
static bool dupFence(const hidl_handle& fenceHandle, int* outFd);
gralloc1_device_t* mDevice;
struct {
bool layeredBuffers;
} mCapabilities;
struct {
GRALLOC1_PFN_RETAIN retain;
GRALLOC1_PFN_RELEASE release;
GRALLOC1_PFN_GET_DIMENSIONS getDimensions;
GRALLOC1_PFN_GET_FORMAT getFormat;
GRALLOC1_PFN_GET_LAYER_COUNT getLayerCount;
GRALLOC1_PFN_GET_PRODUCER_USAGE getProducerUsage;
GRALLOC1_PFN_GET_CONSUMER_USAGE getConsumerUsage;
GRALLOC1_PFN_GET_BACKING_STORE getBackingStore;
GRALLOC1_PFN_GET_STRIDE getStride;
GRALLOC1_PFN_GET_NUM_FLEX_PLANES getNumFlexPlanes;
GRALLOC1_PFN_LOCK lock;
GRALLOC1_PFN_LOCK_FLEX lockFlex;
GRALLOC1_PFN_UNLOCK unlock;
} mDispatch;
std::mutex mMutex;
std::unordered_map<buffer_handle_t, size_t> mBufferReferenceCounts;
};
GrallocMapperHal::GrallocMapperHal(const hw_module_t* module)
: mDevice(nullptr), mCapabilities(), mDispatch()
{
int status = gralloc1_open(module, &mDevice);
if (status) {
LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
strerror(-status));
}
initCapabilities();
initDispatch();
}
GrallocMapperHal::~GrallocMapperHal()
{
gralloc1_close(mDevice);
}
void GrallocMapperHal::initCapabilities()
{
uint32_t count = 0;
mDevice->getCapabilities(mDevice, &count, nullptr);
std::vector<int32_t> caps(count);
mDevice->getCapabilities(mDevice, &count, caps.data());
caps.resize(count);
for (auto cap : caps) {
switch (cap) {
case GRALLOC1_CAPABILITY_LAYERED_BUFFERS:
mCapabilities.layeredBuffers = true;
break;
default:
break;
}
}
}
template<typename T>
void GrallocMapperHal::initDispatch(gralloc1_function_descriptor_t desc,
T* outPfn)
{
auto pfn = mDevice->getFunction(mDevice, desc);
if (!pfn) {
LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
}
*outPfn = reinterpret_cast<T>(pfn);
}
void GrallocMapperHal::initDispatch()
{
initDispatch(GRALLOC1_FUNCTION_RETAIN, &mDispatch.retain);
initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
initDispatch(GRALLOC1_FUNCTION_GET_DIMENSIONS, &mDispatch.getDimensions);
initDispatch(GRALLOC1_FUNCTION_GET_FORMAT, &mDispatch.getFormat);
if (mCapabilities.layeredBuffers) {
initDispatch(GRALLOC1_FUNCTION_GET_LAYER_COUNT,
&mDispatch.getLayerCount);
}
initDispatch(GRALLOC1_FUNCTION_GET_PRODUCER_USAGE,
&mDispatch.getProducerUsage);
initDispatch(GRALLOC1_FUNCTION_GET_CONSUMER_USAGE,
&mDispatch.getConsumerUsage);
initDispatch(GRALLOC1_FUNCTION_GET_BACKING_STORE,
&mDispatch.getBackingStore);
initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride);
initDispatch(GRALLOC1_FUNCTION_GET_NUM_FLEX_PLANES,
&mDispatch.getNumFlexPlanes);
initDispatch(GRALLOC1_FUNCTION_LOCK, &mDispatch.lock);
initDispatch(GRALLOC1_FUNCTION_LOCK_FLEX, &mDispatch.lockFlex);
initDispatch(GRALLOC1_FUNCTION_UNLOCK, &mDispatch.unlock);
}
gralloc1_rect_t GrallocMapperHal::asGralloc1Rect(const IMapper::Rect& rect)
{
return gralloc1_rect_t{rect.left, rect.top, rect.width, rect.height};
}
bool GrallocMapperHal::dupFence(const hidl_handle& fenceHandle, int* outFd)
{
auto handle = fenceHandle.getNativeHandle();
if (!handle || handle->numFds == 0) {
*outFd = -1;
return true;
}
if (handle->numFds > 1) {
ALOGE("invalid fence handle with %d fds", handle->numFds);
if (!descriptorInfo.width || !descriptorInfo.height ||
!descriptorInfo.layerCount) {
return false;
}
*outFd = dup(handle->data[0]);
return (*outFd >= 0);
}
Return<Error> GrallocMapperHal::retain(const hidl_handle& bufferHandle)
{
int32_t err = mDispatch.retain(mDevice, bufferHandle);
if (err == GRALLOC1_ERROR_NONE) {
auto nativeHandle = bufferHandle.getNativeHandle();
std::lock_guard<std::mutex> lock(mMutex);
++mBufferReferenceCounts[nativeHandle];
}
return static_cast<Error>(err);
}
Return<Error> GrallocMapperHal::release(const hidl_handle& bufferHandle)
{
int32_t err = mDispatch.release(mDevice, bufferHandle);
if (err == GRALLOC1_ERROR_NONE) {
auto nativeHandle = bufferHandle.getNativeHandle();
std::lock_guard<std::mutex> lock(mMutex);
auto iter = mBufferReferenceCounts.find(bufferHandle);
if (iter == mBufferReferenceCounts.end()) {
// this should never happen
err = GRALLOC1_ERROR_BAD_HANDLE;
} else if (--iter->second == 0) {
native_handle_close(nativeHandle);
native_handle_delete(const_cast<native_handle_t*>(nativeHandle));
mBufferReferenceCounts.erase(iter);
}
if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount > 1) {
return false;
}
return static_cast<Error>(err);
}
Return<void> GrallocMapperHal::getDimensions(const hidl_handle& bufferHandle,
getDimensions_cb hidl_cb)
{
uint32_t width = 0;
uint32_t height = 0;
int32_t err = mDispatch.getDimensions(mDevice, bufferHandle,
&width, &height);
hidl_cb(static_cast<Error>(err), width, height);
return Void();
}
Return<void> GrallocMapperHal::getFormat(const hidl_handle& bufferHandle,
getFormat_cb hidl_cb)
{
int32_t format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
int32_t err = mDispatch.getFormat(mDevice, bufferHandle, &format);
hidl_cb(static_cast<Error>(err), static_cast<PixelFormat>(format));
return Void();
}
Return<void> GrallocMapperHal::getLayerCount(const hidl_handle& bufferHandle,
getLayerCount_cb hidl_cb)
{
int32_t err = GRALLOC1_ERROR_NONE;
uint32_t count = 1;
if (mCapabilities.layeredBuffers) {
err = mDispatch.getLayerCount(mDevice, bufferHandle, &count);
if (descriptorInfo.format == static_cast<PixelFormat>(0)) {
return false;
}
if (descriptorInfo.usage & ~validUsageBits) {
// could not fail as gralloc may use the reserved bits...
ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64,
descriptorInfo.usage & ~validUsageBits);
}
return true;
}
Return<void> GrallocMapper::createDescriptor(
const BufferDescriptorInfo& descriptorInfo, createDescriptor_cb hidl_cb) {
if (validateDescriptorInfo(descriptorInfo)) {
hidl_cb(Error::NONE, grallocEncodeBufferDescriptor(descriptorInfo));
} else {
hidl_cb(Error::BAD_VALUE, BufferDescriptor());
}
hidl_cb(static_cast<Error>(err), count);
return Void();
}
Return<void> GrallocMapperHal::getProducerUsageMask(
const hidl_handle& bufferHandle, getProducerUsageMask_cb hidl_cb)
{
uint64_t mask = 0x0;
int32_t err = mDispatch.getProducerUsage(mDevice, bufferHandle, &mask);
hidl_cb(static_cast<Error>(err), mask);
return Void();
bool GrallocMapper::addRegisteredHandle(buffer_handle_t bufferHandle) {
std::lock_guard<std::mutex> lock(mMutex);
return mRegisteredHandles.insert(bufferHandle).second;
}
Return<void> GrallocMapperHal::getConsumerUsageMask(
const hidl_handle& bufferHandle, getConsumerUsageMask_cb hidl_cb)
{
uint64_t mask = 0x0;
int32_t err = mDispatch.getConsumerUsage(mDevice, bufferHandle, &mask);
native_handle_t* GrallocMapper::popRegisteredHandle(void* buffer) {
auto bufferHandle = static_cast<native_handle_t*>(buffer);
hidl_cb(static_cast<Error>(err), mask);
return Void();
std::lock_guard<std::mutex> lock(mMutex);
return mRegisteredHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr;
}
Return<void> GrallocMapperHal::getBackingStore(
const hidl_handle& bufferHandle, getBackingStore_cb hidl_cb)
{
uint64_t store = 0;
int32_t err = mDispatch.getBackingStore(mDevice, bufferHandle, &store);
buffer_handle_t GrallocMapper::getRegisteredHandle(const void* buffer) {
auto bufferHandle = static_cast<buffer_handle_t>(buffer);
hidl_cb(static_cast<Error>(err), store);
return Void();
std::lock_guard<std::mutex> lock(mMutex);
return mRegisteredHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr;
}
Return<void> GrallocMapperHal::getStride(const hidl_handle& bufferHandle,
getStride_cb hidl_cb)
{
uint32_t stride = 0;
int32_t err = mDispatch.getStride(mDevice, bufferHandle, &stride);
Return<void> GrallocMapper::importBuffer(const hidl_handle& rawHandle,
importBuffer_cb hidl_cb) {
// importing an already imported handle rather than a raw handle
if (getRegisteredHandle(rawHandle.getNativeHandle())) {
hidl_cb(Error::BAD_BUFFER, nullptr);
return Void();
}
hidl_cb(static_cast<Error>(err), stride);
return Void();
}
if (!rawHandle.getNativeHandle()) {
hidl_cb(Error::BAD_BUFFER, nullptr);
return Void();
}
Return<void> GrallocMapperHal::lock(const hidl_handle& bufferHandle,
uint64_t producerUsageMask, uint64_t consumerUsageMask,
const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
lock_cb hidl_cb)
{
gralloc1_rect_t rect = asGralloc1Rect(accessRegion);
int fence = -1;
if (!dupFence(acquireFence, &fence)) {
native_handle_t* bufferHandle =
native_handle_clone(rawHandle.getNativeHandle());
if (!bufferHandle) {
hidl_cb(Error::NO_RESOURCES, nullptr);
return Void();
}
Error error = registerBuffer(bufferHandle);
if (error != Error::NONE) {
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
hidl_cb(error, nullptr);
return Void();
}
// The newly cloned handle is already registered? This can only happen
// when a handle previously registered was native_handle_delete'd instead
// of freeBuffer'd.
if (!addRegisteredHandle(bufferHandle)) {
ALOGE("handle %p has already been imported; potential fd leaking",
bufferHandle);
unregisterBuffer(bufferHandle);
if (!mCapabilities.unregisterImplyDelete) {
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
}
hidl_cb(Error::NO_RESOURCES, nullptr);
return Void();
}
hidl_cb(Error::NONE, bufferHandle);
return Void();
}
Return<Error> GrallocMapper::freeBuffer(void* buffer) {
native_handle_t* bufferHandle = popRegisteredHandle(buffer);
if (!bufferHandle) {
return Error::BAD_BUFFER;
}
unregisterBuffer(bufferHandle);
if (!mCapabilities.unregisterImplyDelete) {
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
}
return Error::NONE;
}
void GrallocMapper::waitFenceFd(int fenceFd, const char* logname) {
if (fenceFd < 0) {
return;
}
const int warningTimeout = 3500;
const int error = sync_wait(fenceFd, warningTimeout);
if (error < 0 && errno == ETIME) {
ALOGE("%s: fence %d didn't signal in %u ms", logname, fenceFd,
warningTimeout);
sync_wait(fenceFd, -1);
}
}
bool GrallocMapper::getFenceFd(const hidl_handle& fenceHandle,
int* outFenceFd) {
auto handle = fenceHandle.getNativeHandle();
if (handle && handle->numFds > 1) {
ALOGE("invalid fence handle with %d fds", handle->numFds);
return false;
}
*outFenceFd = (handle && handle->numFds == 1) ? handle->data[0] : -1;
return true;
}
hidl_handle GrallocMapper::getFenceHandle(int fenceFd, char* handleStorage) {
native_handle_t* handle = nullptr;
if (fenceFd >= 0) {
handle = native_handle_init(handleStorage, 1, 0);
handle->data[0] = fenceFd;
}
return hidl_handle(handle);
}
Return<void> GrallocMapper::lock(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lock_cb hidl_cb) {
buffer_handle_t bufferHandle = getRegisteredHandle(buffer);
if (!bufferHandle) {
hidl_cb(Error::BAD_BUFFER, nullptr);
return Void();
}
int fenceFd;
if (!getFenceFd(acquireFence, &fenceFd)) {
hidl_cb(Error::BAD_VALUE, nullptr);
return Void();
}
void* data = nullptr;
int32_t err = mDispatch.lock(mDevice, bufferHandle, producerUsageMask,
consumerUsageMask, &rect, &data, fence);
if (err != GRALLOC1_ERROR_NONE) {
close(fence);
}
Error error =
lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &data);
hidl_cb(static_cast<Error>(err), data);
hidl_cb(error, data);
return Void();
}
Return<void> GrallocMapperHal::lockFlex(const hidl_handle& bufferHandle,
uint64_t producerUsageMask, uint64_t consumerUsageMask,
const IMapper::Rect& accessRegion, const hidl_handle& acquireFence,
lockFlex_cb hidl_cb)
{
FlexLayout layout_reply{};
Return<void> GrallocMapper::lockYCbCr(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lockYCbCr_cb hidl_cb) {
YCbCrLayout layout = {};
uint32_t planeCount = 0;
int32_t err = mDispatch.getNumFlexPlanes(mDevice, bufferHandle,
&planeCount);
if (err != GRALLOC1_ERROR_NONE) {
hidl_cb(static_cast<Error>(err), layout_reply);
buffer_handle_t bufferHandle = getRegisteredHandle(buffer);
if (!bufferHandle) {
hidl_cb(Error::BAD_BUFFER, layout);
return Void();
}
gralloc1_rect_t rect = asGralloc1Rect(accessRegion);
int fence = -1;
if (!dupFence(acquireFence, &fence)) {
hidl_cb(Error::NO_RESOURCES, layout_reply);
int fenceFd;
if (!getFenceFd(acquireFence, &fenceFd)) {
hidl_cb(Error::BAD_VALUE, layout);
return Void();
}
std::vector<android_flex_plane_t> planes(planeCount);
android_flex_layout_t layout{};
layout.num_planes = planes.size();
layout.planes = planes.data();
Error error =
lockBuffer(bufferHandle, cpuUsage, accessRegion, fenceFd, &layout);
err = mDispatch.lockFlex(mDevice, bufferHandle, producerUsageMask,
consumerUsageMask, &rect, &layout, fence);
if (err == GRALLOC1_ERROR_NONE) {
layout_reply.format = static_cast<FlexFormat>(layout.format);
hidl_cb(error, layout);
return Void();
}
planes.resize(layout.num_planes);
layout_reply.planes.setToExternal(
reinterpret_cast<FlexPlane*>(planes.data()), planes.size());
Return<void> GrallocMapper::unlock(void* buffer, unlock_cb hidl_cb) {
buffer_handle_t bufferHandle = getRegisteredHandle(buffer);
if (!bufferHandle) {
hidl_cb(Error::BAD_BUFFER, nullptr);
return Void();
}
int fenceFd;
Error error = unlockBuffer(bufferHandle, &fenceFd);
if (error == Error::NONE) {
NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
hidl_cb(error, getFenceHandle(fenceFd, fenceStorage));
if (fenceFd >= 0) {
close(fenceFd);
}
} else {
close(fence);
hidl_cb(error, nullptr);
}
hidl_cb(static_cast<Error>(err), layout_reply);
return Void();
}
Return<void> GrallocMapperHal::unlock(const hidl_handle& bufferHandle,
unlock_cb hidl_cb)
{
int32_t fence = -1;
int32_t err = mDispatch.unlock(mDevice, bufferHandle, &fence);
NATIVE_HANDLE_DECLARE_STORAGE(fenceStorage, 1, 0);
hidl_handle fenceHandle;
if (err == GRALLOC1_ERROR_NONE && fence >= 0) {
auto nativeHandle = native_handle_init(fenceStorage, 1, 0);
nativeHandle->data[0] = fence;
fenceHandle = nativeHandle;
}
hidl_cb(static_cast<Error>(err), fenceHandle);
return Void();
}
} // anonymous namespace
IMapper* HIDL_FETCH_IMapper(const char* /* name */) {
const hw_module_t* module = nullptr;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
@@ -410,12 +287,15 @@ IMapper* HIDL_FETCH_IMapper(const char* /* name */) {
}
uint8_t major = (module->module_api_version >> 8) & 0xff;
if (major != 1) {
ALOGE("unknown gralloc module major version %d", major);
return nullptr;
switch (major) {
case 1:
return new Gralloc1Mapper(module);
case 0:
return new Gralloc0Mapper(module);
default:
ALOGE("unknown gralloc module major version %d", major);
return nullptr;
}
return new GrallocMapperHal(module);
}
} // namespace implementation

View File

@@ -18,6 +18,10 @@
#define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <system/window.h>
#include <mutex>
#include <unordered_set>
namespace android {
namespace hardware {
@@ -26,6 +30,68 @@ namespace mapper {
namespace V2_0 {
namespace implementation {
class GrallocMapper : public IMapper {
public:
// IMapper interface
Return<void> createDescriptor(const BufferDescriptorInfo& descriptorInfo,
createDescriptor_cb hidl_cb) override;
Return<void> importBuffer(const hidl_handle& rawHandle,
importBuffer_cb hidl_cb) override;
Return<Error> freeBuffer(void* buffer) override;
Return<void> lock(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lock_cb hidl_cb) override;
Return<void> lockYCbCr(void* buffer, uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
const hidl_handle& acquireFence,
lockYCbCr_cb hidl_cb) override;
Return<void> unlock(void* buffer, unlock_cb hidl_cb) override;
protected:
static void waitFenceFd(int fenceFd, const char* logname);
struct {
bool highUsageBits;
bool layeredBuffers;
bool unregisterImplyDelete;
} mCapabilities = {};
private:
virtual bool validateDescriptorInfo(
const BufferDescriptorInfo& descriptorInfo) const;
// Register a buffer. The handle is already cloned by the caller.
virtual Error registerBuffer(buffer_handle_t bufferHandle) = 0;
// Unregister a buffer. The handle is closed and deleted by the
// callee if and only if mCapabilities.unregisterImplyDelete is set.
virtual void unregisterBuffer(buffer_handle_t bufferHandle) = 0;
// Lock a buffer. The fence is owned by the caller.
virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
void** outData) = 0;
virtual Error lockBuffer(buffer_handle_t bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int fenceFd,
YCbCrLayout* outLayout) = 0;
// Unlock a buffer. The returned fence is owned by the caller.
virtual Error unlockBuffer(buffer_handle_t bufferHandle,
int* outFenceFd) = 0;
static bool addRegisteredHandle(buffer_handle_t bufferHandle);
static buffer_handle_t getRegisteredHandle(const void* buffer);
static native_handle_t* popRegisteredHandle(void* buffer);
static bool getFenceFd(const hidl_handle& fenceHandle, int* outFenceFd);
static hidl_handle getFenceHandle(int fenceFd, char* handleStorage);
// these are static and shared by all mappers
static std::mutex mMutex;
static std::unordered_set<buffer_handle_t> mRegisteredHandles;
};
extern "C" IMapper* HIDL_FETCH_IMapper(const char* name);
} // namespace implementation

View File

@@ -16,101 +16,50 @@
package android.hardware.graphics.mapper@2.0;
enum Error : int32_t {
NONE = 0, /** no error */
BAD_DESCRIPTOR = 1, /** invalid BufferDescriptor */
BAD_BUFFER = 2, /** invalid buffer handle */
BAD_VALUE = 3, /** invalid width, height, etc. */
/* 4 is reserved */
NO_RESOURCES = 5, /** temporary failure due to resource contention */
/* 6 is reserved */
UNSUPPORTED = 7, /** permanent failure */
};
/**
* Structures for describing flexible YUVA/RGBA formats for consumption by
* applications. Such flexible formats contain a plane for each component (e.g.
* red, green, blue), where each plane is laid out in a grid-like pattern
* occupying unique byte addresses and with consistent byte offsets between
* neighboring pixels.
*
* The FlexLayout structure is used with any pixel format that can be
* represented by it, such as:
* - PixelFormat::YCBCR_*_888
* - PixelFormat::FLEX_RGB*_888
* - PixelFormat::RGB[AX]_888[8],BGRA_8888,RGB_888
* - PixelFormat::YV12,Y8,Y16,YCBCR_422_SP/I,YCRCB_420_SP
* - even implementation defined formats that can be represented by
* the structures
*
* Vertical increment (aka. row increment or stride) describes the distance in
* bytes from the first pixel of one row to the first pixel of the next row
* (below) for the component plane. This can be negative.
*
* Horizontal increment (aka. column or pixel increment) describes the distance
* in bytes from one pixel to the next pixel (to the right) on the same row for
* the component plane. This can be negative.
*
* Each plane can be subsampled either vertically or horizontally by
* a power-of-two factor.
*
* The bit-depth of each component can be arbitrary, as long as the pixels are
* laid out on whole bytes, in native byte-order, using the most significant
* bits of each unit.
* A buffer descriptor is an implementation-defined opaque data returned by
* createDescriptor. It describes the properties of a buffer and is consumed
* by the allocator.
*/
typedef vec<uint32_t> BufferDescriptor;
enum FlexComponent : int32_t {
Y = 1 << 0, /** luma */
CB = 1 << 1, /** chroma blue */
CR = 1 << 2, /** chroma red */
R = 1 << 10, /** red */
G = 1 << 11, /** green */
B = 1 << 12, /** blue */
A = 1 << 30, /** alpha */
/**
* Structure for describing YCbCr formats for consumption by applications.
* This is used with PixelFormat::YCBCR_*_888.
*
* Buffer chroma subsampling is defined in the format.
* e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0.
*
* Buffers must have a 8 bit depth.
*
* y, cb, and cr point to the first byte of their respective planes.
*
* Stride describes the distance in bytes from the first value of one row of
* the image to the first value of the next row. It includes the width of the
* image plus padding.
* yStride is the stride of the luma plane.
* cStride is the stride of the chroma planes.
*
* chromaStep is the distance in bytes from one chroma pixel value to the
* next. This is 2 bytes for semiplanar (because chroma values are interleaved
* and each chroma value is one byte) and 1 for planar.
*/
struct YCbCrLayout {
pointer y;
pointer cb;
pointer cr;
uint32_t yStride;
uint32_t cStride;
uint32_t chromaStep;
};
enum FlexFormat : int32_t {
/** not a flexible format */
INVALID = 0x0,
Y = FlexComponent:Y,
YCBCR = Y | FlexComponent:CB | FlexComponent:CR,
YCBCRA = YCBCR | FlexComponent:A,
RGB = FlexComponent:R | FlexComponent:G | FlexComponent:B,
RGBA = RGB | FlexComponent:A,
};
struct FlexPlane {
/** Pointer to the first byte of the top-left pixel of the plane. */
pointer topLeft;
FlexComponent component;
/**
* Bits allocated for the component in each pixel. Must be a positive
* multiple of 8.
*/
int32_t bitsPerComponent;
/**
* Number of the most significant bits used in the format for this
* component. Must be between 1 and bitsPerComponent, inclusive.
*/
int32_t bitsUsed;
/** Horizontal increment. */
int32_t hIncrement;
/** Vertical increment. */
int32_t vIncrement;
/** Horizontal subsampling. Must be a positive power of 2. */
int32_t hSubsampling;
/** Vertical subsampling. Must be a positive power of 2. */
int32_t vSubsampling;
};
struct FlexLayout {
/** The kind of flexible format. */
FlexFormat format;
/**
* A plane for each component; ordered in increasing component value
* order. E.g. FlexFormat::RGBA maps 0 -> R, 1 -> G, etc. Can have size 0
* for FlexFormat::INVALID.
*/
vec<FlexPlane> planes;
};
/** Backing store ID of a buffer. See IMapper::getBackingStore. */
typedef uint64_t BackingStore;

View File

@@ -24,7 +24,6 @@ cc_library_static {
],
static_libs: [
"VtsHalHidlTargetTestBase",
"libVtsHalGraphicsAllocatorTestUtils",
],
cflags: [
"-Wall",
@@ -54,7 +53,6 @@ cc_test {
"android.hardware.graphics.common@1.0",
],
static_libs: [
"libVtsHalGraphicsAllocatorTestUtils",
"libVtsHalGraphicsMapperTestUtils",
"VtsHalHidlTargetTestBase",
],

View File

@@ -25,228 +25,233 @@ namespace mapper {
namespace V2_0 {
namespace tests {
using android::hardware::graphics::allocator::V2_0::Buffer;
using android::hardware::graphics::allocator::V2_0::BufferDescriptor;
using android::hardware::graphics::allocator::V2_0::Error;
Mapper::Mapper() { init(); }
void Mapper::init() {
mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>();
ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
Gralloc::Gralloc() {
init();
}
Mapper::~Mapper() {
for (auto it : mHandles) {
while (it.second) {
EXPECT_EQ(Error::NONE, mMapper->release(it.first))
<< "failed to release handle " << it.first;
it.second--;
void Gralloc::init() {
mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>();
ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>();
ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
}
Gralloc::~Gralloc() {
for (auto bufferHandle : mClonedBuffers) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
native_handle_close(buffer);
native_handle_delete(buffer);
}
}
mHandles.clear();
mClonedBuffers.clear();
for (auto bufferHandle : mImportedBuffers) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer))
<< "failed to free buffer " << buffer;
}
mImportedBuffers.clear();
}
sp<IMapper> Mapper::getRaw() const { return mMapper; }
void Mapper::retain(const native_handle_t* handle) {
Error error = mMapper->retain(handle);
ASSERT_EQ(Error::NONE, error) << "failed to retain handle " << handle;
mHandles[handle]++;
sp<IAllocator> Gralloc::getAllocator() const {
return mAllocator;
}
void Mapper::release(const native_handle_t* handle) {
Error error = mMapper->release(handle);
ASSERT_EQ(Error::NONE, error) << "failed to release handle " << handle;
std::string Gralloc::dumpDebugInfo() {
std::string debugInfo;
mAllocator->dumpDebugInfo(
[&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
if (--mHandles[handle] == 0) {
mHandles.erase(handle);
}
return debugInfo;
}
Mapper::Dimensions Mapper::getDimensions(const native_handle_t* handle) {
Dimensions dimensions = {};
mMapper->getDimensions(handle, [&](const auto& tmpError, const auto& tmpWidth,
const auto& tmpHeight) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to get dimensions for handle " << handle;
dimensions.width = tmpWidth;
dimensions.height = tmpHeight;
});
const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
const native_handle_t* bufferHandle =
native_handle_clone(rawHandle.getNativeHandle());
EXPECT_NE(nullptr, bufferHandle);
return dimensions;
if (bufferHandle) {
mClonedBuffers.insert(bufferHandle);
}
return bufferHandle;
}
PixelFormat Mapper::getFormat(const native_handle_t* handle) {
PixelFormat format = static_cast<PixelFormat>(0);
mMapper->getFormat(handle, [&](const auto& tmpError, const auto& tmpFormat) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to get format for handle " << handle;
format = tmpFormat;
});
std::vector<const native_handle_t*> Gralloc::allocate(
const BufferDescriptor& descriptor, uint32_t count, bool import,
uint32_t* outStride) {
std::vector<const native_handle_t*> bufferHandles;
bufferHandles.reserve(count);
mAllocator->allocate(
descriptor, count, [&](const auto& tmpError, const auto& tmpStride,
const auto& tmpBuffers) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
return format;
for (uint32_t i = 0; i < count; i++) {
if (import) {
ASSERT_NO_FATAL_FAILURE(
bufferHandles.push_back(importBuffer(tmpBuffers[i])));
} else {
ASSERT_NO_FATAL_FAILURE(
bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
}
}
if (outStride) {
*outStride = tmpStride;
}
});
if (::testing::Test::HasFatalFailure()) {
bufferHandles.clear();
}
return bufferHandles;
}
uint32_t Mapper::getLayerCount(const native_handle_t* handle) {
uint32_t count = 0;
mMapper->getLayerCount(
handle, [&](const auto& tmpError, const auto& tmpCount) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to get layer count for handle " << handle;
count = tmpCount;
});
const native_handle_t* Gralloc::allocate(
const IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
uint32_t* outStride) {
BufferDescriptor descriptor = createDescriptor(descriptorInfo);
if (::testing::Test::HasFatalFailure()) {
return nullptr;
}
return count;
auto buffers = allocate(descriptor, 1, import, outStride);
if (::testing::Test::HasFatalFailure()) {
return nullptr;
}
return buffers[0];
}
uint64_t Mapper::getProducerUsageMask(const native_handle_t* handle) {
uint64_t usageMask = 0;
mMapper->getProducerUsageMask(
handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to get producer usage mask for handle " << handle;
usageMask = tmpUsageMask;
});
return usageMask;
sp<IMapper> Gralloc::getMapper() const {
return mMapper;
}
uint64_t Mapper::getConsumerUsageMask(const native_handle_t* handle) {
uint64_t usageMask = 0;
mMapper->getConsumerUsageMask(
handle, [&](const auto& tmpError, const auto& tmpUsageMask) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to get consumer usage mask for handle " << handle;
usageMask = tmpUsageMask;
});
BufferDescriptor Gralloc::createDescriptor(
const IMapper::BufferDescriptorInfo& descriptorInfo) {
BufferDescriptor descriptor;
mMapper->createDescriptor(
descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
descriptor = tmpDescriptor;
});
return usageMask;
return descriptor;
}
BackingStore Mapper::getBackingStore(const native_handle_t* handle) {
BackingStore backingStore = 0;
mMapper->getBackingStore(
handle, [&](const auto& tmpError, const auto& tmpBackingStore) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to get backing store for handle " << handle;
backingStore = tmpBackingStore;
});
const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) {
const native_handle_t* bufferHandle = nullptr;
mMapper->importBuffer(
rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to import buffer %p"
<< rawHandle.getNativeHandle();
bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
});
return backingStore;
if (bufferHandle) {
mImportedBuffers.insert(bufferHandle);
}
return bufferHandle;
}
uint32_t Mapper::getStride(const native_handle_t* handle) {
uint32_t stride = 0;
mMapper->getStride(handle, [&](const auto& tmpError, const auto& tmpStride) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to get stride for handle " << handle;
stride = tmpStride;
});
void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
return stride;
if (mImportedBuffers.erase(bufferHandle)) {
Error error = mMapper->freeBuffer(buffer);
ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer;
} else {
mClonedBuffers.erase(bufferHandle);
native_handle_close(buffer);
native_handle_delete(buffer);
}
}
void* Mapper::lock(const native_handle_t* handle, uint64_t producerUsageMask,
uint64_t consumerUsageMask,
const IMapper::Rect& accessRegion, int acquireFence) {
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
native_handle_t* acquireFenceHandle = nullptr;
if (acquireFence >= 0) {
acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
acquireFenceHandle->data[0] = acquireFence;
}
void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int acquireFence) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
void* data = nullptr;
mMapper->lock(
handle, producerUsageMask, consumerUsageMask, accessRegion,
acquireFenceHandle, [&](const auto& tmpError, const auto& tmpData) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to lock handle " << handle;
data = tmpData;
});
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
hidl_handle acquireFenceHandle;
if (acquireFence >= 0) {
auto h = native_handle_init(acquireFenceStorage, 1, 0);
h->data[0] = acquireFence;
acquireFenceHandle = h;
}
if (acquireFence >= 0) {
close(acquireFence);
}
return data;
}
FlexLayout Mapper::lockFlex(const native_handle_t* handle,
uint64_t producerUsageMask,
uint64_t consumerUsageMask,
const IMapper::Rect& accessRegion,
int acquireFence) {
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 0, 1);
native_handle_t* acquireFenceHandle = nullptr;
if (acquireFence >= 0) {
acquireFenceHandle = native_handle_init(acquireFenceStorage, 0, 1);
acquireFenceHandle->data[0] = acquireFence;
}
FlexLayout layout = {};
mMapper->lockFlex(handle, producerUsageMask, consumerUsageMask, accessRegion,
acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpLayout) {
void* data = nullptr;
mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpData) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to lockFlex handle " << handle;
layout = tmpLayout;
});
<< "failed to lock buffer " << buffer;
data = tmpData;
});
if (acquireFence >= 0) {
close(acquireFence);
}
return layout;
}
int Mapper::unlock(const native_handle_t* handle) {
int releaseFence = -1;
mMapper->unlock(handle, [&](const auto& tmpError,
const auto& tmpReleaseFence) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock handle " << handle;
auto handle = tmpReleaseFence.getNativeHandle();
if (handle) {
ASSERT_EQ(0, handle->numInts) << "invalid fence handle " << handle;
if (handle->numFds == 1) {
releaseFence = dup(handle->data[0]);
ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
} else {
ASSERT_EQ(0, handle->numFds) << " invalid fence handle " << handle;
}
if (acquireFence >= 0) {
close(acquireFence);
}
});
return releaseFence;
return data;
}
const native_handle_t* Mapper::allocate(
std::unique_ptr<AllocatorClient>& allocatorClient,
const IAllocatorClient::BufferDescriptorInfo& info) {
BufferDescriptor descriptor = allocatorClient->createDescriptor(info);
if (::testing::Test::HasFatalFailure()) {
return nullptr;
}
YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle,
uint64_t cpuUsage,
const IMapper::Rect& accessRegion,
int acquireFence) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
Buffer buffer = allocatorClient->allocate(descriptor);
if (::testing::Test::HasFatalFailure()) {
allocatorClient->destroyDescriptor(descriptor);
return nullptr;
}
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
hidl_handle acquireFenceHandle;
if (acquireFence >= 0) {
auto h = native_handle_init(acquireFenceStorage, 1, 0);
h->data[0] = acquireFence;
acquireFenceHandle = h;
}
const native_handle_t* handle =
allocatorClient->exportHandle(descriptor, buffer);
if (handle) {
retain(handle);
}
YCbCrLayout layout = {};
mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpLayout) {
ASSERT_EQ(Error::NONE, tmpError)
<< "failed to lockYCbCr buffer " << buffer;
layout = tmpLayout;
});
allocatorClient->free(buffer);
allocatorClient->destroyDescriptor(descriptor);
if (acquireFence >= 0) {
close(acquireFence);
}
return handle;
return layout;
}
int Gralloc::unlock(const native_handle_t* bufferHandle) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
int releaseFence = -1;
mMapper->unlock(
buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer "
<< buffer;
auto fenceHandle = tmpReleaseFence.getNativeHandle();
if (fenceHandle) {
ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle "
<< fenceHandle;
if (fenceHandle->numFds == 1) {
releaseFence = dup(fenceHandle->data[0]);
ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
} else {
ASSERT_EQ(0, fenceHandle->numFds)
<< " invalid fence handle " << fenceHandle;
}
}
});
return releaseFence;
}
} // namespace tests

View File

@@ -17,14 +17,12 @@
#ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS
#define VTS_HAL_GRAPHICS_MAPPER_UTILS
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <utils/StrongPointer.h>
#include "VtsHalGraphicsAllocatorTestUtils.h"
namespace android {
namespace hardware {
namespace graphics {
@@ -32,59 +30,62 @@ namespace mapper {
namespace V2_0 {
namespace tests {
using android::hardware::graphics::common::V1_0::PixelFormat;
using android::hardware::graphics::allocator::V2_0::IAllocatorClient;
using android::hardware::graphics::allocator::V2_0::tests::AllocatorClient;
using android::hardware::graphics::allocator::V2_0::IAllocator;
// A wrapper to IMapper.
class Mapper {
public:
Mapper();
~Mapper();
// A wrapper to IAllocator and IMapper.
class Gralloc {
public:
Gralloc();
~Gralloc();
sp<IMapper> getRaw() const;
// IAllocator methods
void retain(const native_handle_t* handle);
void release(const native_handle_t* handle);
sp<IAllocator> getAllocator() const;
struct Dimensions {
uint32_t width;
uint32_t height;
};
Dimensions getDimensions(const native_handle_t* handle);
std::string dumpDebugInfo();
PixelFormat getFormat(const native_handle_t* handle);
uint32_t getLayerCount(const native_handle_t* handle);
uint64_t getProducerUsageMask(const native_handle_t* handle);
uint64_t getConsumerUsageMask(const native_handle_t* handle);
BackingStore getBackingStore(const native_handle_t* handle);
uint32_t getStride(const native_handle_t* handle);
// When import is false, this simply calls IAllocator::allocate. When import
// is true, the returned buffers are also imported into the mapper.
//
// Either case, the returned buffers must be freed with freeBuffer.
std::vector<const native_handle_t*> allocate(
const BufferDescriptor& descriptor, uint32_t count, bool import = true,
uint32_t* outStride = nullptr);
const native_handle_t* allocate(
const IMapper::BufferDescriptorInfo& descriptorInfo, bool import = true,
uint32_t* outStride = nullptr);
// We use fd instead of hidl_handle in these functions to pass fences
// in and out of the mapper. The ownership of the fd is always transferred
// with each of these functions.
void* lock(const native_handle_t* handle, uint64_t producerUsageMask,
uint64_t consumerUsageMask, const IMapper::Rect& accessRegion,
int acquireFence);
FlexLayout lockFlex(const native_handle_t* handle, uint64_t producerUsageMask,
uint64_t consumerUsageMask,
const IMapper::Rect& accessRegion, int acquireFence);
int unlock(const native_handle_t* handle);
// IMapper methods
// Requests AllocatorClient to allocate a buffer, export the handle, and
// register the handle with mapper.
const native_handle_t* allocate(
std::unique_ptr<AllocatorClient>& allocatorClient,
const IAllocatorClient::BufferDescriptorInfo& info);
sp<IMapper> getMapper() const;
private:
void init();
BufferDescriptor createDescriptor(
const IMapper::BufferDescriptorInfo& descriptorInfo);
sp<IMapper> mMapper;
const native_handle_t* importBuffer(const hidl_handle& rawHandle);
void freeBuffer(const native_handle_t* bufferHandle);
// Keep track of all registered (retained) handles. When a test fails with
// ASSERT_*, the destructor will release the handles for the test.
std::unordered_map<const native_handle_t*, uint64_t> mHandles;
// We use fd instead of hidl_handle in these functions to pass fences
// in and out of the mapper. The ownership of the fd is always transferred
// with each of these functions.
void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, int acquireFence);
YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle,
uint64_t cpuUsage, const IMapper::Rect& accessRegion,
int acquireFence);
int unlock(const native_handle_t* bufferHandle);
private:
void init();
const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
sp<IAllocator> mAllocator;
sp<IMapper> mMapper;
// Keep track of all cloned and imported handles. When a test fails with
// ASSERT_*, the destructor will free the handles for the test.
std::unordered_set<const native_handle_t*> mClonedBuffers;
std::unordered_set<const native_handle_t*> mImportedBuffers;
};
} // namespace tests

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
#define LOG_TAG "graphics_mapper_hidl_hal_test"
#define LOG_TAG "VtsHalGraphicsMapperV2_0TargetTest"
#include <android-base/logging.h>
#include <VtsHalHidlTargetTestBase.h>
#include <android-base/logging.h>
#include <sync/sync.h>
#include "VtsHalGraphicsMapperTestUtils.h"
@@ -29,202 +29,384 @@ namespace V2_0 {
namespace tests {
namespace {
using namespace android::hardware::graphics::allocator::V2_0;
using namespace android::hardware::graphics::allocator::V2_0::tests;
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::PixelFormat;
class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
protected:
void SetUp() override {
ASSERT_NO_FATAL_FAILURE(mAllocator = std::make_unique<Allocator>());
ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient());
ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique<Mapper>());
ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
mDummyDescriptorInfo.width = 64;
mDummyDescriptorInfo.height = 64;
mDummyDescriptorInfo.layerCount = 1;
mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
mDummyDescriptorInfo.producerUsageMask =
static_cast<uint64_t>(ProducerUsage::CPU_WRITE);
mDummyDescriptorInfo.consumerUsageMask =
static_cast<uint64_t>(ConsumerUsage::CPU_READ);
mDummyDescriptorInfo.width = 64;
mDummyDescriptorInfo.height = 64;
mDummyDescriptorInfo.layerCount = 1;
mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
mDummyDescriptorInfo.usage = static_cast<uint64_t>(
BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
}
void TearDown() override {}
std::unique_ptr<Allocator> mAllocator;
std::unique_ptr<AllocatorClient> mAllocatorClient;
std::unique_ptr<Mapper> mMapper;
IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{};
std::unique_ptr<Gralloc> mGralloc;
IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
};
/**
* Test IMapper::retain and IMapper::release.
* Test IAllocator::dumpDebugInfo by calling it.
*/
TEST_F(GraphicsMapperHidlTest, RetainRelease) {
const native_handle_t* buffer;
ASSERT_NO_FATAL_FAILURE(
buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
const int maxRefs = 10;
for (int i = 0; i < maxRefs; i++) {
ASSERT_NO_FATAL_FAILURE(mMapper->retain(buffer));
}
for (int i = 0; i < maxRefs; i++) {
ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
}
ASSERT_NO_FATAL_FAILURE(mMapper->release(buffer));
TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
mGralloc->dumpDebugInfo();
}
/**
* Test IMapper::get* getters.
* Test IAllocator::allocate with valid buffer descriptors.
*/
TEST_F(GraphicsMapperHidlTest, Getters) {
const native_handle_t* buffer;
ASSERT_NO_FATAL_FAILURE(
buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
BufferDescriptor descriptor;
ASSERT_NO_FATAL_FAILURE(
descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
IAllocatorClient::BufferDescriptorInfo info = {};
for (uint32_t count = 0; count < 5; count++) {
std::vector<const native_handle_t*> bufferHandles;
uint32_t stride;
ASSERT_NO_FATAL_FAILURE(bufferHandles = mGralloc->allocate(
descriptor, count, false, &stride));
Mapper::Dimensions dimensions;
ASSERT_NO_FATAL_FAILURE(dimensions = mMapper->getDimensions(buffer));
info.width = dimensions.width;
info.height = dimensions.height;
if (count >= 1) {
EXPECT_LE(mDummyDescriptorInfo.width, stride)
<< "invalid buffer stride";
}
ASSERT_NO_FATAL_FAILURE(info.format = mMapper->getFormat(buffer));
ASSERT_NO_FATAL_FAILURE(info.producerUsageMask =
mMapper->getProducerUsageMask(buffer));
ASSERT_NO_FATAL_FAILURE(info.consumerUsageMask =
mMapper->getConsumerUsageMask(buffer));
for (auto bufferHandle : bufferHandles) {
mGralloc->freeBuffer(bufferHandle);
}
}
}
EXPECT_EQ(mDummyDescriptorInfo.width, info.width);
EXPECT_EQ(mDummyDescriptorInfo.height, info.height);
EXPECT_EQ(mDummyDescriptorInfo.format, info.format);
EXPECT_EQ(mDummyDescriptorInfo.producerUsageMask, info.producerUsageMask);
EXPECT_EQ(mDummyDescriptorInfo.consumerUsageMask, info.consumerUsageMask);
/**
* Test IAllocator::allocate with invalid buffer descriptors.
*/
TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
// this assumes any valid descriptor is non-empty
BufferDescriptor descriptor;
mGralloc->getAllocator()->allocate(
descriptor, 1, [&](const auto& tmpError, const auto&, const auto&) {
EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
});
}
ASSERT_NO_FATAL_FAILURE(mMapper->getBackingStore(buffer));
/**
* Test IAllocator::allocate does not leak.
*/
TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
uint32_t stride;
ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
EXPECT_LE(info.width, stride);
for (int i = 0; i < 2048; i++) {
auto bufferHandle = mGralloc->allocate(info, false);
mGralloc->freeBuffer(bufferHandle);
}
}
/**
* Test IMapper::createDescriptor with valid descriptor info.
*/
TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
}
/**
* Test IMapper::createDescriptor with invalid descriptor info.
*/
TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
auto info = mDummyDescriptorInfo;
info.width = 0;
mGralloc->getMapper()->createDescriptor(
info, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_VALUE, tmpError)
<< "createDescriptor did not fail with BAD_VALUE";
});
}
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
*/
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
const native_handle_t* bufferHandle;
ASSERT_NO_FATAL_FAILURE(bufferHandle =
mGralloc->allocate(mDummyDescriptorInfo, true));
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
}
/**
* Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
*/
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
const native_handle_t* clonedBufferHandle;
ASSERT_NO_FATAL_FAILURE(
clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
// A cloned handle is a raw handle. Check that we can import it multiple
// times.
const native_handle_t* importedBufferHandles[2];
ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] =
mGralloc->importBuffer(clonedBufferHandle));
ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] =
mGralloc->importBuffer(clonedBufferHandle));
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
}
/**
* Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
*/
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
const native_handle_t* rawHandle;
ASSERT_NO_FATAL_FAILURE(
rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
native_handle_t* importedHandle = nullptr;
mGralloc->getMapper()->importBuffer(
rawHandle, [&](const auto& tmpError, const auto& buffer) {
ASSERT_EQ(Error::NONE, tmpError);
importedHandle = static_cast<native_handle_t*>(buffer);
});
// free the imported handle with another mapper
std::unique_ptr<Gralloc> anotherGralloc;
ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique<Gralloc>());
Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
ASSERT_EQ(Error::NONE, error);
ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
}
/**
* Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
*/
TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
auto info = mDummyDescriptorInfo;
info.width = 1024;
info.height = 1024;
for (int i = 0; i < 2048; i++) {
auto bufferHandle = mGralloc->allocate(info, true);
mGralloc->freeBuffer(bufferHandle);
}
}
/**
* Test IMapper::importBuffer with invalid buffers.
*/
TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->importBuffer(
invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
<< "importBuffer with nullptr did not fail with BAD_BUFFER";
});
invalidHandle = native_handle_create(0, 0);
mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError,
const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
<< "importBuffer with invalid handle did not fail with BAD_BUFFER";
});
native_handle_delete(invalidHandle);
const native_handle_t* importedHandle;
ASSERT_NO_FATAL_FAILURE(importedHandle =
mGralloc->allocate(mDummyDescriptorInfo, true));
mGralloc->getMapper()->importBuffer(
importedHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
<< "importBuffer with an "
"already imported handle did "
"not fail with BAD_BUFFER";
});
mGralloc->freeBuffer(importedHandle);
}
/**
* Test IMapper::freeBuffer with invalid buffers.
*/
TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
native_handle_t* invalidHandle = nullptr;
Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
EXPECT_EQ(Error::BAD_BUFFER, error)
<< "freeBuffer with nullptr did not fail with BAD_BUFFER";
invalidHandle = native_handle_create(0, 0);
error = mGralloc->getMapper()->freeBuffer(invalidHandle);
EXPECT_EQ(Error::BAD_BUFFER, error)
<< "freeBuffer with invalid handle did not fail with BAD_BUFFER";
native_handle_delete(invalidHandle);
const native_handle_t* clonedBufferHandle;
ASSERT_NO_FATAL_FAILURE(
clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
error = mGralloc->getMapper()->freeBuffer(invalidHandle);
EXPECT_EQ(Error::BAD_BUFFER, error)
<< "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
mGralloc->freeBuffer(clonedBufferHandle);
}
/**
* Test IMapper::lock and IMapper::unlock.
*/
TEST_F(GraphicsMapperHidlTest, LockBasic) {
const auto& info = mDummyDescriptorInfo;
TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
const auto& info = mDummyDescriptorInfo;
const native_handle_t* buffer;
ASSERT_NO_FATAL_FAILURE(
buffer = mMapper->allocate(mAllocatorClient, mDummyDescriptorInfo));
const native_handle_t* bufferHandle;
uint32_t stride;
ASSERT_NO_FATAL_FAILURE(bufferHandle =
mGralloc->allocate(info, true, &stride));
uint32_t stride;
ASSERT_NO_FATAL_FAILURE(stride = mMapper->getStride(buffer));
// lock buffer for writing
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
static_cast<int32_t>(info.height)};
int fence = -1;
uint8_t* data;
ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
bufferHandle, info.usage, region, fence)));
// lock buffer for writing
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
static_cast<int32_t>(info.height)};
int fence = -1;
uint32_t* data;
ASSERT_NO_FATAL_FAILURE(
data = static_cast<uint32_t*>(
mMapper->lock(buffer, info.producerUsageMask, 0, region, fence)));
// RGBA_8888
size_t strideInBytes = stride * 4;
size_t writeInBytes = info.width * 4;
for (uint32_t y = 0; y < info.height; y++) {
for (uint32_t x = 0; x < info.width; x++) {
data[stride * y + x] = info.height * y + x;
for (uint32_t y = 0; y < info.height; y++) {
memset(data, y, writeInBytes);
data += strideInBytes;
}
}
ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
// lock buffer for reading
ASSERT_NO_FATAL_FAILURE(
data = static_cast<uint32_t*>(
mMapper->lock(buffer, 0, info.consumerUsageMask, region, fence)));
for (uint32_t y = 0; y < info.height; y++) {
for (uint32_t x = 0; x < info.width; x++) {
EXPECT_EQ(info.height * y + x, data[stride * y + x]);
// lock again for reading
ASSERT_NO_FATAL_FAILURE(data = static_cast<uint8_t*>(mGralloc->lock(
bufferHandle, info.usage, region, fence)));
for (uint32_t y = 0; y < info.height; y++) {
for (size_t i = 0; i < writeInBytes; i++) {
EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
}
data += strideInBytes;
}
}
ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
if (fence >= 0) {
close(fence);
}
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
if (fence >= 0) {
close(fence);
}
}
/**
* Test IMapper::lockFlex. This locks a YV12 buffer, and makes sure we can
* Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can
* write to and read from it.
*/
TEST_F(GraphicsMapperHidlTest, LockFlexBasic) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YV12;
TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
auto info = mDummyDescriptorInfo;
info.format = PixelFormat::YV12;
const native_handle_t* buffer;
ASSERT_NO_FATAL_FAILURE(buffer = mMapper->allocate(mAllocatorClient, info));
const native_handle_t* bufferHandle;
uint32_t stride;
ASSERT_NO_FATAL_FAILURE(bufferHandle =
mGralloc->allocate(info, true, &stride));
// lock buffer for writing
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
static_cast<int32_t>(info.height)};
int fence = -1;
FlexLayout layout;
ASSERT_NO_FATAL_FAILURE(
layout =
mMapper->lockFlex(buffer, info.producerUsageMask, 0, region, fence));
ASSERT_EQ(FlexFormat::YCBCR, layout.format);
ASSERT_EQ(3u, layout.planes.size());
// lock buffer for writing
const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
static_cast<int32_t>(info.height)};
int fence = -1;
YCbCrLayout layout;
ASSERT_NO_FATAL_FAILURE(
layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
const auto y_stride = layout.planes[0].vIncrement;
const auto c_stride = layout.planes[1].vIncrement;
auto y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
auto cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
auto cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
auto yData = static_cast<uint8_t*>(layout.y);
auto cbData = static_cast<uint8_t*>(layout.cb);
auto crData = static_cast<uint8_t*>(layout.cr);
for (uint32_t y = 0; y < info.height; y++) {
for (uint32_t x = 0; x < info.width; x++) {
auto val = static_cast<uint8_t>(info.height * y + x);
for (uint32_t y = 0; y < info.height; y++) {
for (uint32_t x = 0; x < info.width; x++) {
auto val = static_cast<uint8_t>(info.height * y + x);
y_data[y_stride * y + x] = val;
if (y % 2 == 0 && x % 2 == 0) {
cb_data[c_stride * y / 2 + x / 2] = val;
cr_data[c_stride * y / 2 + x / 2] = val;
}
yData[layout.yStride * y + x] = val;
if (y % 2 == 0 && x % 2 == 0) {
cbData[layout.cStride * y / 2 + x / 2] = val;
crData[layout.cStride * y / 2 + x / 2] = val;
}
}
}
}
ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
// lock buffer for reading
ASSERT_NO_FATAL_FAILURE(
layout =
mMapper->lockFlex(buffer, 0, info.consumerUsageMask, region, fence));
// lock again for reading
ASSERT_NO_FATAL_FAILURE(
layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
y_data = static_cast<uint8_t*>(layout.planes[0].topLeft);
cb_data = static_cast<uint8_t*>(layout.planes[1].topLeft);
cr_data = static_cast<uint8_t*>(layout.planes[2].topLeft);
for (uint32_t y = 0; y < info.height; y++) {
for (uint32_t x = 0; x < info.width; x++) {
auto val = static_cast<uint8_t>(info.height * y + x);
yData = static_cast<uint8_t*>(layout.y);
cbData = static_cast<uint8_t*>(layout.cb);
crData = static_cast<uint8_t*>(layout.cr);
for (uint32_t y = 0; y < info.height; y++) {
for (uint32_t x = 0; x < info.width; x++) {
auto val = static_cast<uint8_t>(info.height * y + x);
EXPECT_EQ(val, y_data[y_stride * y + x]);
if (y % 2 == 0 && x % 2 == 0) {
EXPECT_EQ(val, cb_data[c_stride * y / 2 + x / 2]);
EXPECT_EQ(val, cr_data[c_stride * y / 2 + x / 2]);
}
EXPECT_EQ(val, yData[layout.yStride * y + x]);
if (y % 2 == 0 && x % 2 == 0) {
EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]);
EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]);
}
}
}
}
ASSERT_NO_FATAL_FAILURE(fence = mMapper->unlock(buffer));
if (fence >= 0) {
close(fence);
}
ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
if (fence >= 0) {
close(fence);
}
}
} // namespace anonymous
/**
* Test IMapper::unlock with invalid buffers.
*/
TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
native_handle_t* invalidHandle = nullptr;
mGralloc->getMapper()->unlock(
invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
<< "unlock with nullptr did not fail with BAD_BUFFER";
});
invalidHandle = native_handle_create(0, 0);
mGralloc->getMapper()->unlock(
invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
<< "unlock with invalid handle did not fail with BAD_BUFFER";
});
native_handle_delete(invalidHandle);
ASSERT_NO_FATAL_FAILURE(invalidHandle =
const_cast<native_handle_t*>(mGralloc->allocate(
mDummyDescriptorInfo, false)));
mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError,
const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
<< "unlock with un-imported handle did not fail with BAD_BUFFER";
});
mGralloc->freeBuffer(invalidHandle);
// disabled as it fails on many existing drivers
#if 0
ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
mGralloc->allocate(mDummyDescriptorInfo, true)));
mGralloc->getMapper()->unlock(
invalidHandle, [&](const auto& tmpError, const auto&) {
EXPECT_EQ(Error::BAD_BUFFER, tmpError)
<< "unlock with unlocked handle did not fail with BAD_BUFFER";
});
mGralloc->freeBuffer(invalidHandle);
#endif
}
} // namespace
} // namespace tests
} // namespace V2_0
} // namespace mapper