| /* | |
| * 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 "B2HGraphicBufferProducer@2.0" | |
| #include <android-base/logging.h> | |
| #include <android/hardware/graphics/bufferqueue/2.0/types.h> | |
| #include <android/hardware/graphics/common/1.2/types.h> | |
| #include <gui/bufferqueue/2.0/H2BProducerListener.h> | |
| #include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.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(BQueueBufferOutput const& from, HQueueBufferOutput* to) { | |
| to->width = from.width; | |
| to->height = from.height; | |
| to->transformHint = static_cast<int32_t>(from.transformHint); | |
| to->numPendingBuffers = from.numPendingBuffers; | |
| to->nextFrameNumber = from.nextFrameNumber; | |
| to->bufferReplaced = from.bufferReplaced; | |
| return true; | |
| } | |
| } // unnamed namespace | |
| // B2HGraphicBufferProducer | |
| // ======================== | |
| B2HGraphicBufferProducer::B2HGraphicBufferProducer( | |
| sp<BGraphicBufferProducer> const& base) | |
| : mBase{base} { | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::setMaxDequeuedBufferCount( | |
| int32_t maxDequeuedBuffers) { | |
| HStatus hStatus{}; | |
| bool converted = b2h( | |
| mBase->setMaxDequeuedBufferCount( | |
| static_cast<int>(maxDequeuedBuffers)), | |
| &hStatus); | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<void> B2HGraphicBufferProducer::requestBuffer( | |
| int32_t slot, | |
| requestBuffer_cb _hidl_cb) { | |
| sp<GraphicBuffer> bBuffer; | |
| HStatus hStatus{}; | |
| HardwareBuffer hBuffer{}; | |
| uint32_t hGenerationNumber{}; | |
| bool converted = | |
| b2h(mBase->requestBuffer( | |
| static_cast<int>(slot), &bBuffer), | |
| &hStatus) && | |
| b2h(bBuffer, &hBuffer, &hGenerationNumber); | |
| _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, | |
| hBuffer, hGenerationNumber); | |
| return {}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::setAsyncMode(bool async) { | |
| HStatus hStatus{}; | |
| bool converted = b2h(mBase->setAsyncMode(async), &hStatus); | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<void> B2HGraphicBufferProducer::dequeueBuffer( | |
| DequeueBufferInput const& input, | |
| dequeueBuffer_cb _hidl_cb) { | |
| int bSlot{}; | |
| sp<BFence> bFence; | |
| HStatus hStatus{}; | |
| DequeueBufferOutput hOutput{}; | |
| HFenceWrapper hFenceWrapper; | |
| bool converted = | |
| b2h(mBase->dequeueBuffer( | |
| &bSlot, | |
| &bFence, | |
| input.width, | |
| input.height, | |
| static_cast<PixelFormat>(input.format), | |
| input.usage, | |
| &hOutput.bufferAge, | |
| nullptr /* outTimestamps */), | |
| &hStatus, | |
| &hOutput.bufferNeedsReallocation, | |
| &hOutput.releaseAllBuffers) && | |
| b2h(bFence, &hFenceWrapper); | |
| hOutput.fence = hFenceWrapper.getHandle(); | |
| _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, | |
| static_cast<int32_t>(bSlot), | |
| hOutput); | |
| return {}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::detachBuffer(int32_t slot) { | |
| HStatus hStatus{}; | |
| bool converted = b2h( | |
| mBase->detachBuffer(static_cast<int>(slot)), &hStatus); | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<void> B2HGraphicBufferProducer::detachNextBuffer( | |
| detachNextBuffer_cb _hidl_cb) { | |
| sp<GraphicBuffer> bBuffer; | |
| sp<BFence> bFence; | |
| HStatus hStatus{}; | |
| HardwareBuffer hBuffer{}; | |
| HFenceWrapper hFenceWrapper; | |
| bool converted = | |
| b2h(mBase->detachNextBuffer(&bBuffer, &bFence), &hStatus) && | |
| b2h(bBuffer, &hBuffer) && | |
| b2h(bFence, &hFenceWrapper); | |
| _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, | |
| hBuffer, | |
| hFenceWrapper.getHandle()); | |
| return {}; | |
| } | |
| Return<void> B2HGraphicBufferProducer::attachBuffer( | |
| HardwareBuffer const& hBuffer, | |
| uint32_t generationNumber, | |
| attachBuffer_cb _hidl_cb) { | |
| sp<GraphicBuffer> bBuffer; | |
| if (!h2b(hBuffer, &bBuffer) || !bBuffer) { | |
| _hidl_cb(HStatus::UNKNOWN_ERROR, | |
| static_cast<int32_t>(SlotIndex::INVALID), | |
| false); | |
| return {}; | |
| } | |
| bBuffer->setGenerationNumber(generationNumber); | |
| int bSlot{}; | |
| HStatus hStatus{}; | |
| bool releaseAllBuffers{}; | |
| bool converted = b2h( | |
| mBase->attachBuffer(&bSlot, bBuffer), &hStatus, | |
| nullptr /* bufferNeedsReallocation */, | |
| &releaseAllBuffers); | |
| _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, | |
| static_cast<int32_t>(bSlot), | |
| releaseAllBuffers); | |
| return {}; | |
| } | |
| Return<void> B2HGraphicBufferProducer::queueBuffer( | |
| int32_t slot, | |
| QueueBufferInput const& hInput, | |
| queueBuffer_cb _hidl_cb) { | |
| BQueueBufferInput bInput{ | |
| hInput.timestamp, | |
| hInput.isAutoTimestamp, | |
| static_cast<android_dataspace>(hInput.dataSpace), | |
| {}, /* crop */ | |
| 0 /* scalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE */, | |
| static_cast<uint32_t>(hInput.transform), | |
| {}, /* fence */ | |
| static_cast<uint32_t>(hInput.stickyTransform), | |
| false /* getFrameTimestamps */}; | |
| // Convert crop. | |
| if (!h2b(hInput.crop, &bInput.crop)) { | |
| _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{}); | |
| return {}; | |
| } | |
| // Convert surfaceDamage. | |
| if (!h2b(hInput.surfaceDamage, &bInput.surfaceDamage)) { | |
| _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{}); | |
| return {}; | |
| } | |
| // Convert fence. | |
| if (!h2b(hInput.fence, &bInput.fence)) { | |
| _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{}); | |
| return {}; | |
| } | |
| BQueueBufferOutput bOutput{}; | |
| HStatus hStatus{}; | |
| QueueBufferOutput hOutput{}; | |
| bool converted = | |
| b2h( | |
| mBase->queueBuffer(static_cast<int>(slot), bInput, &bOutput), | |
| &hStatus) && | |
| b2h(bOutput, &hOutput); | |
| _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput); | |
| return {}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::cancelBuffer( | |
| int32_t slot, | |
| hidl_handle const& fence) { | |
| sp<BFence> bFence; | |
| if (!h2b(fence.getNativeHandle(), &bFence)) { | |
| return {HStatus::UNKNOWN_ERROR}; | |
| } | |
| HStatus hStatus{}; | |
| bool converted = b2h( | |
| mBase->cancelBuffer(static_cast<int>(slot), bFence), | |
| &hStatus); | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<void> B2HGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) { | |
| int value{}; | |
| int result = mBase->query(static_cast<int>(what), &value); | |
| _hidl_cb(static_cast<int32_t>(result), static_cast<int32_t>(value)); | |
| return {}; | |
| } | |
| struct Obituary : public hardware::hidl_death_recipient { | |
| wp<B2HGraphicBufferProducer> producer; | |
| sp<HProducerListener> listener; | |
| HConnectionType apiType; | |
| Obituary(const wp<B2HGraphicBufferProducer>& p, | |
| const sp<HProducerListener>& l, | |
| HConnectionType t) | |
| : producer(p), listener(l), apiType(t) {} | |
| void serviceDied(uint64_t /* cookie */, | |
| const wp<::android::hidl::base::V1_0::IBase>& /* who */) override { | |
| sp<B2HGraphicBufferProducer> dr = producer.promote(); | |
| if (dr != nullptr) { | |
| (void)dr->disconnect(apiType); | |
| } | |
| } | |
| }; | |
| Return<void> B2HGraphicBufferProducer::connect( | |
| sp<HProducerListener> const& hListener, | |
| HConnectionType hConnectionType, | |
| bool producerControlledByApp, | |
| connect_cb _hidl_cb) { | |
| sp<BProducerListener> bListener = new H2BProducerListener(hListener); | |
| int bConnectionType{}; | |
| if (!bListener || !h2b(hConnectionType, &bConnectionType)) { | |
| _hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{}); | |
| return {}; | |
| } | |
| BQueueBufferOutput bOutput{}; | |
| HStatus hStatus{}; | |
| QueueBufferOutput hOutput{}; | |
| bool converted = | |
| b2h(mBase->connect(bListener, | |
| bConnectionType, | |
| producerControlledByApp, | |
| &bOutput), | |
| &hStatus) && | |
| b2h(bOutput, &hOutput); | |
| #ifdef NO_BINDER | |
| if (converted && hListener != nullptr) { | |
| mObituary = new Obituary(this, hListener, hConnectionType); | |
| hListener->linkToDeath(mObituary, 0); | |
| } | |
| #endif // NO_BINDER | |
| _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR, hOutput); | |
| return {}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::disconnect( | |
| HConnectionType hConnectionType) { | |
| int bConnectionType; | |
| if (!h2b(hConnectionType, &bConnectionType)) { | |
| return {HStatus::UNKNOWN_ERROR}; | |
| } | |
| HStatus hStatus{}; | |
| bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus); | |
| #ifdef NO_BINDER | |
| if (mObituary != nullptr) { | |
| mObituary->listener->unlinkToDeath(mObituary); | |
| mObituary.clear(); | |
| } | |
| #endif // NO_BINDER | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::allocateBuffers( | |
| uint32_t width, uint32_t height, | |
| uint32_t format, uint64_t usage) { | |
| mBase->allocateBuffers( | |
| width, height, static_cast<PixelFormat>(format), usage); | |
| return {HStatus::OK}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::allowAllocation(bool allow) { | |
| HStatus hStatus{}; | |
| bool converted = b2h(mBase->allowAllocation(allow), &hStatus); | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::setGenerationNumber( | |
| uint32_t generationNumber) { | |
| HStatus hStatus{}; | |
| bool converted = b2h( | |
| mBase->setGenerationNumber(generationNumber), | |
| &hStatus); | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<HStatus> B2HGraphicBufferProducer::setDequeueTimeout( | |
| int64_t timeoutNs) { | |
| HStatus hStatus{}; | |
| bool converted = b2h( | |
| mBase->setDequeueTimeout(static_cast<nsecs_t>(timeoutNs)), | |
| &hStatus); | |
| return {converted ? hStatus : HStatus::UNKNOWN_ERROR}; | |
| } | |
| Return<uint64_t> B2HGraphicBufferProducer::getUniqueId() { | |
| uint64_t outId{}; | |
| HStatus hStatus{}; | |
| bool converted = b2h(mBase->getUniqueId(&outId), &hStatus); | |
| return {converted ? outId : 0}; | |
| } | |
| Return<void> B2HGraphicBufferProducer::getConsumerName( | |
| getConsumerName_cb _hidl_cb) { | |
| _hidl_cb(hidl_string{mBase->getConsumerName().c_str()}); | |
| return {}; | |
| } | |
| } // namespace utils | |
| } // namespace V2_0 | |
| } // namespace bufferqueue | |
| } // namespace graphics | |
| } // namespace hardware | |
| } // namespace android | |