mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 11:36:00 +00:00
Merge "graphics: revise gralloc interfaces" into oc-dev
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
144
graphics/allocator/2.0/default/Gralloc0Allocator.cpp
Normal file
144
graphics/allocator/2.0/default/Gralloc0Allocator.cpp
Normal 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
|
||||
59
graphics/allocator/2.0/default/Gralloc0Allocator.h
Normal file
59
graphics/allocator/2.0/default/Gralloc0Allocator.h
Normal 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
|
||||
321
graphics/allocator/2.0/default/Gralloc1Allocator.cpp
Normal file
321
graphics/allocator/2.0/default/Gralloc1Allocator.cpp
Normal 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
|
||||
89
graphics/allocator/2.0/default/Gralloc1Allocator.h
Normal file
89
graphics/allocator/2.0/default/Gralloc1Allocator.h
Normal 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
|
||||
@@ -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;
|
||||
@@ -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",
|
||||
]
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
#
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -52,7 +52,6 @@ cc_test {
|
||||
],
|
||||
static_libs: [
|
||||
"libhwcomposer-command-buffer",
|
||||
"libVtsHalGraphicsAllocatorTestUtils",
|
||||
"libVtsHalGraphicsComposerTestUtils",
|
||||
"libVtsHalGraphicsMapperTestUtils",
|
||||
"VtsHalHidlTargetTestBase",
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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: ["."],
|
||||
}
|
||||
|
||||
156
graphics/mapper/2.0/default/Gralloc0Mapper.cpp
Normal file
156
graphics/mapper/2.0/default/Gralloc0Mapper.cpp
Normal 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
|
||||
56
graphics/mapper/2.0/default/Gralloc0Mapper.h
Normal file
56
graphics/mapper/2.0/default/Gralloc0Mapper.h
Normal 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
|
||||
273
graphics/mapper/2.0/default/Gralloc1Mapper.cpp
Normal file
273
graphics/mapper/2.0/default/Gralloc1Mapper.cpp
Normal 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
|
||||
76
graphics/mapper/2.0/default/Gralloc1Mapper.h
Normal file
76
graphics/mapper/2.0/default/Gralloc1Mapper.h
Normal 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
|
||||
79
graphics/mapper/2.0/default/GrallocBufferDescriptor.h
Normal file
79
graphics/mapper/2.0/default/GrallocBufferDescriptor.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
],
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user