| /* |
| * 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(); |
| }); |
| if (!transResult.isOk()) { |
| LOG(ERROR) << "getConsumerName: corrupted transaction."; |
| return String8("TransactFailed"); |
| } |
| 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 |