diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.cpp b/automotive/evs/1.0/vts/functional/FrameHandler.cpp index 01d9a0e304..58c2f262e3 100644 --- a/automotive/evs/1.0/vts/functional/FrameHandler.cpp +++ b/automotive/evs/1.0/vts/functional/FrameHandler.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include // std::min @@ -135,11 +134,7 @@ Return 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 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 result = mDisplay->returnTargetBufferForDisplay(tgtBuffer); @@ -183,10 +173,6 @@ Return 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 tgt = new android::GraphicBuffer( + tgtBuffer.memHandle, android::GraphicBuffer::CLONE_HANDLE, + tgtBuffer.width, tgtBuffer.height, tgtBuffer.format, 1, tgtBuffer.usage, + tgtBuffer.stride); + sp 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 pGfxBuff = new android::GraphicBuffer( - buffer.width, buffer.height, buffer.format, - 1, /* we always use exactly one layer */ - buffer.usage, buffer.stride, - const_cast(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); -} diff --git a/automotive/evs/1.0/vts/functional/FrameHandler.h b/automotive/evs/1.0/vts/functional/FrameHandler.h index d5c3f6bfde..17a39803fa 100644 --- a/automotive/evs/1.0/vts/functional/FrameHandler.h +++ b/automotive/evs/1.0/vts/functional/FrameHandler.h @@ -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 mCamera; diff --git a/camera/device/1.0/Android.bp b/camera/device/1.0/Android.bp index 44a108ce29..81e41aa0af 100644 --- a/camera/device/1.0/Android.bp +++ b/camera/device/1.0/Android.bp @@ -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", ], diff --git a/camera/device/1.0/ICameraDevicePreviewCallback.hal b/camera/device/1.0/ICameraDevicePreviewCallback.hal index 4c9b517265..54219811fc 100644 --- a/camera/device/1.0/ICameraDevicePreviewCallback.hal +++ b/camera/device/1.0/ICameraDevicePreviewCallback.hal @@ -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. diff --git a/camera/device/1.0/default/CameraDevice.cpp b/camera/device/1.0/default/CameraDevice.cpp index 6495f30222..cb20fec80f 100644 --- a/camera/device/1.0/default/CameraDevice.cpp +++ b/camera/device/1.0/default/CameraDevice.cpp @@ -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) { diff --git a/camera/device/3.2/Android.bp b/camera/device/3.2/Android.bp index fd7276f946..7807a857aa 100644 --- a/camera/device/3.2/Android.bp +++ b/camera/device/3.2/Android.bp @@ -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", ], diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp index 5b3024b238..5bb53c7d5f 100644 --- a/camera/device/3.2/default/CameraDeviceSession.cpp +++ b/camera/device/3.2/default/CameraDeviceSession.cpp @@ -650,7 +650,8 @@ Return 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); } } diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp index c7cc75ad4d..d878deb03d 100644 --- a/camera/device/3.2/default/convert.cpp +++ b/camera/device/3.2/default/convert.cpp @@ -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. diff --git a/camera/device/3.2/types.hal b/camera/device/3.2/types.hal index 5ae7a18c39..1632570953 100644 --- a/camera/device/3.2/types.hal +++ b/camera/device/3.2/types.hal @@ -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 CameraMetadata; -typedef bitfield ProducerUsageFlags; -typedef bitfield ConsumerUsageFlags; +typedef bitfield BufferUsageFlags; typedef bitfield 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 diff --git a/camera/provider/2.4/Android.bp b/camera/provider/2.4/Android.bp index 1656325edc..d295f3e0b5 100644 --- a/camera/provider/2.4/Android.bp +++ b/camera/provider/2.4/Android.bp @@ -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", ], diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 74e6efe6dc..e37f989c58 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -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 setCrop(int32_t left, int32_t top, int32_t right, int32_t bottom) override; - Return setUsage(ProducerUsage usage) override; + Return setUsage(BufferUsage usage) override; Return setSwapInterval(int32_t interval) override; @@ -408,7 +408,7 @@ Return PreviewWindowCb::setCrop(int32_t left, int32_t top, return mapToStatus(rc); } -Return PreviewWindowCb::setUsage(ProducerUsage usage) { +Return PreviewWindowCb::setUsage(BufferUsage usage) { auto rc = native_window_set_usage(mAnw.get(), static_cast(usage)); if (rc == ::android::OK) { mPreviewUsage = static_cast(usage); diff --git a/graphics/Android.bp b/graphics/Android.bp index f4f7db46d9..9aea85f6c4 100644 --- a/graphics/Android.bp +++ b/graphics/Android.bp @@ -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", diff --git a/graphics/allocator/2.0/Android.bp b/graphics/allocator/2.0/Android.bp index 271f2cecbc..f707468d25 100644 --- a/graphics/allocator/2.0/Android.bp +++ b/graphics/allocator/2.0/Android.bp @@ -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", ], } diff --git a/graphics/allocator/2.0/IAllocator.hal b/graphics/allocator/2.0/IAllocator.hal index bf0e141729..43a39169a8 100644 --- a/graphics/allocator/2.0/IAllocator.hal +++ b/graphics/allocator/2.0/IAllocator.hal @@ -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 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 buffers); }; diff --git a/graphics/allocator/2.0/IAllocatorClient.hal b/graphics/allocator/2.0/IAllocatorClient.hal deleted file mode 100644 index 8ca568f275..0000000000 --- a/graphics/allocator/2.0/IAllocatorClient.hal +++ /dev/null @@ -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 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 descriptors) - generates (Error error, - vec 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); -}; diff --git a/graphics/allocator/2.0/default/Android.bp b/graphics/allocator/2.0/default/Android.bp index 0baef89308..6adfa71f7b 100644 --- a/graphics/allocator/2.0/default/Android.bp +++ b/graphics/allocator/2.0/default/Android.bp @@ -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 { diff --git a/graphics/allocator/2.0/default/Gralloc.cpp b/graphics/allocator/2.0/default/Gralloc.cpp index 0b9e863eb5..273d3f5843 100644 --- a/graphics/allocator/2.0/default/Gralloc.cpp +++ b/graphics/allocator/2.0/default/Gralloc.cpp @@ -16,17 +16,11 @@ #define LOG_TAG "GrallocPassthrough" -#include -#include -#include -#include - -#include - -#include -#include - #include "Gralloc.h" +#include "Gralloc0Allocator.h" +#include "Gralloc1Allocator.h" + +#include 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 getCapabilities(getCapabilities_cb hidl_cb) override; - Return dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; - Return createClient(createClient_cb hidl_cb) override; - - Error createDescriptor( - const IAllocatorClient::BufferDescriptorInfo& descriptorInfo, - BufferDescriptor* outDescriptor); - Error destroyDescriptor(BufferDescriptor descriptor); - - Error testAllocate(const hidl_vec& descriptors); - Error allocate(const hidl_vec& descriptors, - hidl_vec* outBuffers); - Error free(Buffer buffer); - - Error exportHandle(Buffer buffer, const native_handle_t** outHandle); - -private: - void initCapabilities(); - - template - void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn); - void initDispatch(); - - bool hasCapability(Capability capability) const; - - gralloc1_device_t* mDevice; - - std::unordered_set 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 createDescriptor(const BufferDescriptorInfo& descriptorInfo, - createDescriptor_cb hidl_cb) override; - Return destroyDescriptor(BufferDescriptor descriptor) override; - - Return testAllocate( - const hidl_vec& descriptors) override; - Return allocate(const hidl_vec& descriptors, - allocate_cb hidl_cb) override; - Return free(Buffer buffer) override; - - Return exportHandle(BufferDescriptor descriptor, - Buffer buffer, exportHandle_cb hidl_cb) override; - -private: - GrallocHal& mHal; - - std::mutex mMutex; - std::unordered_set mDescriptors; - std::unordered_set 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 caps(count); - mDevice->getCapabilities(mDevice, &count, reinterpret_cast< - std::underlying_type::type*>(caps.data())); - caps.resize(count); - - mCapabilities.insert(caps.cbegin(), caps.cend()); -} - -template -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(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 GrallocHal::getCapabilities(getCapabilities_cb hidl_cb) -{ - std::vector caps( - mCapabilities.cbegin(), mCapabilities.cend()); - - hidl_vec reply; - reply.setToExternal(caps.data(), caps.size()); - hidl_cb(reply); - - return Void(); -} - -Return GrallocHal::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) -{ - uint32_t len = 0; - mDispatch.dump(mDevice, &len, nullptr); - - std::vector 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 GrallocHal::createClient(createClient_cb hidl_cb) -{ - sp 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(err); - } - - err = mDispatch.setDimensions(mDevice, descriptor, - descriptorInfo.width, descriptorInfo.height); - if (err == GRALLOC1_ERROR_NONE) { - err = mDispatch.setFormat(mDevice, descriptor, - static_cast(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(err); -} - -Error GrallocHal::destroyDescriptor(BufferDescriptor descriptor) -{ - int32_t err = mDispatch.destroyDescriptor(mDevice, descriptor); - return static_cast(err); -} - -Error GrallocHal::testAllocate(const hidl_vec& descriptors) -{ - if (!hasCapability(Capability::TEST_ALLOCATE)) { - return Error::UNDEFINED; - } - - int32_t err = mDispatch.allocate(mDevice, descriptors.size(), - descriptors.data(), nullptr); - return static_cast(err); -} - -Error GrallocHal::allocate(const hidl_vec& descriptors, - hidl_vec* outBuffers) -{ - std::vector 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( - reinterpret_cast(buffers[i])); - } - } - - return static_cast(err); -} - -Error GrallocHal::free(Buffer buffer) -{ - buffer_handle_t handle = reinterpret_cast( - static_cast(buffer)); - - int32_t err = mDispatch.release(mDevice, handle); - return static_cast(err); -} - -Error GrallocHal::exportHandle(Buffer buffer, - const native_handle_t** outHandle) -{ - // we rely on the caller to validate buffer here - *outHandle = reinterpret_cast( - static_cast(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 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 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 GrallocClient::destroyDescriptor(BufferDescriptor descriptor) -{ - { - std::lock_guard lock(mMutex); - if (!mDescriptors.erase(descriptor)) { - return Error::BAD_DESCRIPTOR; - } - } - - return mHal.destroyDescriptor(descriptor); -} - -Return GrallocClient::testAllocate( - const hidl_vec& descriptors) -{ - return mHal.testAllocate(descriptors); -} - -Return GrallocClient::allocate( - const hidl_vec& descriptors, - allocate_cb hidl_cb) { - hidl_vec buffers; - Error err = mHal.allocate(descriptors, &buffers); - - if (err == Error::NONE || err == Error::NOT_SHARED) { - std::lock_guard 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(); - err = Error::NO_RESOURCES; - break; - } - } - } - - hidl_cb(err, buffers); - return Void(); -} - -Return GrallocClient::free(Buffer buffer) -{ - { - std::lock_guard lock(mMutex); - if (!mBuffers.erase(buffer)) { - return Error::BAD_BUFFER; - } - } - - return mHal.free(buffer); -} - -Return GrallocClient::exportHandle(BufferDescriptor /*descriptor*/, - Buffer buffer, exportHandle_cb hidl_cb) -{ - const native_handle_t* handle = nullptr; - - { - std::lock_guard 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 diff --git a/graphics/allocator/2.0/default/Gralloc0Allocator.cpp b/graphics/allocator/2.0/default/Gralloc0Allocator.cpp new file mode 100644 index 0000000000..3b62bb3191 --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc0Allocator.cpp @@ -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 + +#include + +#include + +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 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 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()); + return Void(); + } + + Error error = Error::NONE; + uint32_t stride = 0; + std::vector 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_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(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 diff --git a/graphics/allocator/2.0/default/Gralloc0Allocator.h b/graphics/allocator/2.0/default/Gralloc0Allocator.h new file mode 100644 index 0000000000..0e90527f70 --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc0Allocator.h @@ -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 +#include +#include + +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 dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; + Return 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 diff --git a/graphics/allocator/2.0/default/Gralloc1Allocator.cpp b/graphics/allocator/2.0/default/Gralloc1Allocator.cpp new file mode 100644 index 0000000000..c0a5e1e0cb --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc1Allocator.cpp @@ -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 + +#include + +#include + +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 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 +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(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 Gralloc1Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) { + uint32_t len = 0; + mDispatch.dump(mDevice, &len, nullptr); + + std::vector 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 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()); + return Void(); + } + + gralloc1_buffer_descriptor_t desc; + Error error = createDescriptor(descriptorInfo, &desc); + if (error != Error::NONE) { + hidl_cb(error, 0, hidl_vec()); + return Void(); + } + + uint32_t stride = 0; + std::vector 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_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(BufferUsage::CPU_READ_MASK | + BufferUsage::CPU_WRITE_MASK); + + switch (usage & BufferUsage::CPU_WRITE_MASK) { + case static_cast(BufferUsage::CPU_WRITE_RARELY): + producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE; + break; + case static_cast(BufferUsage::CPU_WRITE_OFTEN): + producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN; + break; + default: + break; + } + + switch (usage & BufferUsage::CPU_READ_MASK) { + case static_cast(BufferUsage::CPU_READ_RARELY): + producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ; + break; + case static_cast(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(BufferUsage::CPU_READ_MASK | + BufferUsage::CPU_WRITE_MASK); + + switch (usage & BufferUsage::CPU_READ_MASK) { + case static_cast(BufferUsage::CPU_READ_RARELY): + consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ; + break; + case static_cast(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(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 diff --git a/graphics/allocator/2.0/default/Gralloc1Allocator.h b/graphics/allocator/2.0/default/Gralloc1Allocator.h new file mode 100644 index 0000000000..7b5a96613f --- /dev/null +++ b/graphics/allocator/2.0/default/Gralloc1Allocator.h @@ -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 +#include +#include + +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 dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override; + Return allocate(const BufferDescriptor& descriptor, uint32_t count, + allocate_cb hidl_cb) override; + + private: + void initCapabilities(); + + template + 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 diff --git a/graphics/allocator/2.0/types.hal b/graphics/allocator/2.0/types.hal deleted file mode 100644 index d9b184bba3..0000000000 --- a/graphics/allocator/2.0/types.hal +++ /dev/null @@ -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; diff --git a/graphics/allocator/2.0/vts/functional/Android.bp b/graphics/allocator/2.0/vts/functional/Android.bp deleted file mode 100644 index fb77ab322a..0000000000 --- a/graphics/allocator/2.0/vts/functional/Android.bp +++ /dev/null @@ -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", - ] -} diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp deleted file mode 100644 index 0dc43be640..0000000000 --- a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.cpp +++ /dev/null @@ -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 - -#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(); - ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service"; - - std::vector capabilities = getCapabilities(); - mCapabilities.insert(capabilities.begin(), capabilities.end()); -} - -sp Allocator::getRaw() const { return mAllocator; } - -bool Allocator::hasCapability(IAllocator::Capability capability) const { - return mCapabilities.count(capability) > 0; -} - -std::vector Allocator::getCapabilities() { - std::vector 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 Allocator::createClient() { - std::unique_ptr client; - mAllocator->createClient([&](const auto& tmpError, const auto& tmpClient) { - ASSERT_EQ(Error::NONE, tmpError) << "failed to create client"; - client = std::make_unique(tmpClient); - }); - - return client; -} - -AllocatorClient::AllocatorClient(const sp& 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 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& descriptors) { - return mClient->testAllocate(descriptors); -} - -bool AllocatorClient::testAllocate(BufferDescriptor descriptor) { - std::vector descriptors(1, descriptor); - Error error = testAllocate(descriptors); - return (error == Error::NONE || error == Error::NOT_SHARED); -} - -Error AllocatorClient::allocate( - const std::vector& descriptors, - std::vector& 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 descriptors(1, descriptor); - std::vector 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 diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h deleted file mode 100644 index c9bfe8fd82..0000000000 --- a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorTestUtils.h +++ /dev/null @@ -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 -#include -#include -#include - -#include -#include - -namespace android { -namespace hardware { -namespace graphics { -namespace allocator { -namespace V2_0 { -namespace tests { - -class AllocatorClient; - -// A wrapper to IAllocator. -class Allocator { - public: - Allocator(); - - sp getRaw() const; - - // Returns true when the allocator supports the specified capability. - bool hasCapability(IAllocator::Capability capability) const; - - std::vector getCapabilities(); - std::string dumpDebugInfo(); - std::unique_ptr createClient(); - - private: - void init(); - - sp mAllocator; - std::unordered_set mCapabilities; -}; - -// A wrapper to IAllocatorClient. -class AllocatorClient { - public: - AllocatorClient(const sp& client); - ~AllocatorClient(); - - sp getRaw() const; - - BufferDescriptor createDescriptor( - const IAllocatorClient::BufferDescriptorInfo& info); - void destroyDescriptor(BufferDescriptor descriptor); - - Error testAllocate(const std::vector& descriptors); - bool testAllocate(BufferDescriptor descriptor); - - Error allocate(const std::vector& descriptors, - std::vector& 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 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 mDescriptors; - std::unordered_set mBuffers; -}; - -} // namespace tests -} // namespace V2_0 -} // namespace allocator -} // namespace graphics -} // namespace hardware -} // namespace android - -#endif // VTS_HAL_GRAPHICS_ALLOCATOR_UTILS diff --git a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp b/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp deleted file mode 100644 index b1c764fc90..0000000000 --- a/graphics/allocator/2.0/vts/functional/VtsHalGraphicsAllocatorV2_0TargetTest.cpp +++ /dev/null @@ -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 -#include - -#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()); - 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(ProducerUsage::CPU_WRITE); - mDummyDescriptorInfo.consumerUsageMask = - static_cast(ConsumerUsage::CPU_READ); - } - - void TearDown() override {} - - std::unique_ptr mAllocator; - std::unique_ptr 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 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 descriptors; - descriptors.resize(3); - descriptors[0] = descriptor1; - descriptors[1] = descriptor1; - descriptors[2] = descriptor2; - - std::vector 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; -} diff --git a/graphics/common/1.0/Android.mk b/graphics/common/1.0/Android.mk index c08053de4d..ae80c6afd9 100644 --- a/graphics/common/1.0/Android.mk +++ b/graphics/common/1.0/Android.mk @@ -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) # diff --git a/graphics/common/1.0/types.hal b/graphics/common/1.0/types.hal index 8aa07799ff..3bd1ec174b 100644 --- a/graphics/common/1.0/types.hal +++ b/graphics/common/1.0/types.hal @@ -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 * diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp index 8e1f925c17..66323d4a4f 100644 --- a/graphics/composer/2.1/vts/functional/Android.bp +++ b/graphics/composer/2.1/vts/functional/Android.bp @@ -52,7 +52,6 @@ cc_test { ], static_libs: [ "libhwcomposer-command-buffer", - "libVtsHalGraphicsAllocatorTestUtils", "libVtsHalGraphicsComposerTestUtils", "libVtsHalGraphicsMapperTestUtils", "VtsHalHidlTargetTestBase", diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp index 0da3a33194..387222fbbe 100644 --- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp +++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp @@ -18,7 +18,6 @@ #include #include -#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()); - ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient()); - ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique()); + ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); mWriter = std::make_unique(1024); mReader = std::make_unique(); @@ -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(ProducerUsage::CPU_WRITE); - info.consumerUsageMask = static_cast(ConsumerUsage::CPU_READ); + IMapper::BufferDescriptorInfo info{}; + info.width = 64; + info.height = 64; + info.layerCount = 1; + info.format = PixelFormat::RGBA_8888; + info.usage = static_cast(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 mReader; private: - std::unique_ptr mAllocator; - std::unique_ptr mAllocatorClient; - std::unique_ptr mMapper; + std::unique_ptr mGralloc; }; /** diff --git a/graphics/mapper/2.0/Android.bp b/graphics/mapper/2.0/Android.bp index 98a509bb5a..cc2bd73c8f 100644 --- a/graphics/mapper/2.0/Android.bp +++ b/graphics/mapper/2.0/Android.bp @@ -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", ], diff --git a/graphics/mapper/2.0/IMapper.hal b/graphics/mapper/2.0/IMapper.hal index 573dcd09d0..246be240f2 100644 --- a/graphics/mapper/2.0/IMapper.hal +++ b/graphics/mapper/2.0/IMapper.hal @@ -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 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 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 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); }; diff --git a/graphics/mapper/2.0/default/Android.bp b/graphics/mapper/2.0/default/Android.bp index 1dc5aea643..090c61fb39 100644 --- a/graphics/mapper/2.0/default/Android.bp +++ b/graphics/mapper/2.0/default/Android.bp @@ -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: ["."], +} diff --git a/graphics/mapper/2.0/default/Gralloc0Mapper.cpp b/graphics/mapper/2.0/default/Gralloc0Mapper.cpp new file mode 100644 index 0000000000..28f50161c7 --- /dev/null +++ b/graphics/mapper/2.0/default/Gralloc0Mapper.cpp @@ -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 + +namespace android { +namespace hardware { +namespace graphics { +namespace mapper { +namespace V2_0 { +namespace implementation { + +Gralloc0Mapper::Gralloc0Mapper(const hw_module_t* module) + : mModule(reinterpret_cast(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 diff --git a/graphics/mapper/2.0/default/Gralloc0Mapper.h b/graphics/mapper/2.0/default/Gralloc0Mapper.h new file mode 100644 index 0000000000..e792a69703 --- /dev/null +++ b/graphics/mapper/2.0/default/Gralloc0Mapper.h @@ -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 + +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 diff --git a/graphics/mapper/2.0/default/Gralloc1Mapper.cpp b/graphics/mapper/2.0/default/Gralloc1Mapper.cpp new file mode 100644 index 0000000000..c1e5adcd64 --- /dev/null +++ b/graphics/mapper/2.0/default/Gralloc1Mapper.cpp @@ -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 + +#include + +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 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 +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(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(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 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(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 diff --git a/graphics/mapper/2.0/default/Gralloc1Mapper.h b/graphics/mapper/2.0/default/Gralloc1Mapper.h new file mode 100644 index 0000000000..452afdf820 --- /dev/null +++ b/graphics/mapper/2.0/default/Gralloc1Mapper.h @@ -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 + +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 + 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 diff --git a/graphics/mapper/2.0/default/GrallocBufferDescriptor.h b/graphics/mapper/2.0/default/GrallocBufferDescriptor.h new file mode 100644 index 0000000000..9b5ab04562 --- /dev/null +++ b/graphics/mapper/2.0/default/GrallocBufferDescriptor.h @@ -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 + +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(descriptorInfo.format); + descriptor[5] = static_cast(descriptorInfo.usage); + descriptor[6] = static_cast(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(descriptor[4]), + (static_cast(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 diff --git a/graphics/mapper/2.0/default/GrallocMapper.cpp b/graphics/mapper/2.0/default/GrallocMapper.cpp index 526aca23b6..339317aff8 100644 --- a/graphics/mapper/2.0/default/GrallocMapper.cpp +++ b/graphics/mapper/2.0/default/GrallocMapper.cpp @@ -17,14 +17,14 @@ #include "GrallocMapper.h" -#include -#include -#include +#include "Gralloc0Mapper.h" +#include "Gralloc1Mapper.h" +#include "GrallocBufferDescriptor.h" -#include +#include -#include #include +#include 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 GrallocMapper::mRegisteredHandles; - // IMapper interface - Return retain(const hidl_handle& bufferHandle) override; - Return release(const hidl_handle& bufferHandle) override; - Return getDimensions(const hidl_handle& bufferHandle, - getDimensions_cb hidl_cb) override; - Return getFormat(const hidl_handle& bufferHandle, - getFormat_cb hidl_cb) override; - Return getLayerCount(const hidl_handle& bufferHandle, - getLayerCount_cb hidl_cb) override; - Return getProducerUsageMask(const hidl_handle& bufferHandle, - getProducerUsageMask_cb hidl_cb) override; - Return getConsumerUsageMask(const hidl_handle& bufferHandle, - getConsumerUsageMask_cb hidl_cb) override; - Return getBackingStore(const hidl_handle& bufferHandle, - getBackingStore_cb hidl_cb) override; - Return getStride(const hidl_handle& bufferHandle, - getStride_cb hidl_cb) override; - Return 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 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 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(0)); -private: - void initCapabilities(); - - template - 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 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 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 -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(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 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 lock(mMutex); - - ++mBufferReferenceCounts[nativeHandle]; - } - return static_cast(err); -} - -Return 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 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(nativeHandle)); - - mBufferReferenceCounts.erase(iter); - } + if (!mCapabilities.layeredBuffers && descriptorInfo.layerCount > 1) { + return false; } - return static_cast(err); -} - -Return 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(err), width, height); - return Void(); -} - -Return 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(err), static_cast(format)); - return Void(); -} - -Return 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(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 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(err), count); return Void(); } -Return 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(err), mask); - return Void(); +bool GrallocMapper::addRegisteredHandle(buffer_handle_t bufferHandle) { + std::lock_guard lock(mMutex); + return mRegisteredHandles.insert(bufferHandle).second; } -Return 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(buffer); - hidl_cb(static_cast(err), mask); - return Void(); + std::lock_guard lock(mMutex); + return mRegisteredHandles.erase(bufferHandle) == 1 ? bufferHandle : nullptr; } -Return 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); - hidl_cb(static_cast(err), store); - return Void(); + std::lock_guard lock(mMutex); + return mRegisteredHandles.count(bufferHandle) == 1 ? bufferHandle : nullptr; } -Return GrallocMapperHal::getStride(const hidl_handle& bufferHandle, - getStride_cb hidl_cb) -{ - uint32_t stride = 0; - int32_t err = mDispatch.getStride(mDevice, bufferHandle, &stride); +Return 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(err), stride); - return Void(); -} + if (!rawHandle.getNativeHandle()) { + hidl_cb(Error::BAD_BUFFER, nullptr); + return Void(); + } -Return 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 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 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(err), data); + hidl_cb(error, data); return Void(); } -Return 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 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(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 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(layout.format); + hidl_cb(error, layout); + return Void(); +} - planes.resize(layout.num_planes); - layout_reply.planes.setToExternal( - reinterpret_cast(planes.data()), planes.size()); +Return 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(err), layout_reply); return Void(); } -Return 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(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 diff --git a/graphics/mapper/2.0/default/GrallocMapper.h b/graphics/mapper/2.0/default/GrallocMapper.h index a2f89d16ac..c9c6d8a918 100644 --- a/graphics/mapper/2.0/default/GrallocMapper.h +++ b/graphics/mapper/2.0/default/GrallocMapper.h @@ -18,6 +18,10 @@ #define ANDROID_HARDWARE_GRAPHICS_MAPPER_V2_0_GRALLOC_MAPPER_H #include +#include + +#include +#include namespace android { namespace hardware { @@ -26,6 +30,68 @@ namespace mapper { namespace V2_0 { namespace implementation { +class GrallocMapper : public IMapper { + public: + // IMapper interface + Return createDescriptor(const BufferDescriptorInfo& descriptorInfo, + createDescriptor_cb hidl_cb) override; + Return importBuffer(const hidl_handle& rawHandle, + importBuffer_cb hidl_cb) override; + Return freeBuffer(void* buffer) override; + Return lock(void* buffer, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, + const hidl_handle& acquireFence, + lock_cb hidl_cb) override; + Return lockYCbCr(void* buffer, uint64_t cpuUsage, + const IMapper::Rect& accessRegion, + const hidl_handle& acquireFence, + lockYCbCr_cb hidl_cb) override; + Return 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 mRegisteredHandles; +}; + extern "C" IMapper* HIDL_FETCH_IMapper(const char* name); } // namespace implementation diff --git a/graphics/mapper/2.0/types.hal b/graphics/mapper/2.0/types.hal index 2946e85e3e..e9b2f3a76c 100644 --- a/graphics/mapper/2.0/types.hal +++ b/graphics/mapper/2.0/types.hal @@ -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 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 planes; -}; - -/** Backing store ID of a buffer. See IMapper::getBackingStore. */ -typedef uint64_t BackingStore; diff --git a/graphics/mapper/2.0/vts/functional/Android.bp b/graphics/mapper/2.0/vts/functional/Android.bp index e26f087213..1c0e4c5a32 100644 --- a/graphics/mapper/2.0/vts/functional/Android.bp +++ b/graphics/mapper/2.0/vts/functional/Android.bp @@ -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", ], diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp index f6a26ac80e..c534889fca 100644 --- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp +++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.cpp @@ -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(); - 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(); + ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service"; + + mMapper = ::testing::VtsHalHidlTargetTestBase::getService(); + 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(bufferHandle); + native_handle_close(buffer); + native_handle_delete(buffer); } - } - mHandles.clear(); + mClonedBuffers.clear(); + + for (auto bufferHandle : mImportedBuffers) { + auto buffer = const_cast(bufferHandle); + EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) + << "failed to free buffer " << buffer; + } + mImportedBuffers.clear(); } -sp 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 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(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 Gralloc::allocate( + const BufferDescriptor& descriptor, uint32_t count, bool import, + uint32_t* outStride) { + std::vector 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 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(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(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(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, - 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(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(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 diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h index c186b00a54..757f20bcd2 100644 --- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h +++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperTestUtils.h @@ -17,14 +17,12 @@ #ifndef VTS_HAL_GRAPHICS_MAPPER_UTILS #define VTS_HAL_GRAPHICS_MAPPER_UTILS -#include -#include +#include +#include #include #include -#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 getRaw() const; + // IAllocator methods - void retain(const native_handle_t* handle); - void release(const native_handle_t* handle); + sp 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 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, - const IAllocatorClient::BufferDescriptorInfo& info); + sp getMapper() const; - private: - void init(); + BufferDescriptor createDescriptor( + const IMapper::BufferDescriptorInfo& descriptorInfo); - sp 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 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 mAllocator; + sp 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 mClonedBuffers; + std::unordered_set mImportedBuffers; }; } // namespace tests diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp index 92d74d5009..f066a1e2c5 100644 --- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp +++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp @@ -14,10 +14,10 @@ * limitations under the License. */ -#define LOG_TAG "graphics_mapper_hidl_hal_test" +#define LOG_TAG "VtsHalGraphicsMapperV2_0TargetTest" -#include #include +#include #include #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()); - ASSERT_NO_FATAL_FAILURE(mAllocatorClient = mAllocator->createClient()); - ASSERT_NO_FATAL_FAILURE(mMapper = std::make_unique()); + ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique()); - mDummyDescriptorInfo.width = 64; - mDummyDescriptorInfo.height = 64; - mDummyDescriptorInfo.layerCount = 1; - mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; - mDummyDescriptorInfo.producerUsageMask = - static_cast(ProducerUsage::CPU_WRITE); - mDummyDescriptorInfo.consumerUsageMask = - static_cast(ConsumerUsage::CPU_READ); + mDummyDescriptorInfo.width = 64; + mDummyDescriptorInfo.height = 64; + mDummyDescriptorInfo.layerCount = 1; + mDummyDescriptorInfo.format = PixelFormat::RGBA_8888; + mDummyDescriptorInfo.usage = static_cast( + BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN); } void TearDown() override {} - std::unique_ptr mAllocator; - std::unique_ptr mAllocatorClient; - std::unique_ptr mMapper; - IAllocatorClient::BufferDescriptorInfo mDummyDescriptorInfo{}; + std::unique_ptr 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 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(buffer); + }); + + // free the imported handle with another mapper + std::unique_ptr anotherGralloc; + ASSERT_NO_FATAL_FAILURE(anotherGralloc = std::make_unique()); + 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(info.width), + static_cast(info.height)}; + int fence = -1; + uint8_t* data; + ASSERT_NO_FATAL_FAILURE(data = static_cast(mGralloc->lock( + bufferHandle, info.usage, region, fence))); - // lock buffer for writing - const IMapper::Rect region{0, 0, static_cast(info.width), - static_cast(info.height)}; - int fence = -1; - uint32_t* data; - ASSERT_NO_FATAL_FAILURE( - data = static_cast( - 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( - 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(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(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(info.width), - static_cast(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(info.width), + static_cast(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(layout.planes[0].topLeft); - auto cb_data = static_cast(layout.planes[1].topLeft); - auto cr_data = static_cast(layout.planes[2].topLeft); + auto yData = static_cast(layout.y); + auto cbData = static_cast(layout.cb); + auto crData = static_cast(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(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(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(layout.planes[0].topLeft); - cb_data = static_cast(layout.planes[1].topLeft); - cr_data = static_cast(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(info.height * y + x); + yData = static_cast(layout.y); + cbData = static_cast(layout.cb); + crData = static_cast(layout.cr); + for (uint32_t y = 0; y < info.height; y++) { + for (uint32_t x = 0; x < info.width; x++) { + auto val = static_cast(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(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( + 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