You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
11 KiB
288 lines
11 KiB
// 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
|