| /* | 
 |  * Copyright 2019 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | //#define LOG_NDEBUG 0 | 
 | #define LOG_TAG "H2BGraphicBufferProducer@2.0" | 
 |  | 
 | #include <android-base/logging.h> | 
 |  | 
 | #include <android/hardware/graphics/common/1.2/types.h> | 
 | #include <gui/bufferqueue/2.0/B2HProducerListener.h> | 
 | #include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h> | 
 | #include <gui/bufferqueue/2.0/types.h> | 
 | #include <ui/GraphicBuffer.h> | 
 | #include <ui/Rect.h> | 
 | #include <ui/Region.h> | 
 | #include <vndk/hardware_buffer.h> | 
 |  | 
 | namespace android { | 
 | namespace hardware { | 
 | namespace graphics { | 
 | namespace bufferqueue { | 
 | namespace V2_0 { | 
 | namespace utils { | 
 |  | 
 | namespace /* unnamed */ { | 
 |  | 
 | using BQueueBufferInput = ::android:: | 
 |         IGraphicBufferProducer::QueueBufferInput; | 
 | using HQueueBufferInput = ::android::hardware::graphics::bufferqueue::V2_0:: | 
 |         IGraphicBufferProducer::QueueBufferInput; | 
 | using BQueueBufferOutput = ::android:: | 
 |         IGraphicBufferProducer::QueueBufferOutput; | 
 | using HQueueBufferOutput = ::android::hardware::graphics::bufferqueue::V2_0:: | 
 |         IGraphicBufferProducer::QueueBufferOutput; | 
 |  | 
 | using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h; | 
 | using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b; | 
 |  | 
 | bool b2h(BQueueBufferInput const& from, HQueueBufferInput* to, | 
 |          HFenceWrapper* hFenceWrapper) { | 
 |     to->timestamp = from.timestamp; | 
 |     to->isAutoTimestamp = static_cast<bool>(from.isAutoTimestamp); | 
 |     to->dataSpace = static_cast<int32_t>(from.dataSpace); | 
 |     to->transform = static_cast<int32_t>(from.transform); | 
 |     to->stickyTransform = static_cast<int32_t>(from.stickyTransform); | 
 |     if (!b2h(from.crop, &to->crop) || | 
 |             !b2h(from.surfaceDamage, &to->surfaceDamage) || | 
 |             !b2h(from.fence, hFenceWrapper)) { | 
 |         return false; | 
 |     } | 
 |     to->fence = hFenceWrapper->getHandle(); | 
 |     return true; | 
 | } | 
 |  | 
 | bool h2b(HQueueBufferOutput const& from, BQueueBufferOutput* to) { | 
 |     to->width = from.width; | 
 |     to->height = from.height; | 
 |     to->transformHint = static_cast<uint32_t>(from.transformHint); | 
 |     to->numPendingBuffers = from.numPendingBuffers; | 
 |     to->nextFrameNumber = from.nextFrameNumber; | 
 |     to->bufferReplaced = from.bufferReplaced; | 
 |     return true; | 
 | } | 
 |  | 
 | } // unnamed namespace | 
 |  | 
 | // H2BGraphicBufferProducer | 
 | // ======================== | 
 |  | 
 | status_t H2BGraphicBufferProducer::requestBuffer(int slot, | 
 |                                                  sp<GraphicBuffer>* bBuffer) { | 
 |     bool converted{}; | 
 |     status_t bStatus{}; | 
 |     Return<void> transResult = mBase->requestBuffer(slot, | 
 |             [&converted, &bStatus, bBuffer]( | 
 |                     HStatus hStatus, | 
 |                     HardwareBuffer const& hBuffer, | 
 |                     uint32_t generationNumber) { | 
 |                 converted = | 
 |                         h2b(hStatus, &bStatus) && | 
 |                         h2b(hBuffer, bBuffer); | 
 |                 if (*bBuffer) { | 
 |                     (*bBuffer)->setGenerationNumber(generationNumber); | 
 |                 } | 
 |             }); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "requestBuffer: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!converted) { | 
 |         LOG(ERROR) << "requestBuffer: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount( | 
 |         int maxDequeuedBuffers) { | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->setMaxDequeuedBufferCount( | 
 |             static_cast<int32_t>(maxDequeuedBuffers)); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "setMaxDequeuedBufferCount: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "setMaxDequeuedBufferCount: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::setAsyncMode(bool async) { | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->setAsyncMode(async); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "setAsyncMode: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "setAsyncMode: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::dequeueBuffer( | 
 |         int* slot, sp<BFence>* fence, | 
 |         uint32_t w, uint32_t h, | 
 |         PixelFormat format, uint64_t usage, | 
 |         uint64_t* outBufferAge, FrameEventHistoryDelta* /* outTimestamps */) { | 
 |  | 
 |     using HInput = HGraphicBufferProducer::DequeueBufferInput; | 
 |     HInput input{w, h, static_cast<uint32_t>(format), usage}; | 
 |  | 
 |     using HOutput = HGraphicBufferProducer::DequeueBufferOutput; | 
 |     bool converted{}; | 
 |     status_t bStatus{}; | 
 |     Return<void> transResult = mBase->dequeueBuffer(input, | 
 |             [&converted, &bStatus, slot, fence, outBufferAge] ( | 
 |                     HStatus hStatus, int32_t hSlot, HOutput const& hOutput) { | 
 |                 converted = h2b(hStatus, &bStatus); | 
 |                 if (!converted || bStatus != OK) { | 
 |                     return; | 
 |                 } | 
 |                 *slot = hSlot; | 
 |                 *outBufferAge = hOutput.bufferAge; | 
 |                 bStatus = | 
 |                         (hOutput.bufferNeedsReallocation ? | 
 |                         BUFFER_NEEDS_REALLOCATION : 0) | | 
 |                         (hOutput.releaseAllBuffers ? | 
 |                         RELEASE_ALL_BUFFERS : 0); | 
 |                 converted = h2b(hOutput.fence, fence); | 
 |             }); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "dequeueBuffer: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!converted) { | 
 |         LOG(ERROR) << "dequeueBuffer: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::detachBuffer(int slot) { | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->detachBuffer( | 
 |             static_cast<int32_t>(slot)); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "detachBuffer: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "detachBuffer: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::detachNextBuffer( | 
 |         sp<GraphicBuffer>* outBuffer, sp<BFence>* outFence) { | 
 |     bool converted{}; | 
 |     status_t bStatus{}; | 
 |     Return<void> transResult = mBase->detachNextBuffer( | 
 |             [&converted, &bStatus, outBuffer, outFence] ( | 
 |                     HStatus hStatus, | 
 |                     HardwareBuffer const& hBuffer, | 
 |                     hidl_handle const& hFence) { | 
 |                 converted = h2b(hStatus, &bStatus) && | 
 |                     h2b(hBuffer, outBuffer) && | 
 |                     h2b(hFence, outFence); | 
 |             }); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "detachNextBuffer: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!converted) { | 
 |         LOG(ERROR) << "detachNextBuffer: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::attachBuffer( | 
 |         int* outSlot, sp<GraphicBuffer> const& buffer) { | 
 |     HardwareBuffer hBuffer{}; | 
 |     uint32_t hGenerationNumber{}; | 
 |     if (!b2h(buffer, &hBuffer, &hGenerationNumber)) { | 
 |         LOG(ERROR) << "attachBuffer: invalid input buffer."; | 
 |         return BAD_VALUE; | 
 |     } | 
 |  | 
 |     bool converted{}; | 
 |     status_t bStatus{}; | 
 |     Return<void> transResult = mBase->attachBuffer(hBuffer, hGenerationNumber, | 
 |             [&converted, &bStatus, outSlot]( | 
 |                     HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) { | 
 |                 converted = h2b(hStatus, &bStatus); | 
 |                 *outSlot = static_cast<int>(hSlot); | 
 |                 if (converted && releaseAllBuffers && bStatus == OK) { | 
 |                     bStatus = IGraphicBufferProducer::RELEASE_ALL_BUFFERS; | 
 |                 } | 
 |             }); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "attachBuffer: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!converted) { | 
 |         LOG(ERROR) << "attachBuffer: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::queueBuffer( | 
 |         int slot, | 
 |         QueueBufferInput const& input, | 
 |         QueueBufferOutput* output) { | 
 |     HQueueBufferInput hInput{}; | 
 |     HFenceWrapper hFenceWrapper; | 
 |     if (!b2h(input, &hInput, &hFenceWrapper)) { | 
 |         LOG(ERROR) << "queueBuffer: corrupted input."; | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     bool converted{}; | 
 |     status_t bStatus{}; | 
 |     Return<void> transResult = mBase->queueBuffer( | 
 |             static_cast<int32_t>(slot), | 
 |             hInput, | 
 |             [&converted, &bStatus, output]( | 
 |                     HStatus hStatus, | 
 |                     HQueueBufferOutput const& hOutput) { | 
 |                 converted = h2b(hStatus, &bStatus) && h2b(hOutput, output); | 
 |             }); | 
 |  | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "queueBuffer: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!converted) { | 
 |         LOG(ERROR) << "queueBuffer: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::cancelBuffer(int slot, sp<BFence> const& fence) { | 
 |     HFenceWrapper hFenceWrapper; | 
 |     if (!b2h(fence, &hFenceWrapper)) { | 
 |         LOG(ERROR) << "cancelBuffer: corrupted input fence."; | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->cancelBuffer( | 
 |             static_cast<int32_t>(slot), | 
 |             hFenceWrapper.getHandle()); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "cancelBuffer: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "cancelBuffer: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | int H2BGraphicBufferProducer::query(int what, int* value) { | 
 |     int result{}; | 
 |     Return<void> transResult = mBase->query( | 
 |             static_cast<int32_t>(what), | 
 |             [&result, value](int32_t r, int32_t v) { | 
 |                 result = static_cast<int>(r); | 
 |                 *value = static_cast<int>(v); | 
 |             }); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "query: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return result; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::connect( | 
 |         sp<IProducerListener> const& listener, int api, | 
 |         bool producerControlledByApp, QueueBufferOutput* output) { | 
 |     HConnectionType hConnectionType; | 
 |     if (!b2h(api, &hConnectionType)) { | 
 |         LOG(ERROR) << "connect: corrupted input connection type."; | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |     sp<HProducerListener> hListener = nullptr; | 
 |     if (listener && listener->needsReleaseNotify()) { | 
 |         hListener = new B2HProducerListener(listener); | 
 |         if (!hListener) { | 
 |             LOG(ERROR) << "connect: failed to wrap listener."; | 
 |             return UNKNOWN_ERROR; | 
 |         } | 
 |     } | 
 |  | 
 |     bool converted{}; | 
 |     status_t bStatus{}; | 
 |     Return<void> transResult = mBase->connect( | 
 |             hListener, | 
 |             hConnectionType, | 
 |             producerControlledByApp, | 
 |             [&converted, &bStatus, output]( | 
 |                     HStatus hStatus, | 
 |                     HQueueBufferOutput const& hOutput) { | 
 |                 converted = h2b(hStatus, &bStatus) && h2b(hOutput, output); | 
 |             }); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "connect: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!converted) { | 
 |         LOG(ERROR) << "connect: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 |  | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) { | 
 |     HConnectionType hConnectionType; | 
 |     if (mode == DisconnectMode::AllLocal) { | 
 |         hConnectionType = HConnectionType::CURRENTLY_CONNECTED; | 
 |     } else if (!b2h(api, &hConnectionType)) { | 
 |         LOG(ERROR) << "connect: corrupted input connection type."; | 
 |         return UNKNOWN_ERROR; | 
 |     } | 
 |  | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->disconnect(hConnectionType); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "disconnect: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "disconnect: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::setSidebandStream( | 
 |         sp<NativeHandle> const& stream) { | 
 |     if (stream) { | 
 |         LOG(INFO) << "setSidebandStream: not supported."; | 
 |         return INVALID_OPERATION; | 
 |     } | 
 |     return OK; | 
 | } | 
 |  | 
 | void H2BGraphicBufferProducer::allocateBuffers( | 
 |         uint32_t width, uint32_t height, | 
 |         PixelFormat format, uint64_t usage) { | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->allocateBuffers( | 
 |             width, height, static_cast<uint32_t>(format), usage); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "allocateBuffer: transaction failed."; | 
 |         return; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "allocateBuffer: corrupted transaction."; | 
 |         return; | 
 |     } | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::allowAllocation(bool allow) { | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->allowAllocation(allow); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "allowAllocation: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "allowAllocation: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::setGenerationNumber( | 
 |         uint32_t generationNumber) { | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->setGenerationNumber(generationNumber); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "setGenerationNumber: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "setGenerationNumber: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | String8 H2BGraphicBufferProducer::getConsumerName() const { | 
 |     String8 bName; | 
 |     Return<void> transResult = mBase->getConsumerName( | 
 |             [&bName](hidl_string const& name) { | 
 |                 bName = name.c_str(); | 
 |             }); | 
 |     return bName; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) { | 
 |     if (sharedBufferMode) { | 
 |         LOG(INFO) << "setSharedBufferMode: not supported."; | 
 |         return INVALID_OPERATION; | 
 |     } | 
 |     return OK; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) { | 
 |     if (autoRefresh) { | 
 |         LOG(INFO) << "setAutoRefresh: not supported."; | 
 |         return INVALID_OPERATION; | 
 |     } | 
 |     return OK; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) { | 
 |     status_t bStatus{}; | 
 |     Return<HStatus> transResult = mBase->setDequeueTimeout( | 
 |             static_cast<int64_t>(timeout)); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "setDequeueTimeout: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     if (!h2b(static_cast<HStatus>(transResult), &bStatus)) { | 
 |         LOG(ERROR) << "setDequeueTimeout: corrupted transaction."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     return bStatus; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::getLastQueuedBuffer( | 
 |         sp<GraphicBuffer>*, | 
 |         sp<BFence>*, | 
 |         float[16]) { | 
 |     LOG(INFO) << "getLastQueuedBuffer: not supported."; | 
 |     return INVALID_OPERATION; | 
 | } | 
 |  | 
 | void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta*) { | 
 |     LOG(INFO) << "getFrameTimestamps: not supported."; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const { | 
 |     Return<uint64_t> transResult = mBase->getUniqueId(); | 
 |     if (!transResult.isOk()) { | 
 |         LOG(ERROR) << "getUniqueId: transaction failed."; | 
 |         return FAILED_TRANSACTION; | 
 |     } | 
 |     *outId = static_cast<uint64_t>(transResult); | 
 |     return OK; | 
 | } | 
 |  | 
 | status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t*) const { | 
 |     LOG(INFO) << "getConsumerUsage: not supported."; | 
 |     return INVALID_OPERATION; | 
 | } | 
 |  | 
 | }  // namespace utils | 
 | }  // namespace V2_0 | 
 | }  // namespace bufferqueue | 
 | }  // namespace graphics | 
 | }  // namespace hardware | 
 | }  // namespace android |