// Copyright 2021 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. //#define LOG_NDEBUG 0 #define LOG_TAG "H2BGraphicBuferProducer" #include #include #include #include namespace android { using ::android::BufferQueueDefs::BUFFER_NEEDS_REALLOCATION; using ::android::BufferQueueDefs::RELEASE_ALL_BUFFERS; using ::android::hardware::Return; using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer; using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status; using HConnectionType = hardware::graphics::bufferqueue::V2_0::ConnectionType; 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; using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper; H2BGraphicBufferProducer::H2BGraphicBufferProducer(sp base) : mBase(base) {} status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp* buf) { bool converted = false; status_t status = UNKNOWN_ERROR; Return transResult = mBase->requestBuffer( slot, [&converted, &status, buf](HStatus hStatus, HBuffer const& hBuffer, uint32_t generationNumber) { converted = h2b(hStatus, &status) && h2b(hBuffer, buf); if (*buf) { (*buf)->setGenerationNumber(generationNumber); } }); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!converted) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } if (status != OK) { ALOGD("%s() failed: %d", __func__, status); } return status; } status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(int maxDequeuedBuffers) { status_t status = UNKNOWN_ERROR; Return transResult = mBase->setMaxDequeuedBufferCount(static_cast(maxDequeuedBuffers)); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!h2b(static_cast(transResult), &status)) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } if (status != OK) { ALOGD("%s() failed: %d", __func__, status); } return status; } status_t H2BGraphicBufferProducer::dequeueBuffer(uint32_t width, uint32_t height, uint32_t pixelFormat, C2AndroidMemoryUsage androidUsage, int* slot, sp* fence) { using Input = HGraphicBufferProducer::DequeueBufferInput; using Output = HGraphicBufferProducer::DequeueBufferOutput; Input input{width, height, pixelFormat, androidUsage.asGrallocUsage()}; bool converted = false; status_t status = UNKNOWN_ERROR; Return transResult = mBase->dequeueBuffer( input, [&converted, &status, &slot, &fence](HStatus hStatus, int32_t hSlot, Output const& hOutput) { converted = h2b(hStatus, &status); if (!converted || status != OK) { return; } *slot = hSlot; if (hOutput.bufferNeedsReallocation) { status = BUFFER_NEEDS_REALLOCATION; } converted = h2b(hOutput.fence, fence); }); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!converted) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } // The C2VdaBqBlockPool does not fully own the bufferqueue. After buffers are dequeued here, // they are passed into the codec2 framework, processed, and eventually queued into the // bufferqueue. The C2VdaBqBlockPool cannot determine exactly when a buffer gets queued. // However, if every buffer is being processed by the codec2 framework, then dequeueBuffer() // will return INVALID_OPERATION because of an attempt to dequeue too many buffers. // The C2VdaBqBlockPool cannot prevent this from happening, so just map it to TIMED_OUT // and let the C2VdaBqBlockPool's caller's timeout retry logic handle the failure. if (status == INVALID_OPERATION) { status = TIMED_OUT; } if (status != OK && status != BUFFER_NEEDS_REALLOCATION && status != TIMED_OUT) { ALOGD("%s() failed: %d", __func__, status); } return status; } status_t H2BGraphicBufferProducer::detachBuffer(int slot) { status_t status = UNKNOWN_ERROR; Return transResult = mBase->detachBuffer(static_cast(slot)); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!h2b(static_cast(transResult), &status)) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } if (status != OK) { ALOGD("%s() failed: %d", __func__, status); } return status; } status_t H2BGraphicBufferProducer::attachBuffer(const sp& buffer, int* outSlot) { HBuffer hBuffer; uint32_t hGenerationNumber; if (!b2h(buffer, &hBuffer, &hGenerationNumber)) { ALOGE("%s: invalid input buffer.", __func__); return BAD_VALUE; } bool converted = false; status_t status = UNKNOWN_ERROR; Return transResult = mBase->attachBuffer( hBuffer, hGenerationNumber, [&converted, &status, outSlot](HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) { converted = h2b(hStatus, &status); *outSlot = static_cast(hSlot); if (converted && releaseAllBuffers && status == OK) { status = RELEASE_ALL_BUFFERS; } }); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!converted) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } if (status != OK) { ALOGD("%s() failed: %d", __func__, status); } return status; } status_t H2BGraphicBufferProducer::cancelBuffer(int slot, const sp& fence) { HFenceWrapper hFenceWrapper; if (!b2h(fence, &hFenceWrapper)) { ALOGE("%s(): corrupted input fence.", __func__); return UNKNOWN_ERROR; } status_t status = UNKNOWN_ERROR; Return transResult = mBase->cancelBuffer(static_cast(slot), hFenceWrapper.getHandle()); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!h2b(static_cast(transResult), &status)) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } if (status != OK) { ALOGD("%s() failed: %d", __func__, status); } return status; } int H2BGraphicBufferProducer::query(int what, int* value) { int result = 0; Return transResult = mBase->query(static_cast(what), [&result, value](int32_t r, int32_t v) { result = static_cast(r); *value = static_cast(v); }); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } return result; } status_t H2BGraphicBufferProducer::allowAllocation(bool allow) { status_t status = UNKNOWN_ERROR; Return transResult = mBase->allowAllocation(allow); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!h2b(static_cast(transResult), &status)) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } if (status != OK) { ALOGD("%s() failed: %d", __func__, status); } return status; } status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const { Return transResult = mBase->getUniqueId(); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } *outId = static_cast(transResult); return OK; } // android::IProducerListener cannot be depended by vendor library, so we use HProducerListener // directly. status_t H2BGraphicBufferProducer::connect(sp const& hListener, int32_t api, bool producerControlledByApp) { bool converted = false; status_t status = UNKNOWN_ERROR; // hack(b/146409777): We pass self-defined api, so we don't use b2h() here. Return transResult = mBase->connect( hListener, static_cast(api), producerControlledByApp, [&converted, &status](HStatus hStatus, HQueueBufferOutput const& /* hOutput */) { converted = h2b(hStatus, &status); }); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!converted) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } return status; } status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) { status_t status = UNKNOWN_ERROR; Return transResult = mBase->setDequeueTimeout(static_cast(timeout)); if (!transResult.isOk()) { ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str()); return FAILED_TRANSACTION; } if (!h2b(static_cast(transResult), &status)) { ALOGE("%s(): corrupted transaction.", __func__); return FAILED_TRANSACTION; } return status; } } // namespace android