blob: 95251de511e90d88bdda0e0dd0d0bf91558a5241 [file] [log] [blame]
// 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 <v4l2_codec2/plugin_store/H2BGraphicBufferProducer.h>
#include <log/log.h>
#include <types.h>
#include <ui/BufferQueueDefs.h>
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<HGraphicBufferProducer> base) : mBase(base) {}
status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
bool converted = false;
status_t status = UNKNOWN_ERROR;
Return<void> 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<HStatus> transResult =
mBase->setMaxDequeuedBufferCount(static_cast<int32_t>(maxDequeuedBuffers));
if (!transResult.isOk()) {
ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
return FAILED_TRANSACTION;
}
if (!h2b(static_cast<HStatus>(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>* 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<void> 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<HStatus> transResult = mBase->detachBuffer(static_cast<int32_t>(slot));
if (!transResult.isOk()) {
ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
return FAILED_TRANSACTION;
}
if (!h2b(static_cast<HStatus>(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<GraphicBuffer>& 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<void> transResult = mBase->attachBuffer(
hBuffer, hGenerationNumber,
[&converted, &status, outSlot](HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) {
converted = h2b(hStatus, &status);
*outSlot = static_cast<int>(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>& fence) {
HFenceWrapper hFenceWrapper;
if (!b2h(fence, &hFenceWrapper)) {
ALOGE("%s(): corrupted input fence.", __func__);
return UNKNOWN_ERROR;
}
status_t status = UNKNOWN_ERROR;
Return<HStatus> transResult =
mBase->cancelBuffer(static_cast<int32_t>(slot), hFenceWrapper.getHandle());
if (!transResult.isOk()) {
ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
return FAILED_TRANSACTION;
}
if (!h2b(static_cast<HStatus>(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<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()) {
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<HStatus> transResult = mBase->allowAllocation(allow);
if (!transResult.isOk()) {
ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
return FAILED_TRANSACTION;
}
if (!h2b(static_cast<HStatus>(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<uint64_t> transResult = mBase->getUniqueId();
if (!transResult.isOk()) {
ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
return FAILED_TRANSACTION;
}
*outId = static_cast<uint64_t>(transResult);
return OK;
}
// android::IProducerListener cannot be depended by vendor library, so we use HProducerListener
// directly.
status_t H2BGraphicBufferProducer::connect(sp<HProducerListener> 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<void> transResult = mBase->connect(
hListener, static_cast<HConnectionType>(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<HStatus> transResult = mBase->setDequeueTimeout(static_cast<int64_t>(timeout));
if (!transResult.isOk()) {
ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
return FAILED_TRANSACTION;
}
if (!h2b(static_cast<HStatus>(transResult), &status)) {
ALOGE("%s(): corrupted transaction.", __func__);
return FAILED_TRANSACTION;
}
return status;
}
} // namespace android