blob: 7369ac759322009c5f4ddda4b62d57eba9d8b3f4 [file] [log] [blame]
/*
* Copyright 2016 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.
*/
#pragma once
#ifndef LOG_TAG
#warning "Gralloc0Hal.h included without LOG_TAG"
#endif
#include <inttypes.h>
#include <hardware/gralloc.h>
#include <log/log.h>
#include <mapper-hal/2.0/MapperHal.h>
#include <mapper-passthrough/2.0/GrallocBufferDescriptor.h>
#include <sync/sync.h>
namespace android {
namespace hardware {
namespace graphics {
namespace mapper {
namespace V2_0 {
namespace passthrough {
namespace detail {
using common::V1_0::BufferUsage;
// Gralloc0HalImpl implements V2_*::hal::MapperHal on top of gralloc0
template <typename Hal>
class Gralloc0HalImpl : public Hal {
public:
bool initWithModule(const hw_module_t* module) {
mModule = reinterpret_cast<const gralloc_module_t*>(module);
mMinor = module->module_api_version & 0xff;
return true;
}
Error createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo,
BufferDescriptor* outDescriptor) override {
if (!descriptorInfo.width || !descriptorInfo.height || !descriptorInfo.layerCount) {
return Error::BAD_VALUE;
}
if (descriptorInfo.layerCount != 1) {
return Error::UNSUPPORTED;
}
if (descriptorInfo.format == static_cast<PixelFormat>(0)) {
return Error::BAD_VALUE;
}
const uint64_t validUsageBits = getValidBufferUsageMask();
if (descriptorInfo.usage & ~validUsageBits) {
ALOGW("buffer descriptor with invalid usage bits 0x%" PRIx64,
descriptorInfo.usage & ~validUsageBits);
}
*outDescriptor = grallocEncodeBufferDescriptor(descriptorInfo);
return Error::NONE;
}
Error importBuffer(const native_handle_t* rawHandle,
native_handle_t** outBufferHandle) override {
native_handle_t* bufferHandle = native_handle_clone(rawHandle);
if (!bufferHandle) {
return Error::NO_RESOURCES;
}
if (mModule->registerBuffer(mModule, bufferHandle)) {
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
return Error::BAD_BUFFER;
}
*outBufferHandle = bufferHandle;
return Error::NONE;
}
Error freeBuffer(native_handle_t* bufferHandle) override {
if (mModule->unregisterBuffer(mModule, bufferHandle)) {
return Error::BAD_BUFFER;
}
native_handle_close(bufferHandle);
native_handle_delete(bufferHandle);
return Error::NONE;
}
Error lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
void** outData) override {
int result;
void* data = nullptr;
if (mMinor >= 3 && mModule->lockAsync) {
result = mModule->lockAsync(mModule, bufferHandle, cpuUsage, accessRegion.left,
accessRegion.top, accessRegion.width, accessRegion.height,
&data, fenceFd.release());
} else {
waitFenceFd(fenceFd, "Gralloc0Hal::lock");
result =
mModule->lock(mModule, bufferHandle, cpuUsage, accessRegion.left, accessRegion.top,
accessRegion.width, accessRegion.height, &data);
}
if (result) {
return Error::BAD_VALUE;
}
*outData = data;
return Error::NONE;
}
Error lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const IMapper::Rect& accessRegion, base::unique_fd fenceFd,
YCbCrLayout* outLayout) override {
int result;
android_ycbcr ycbcr = {};
if (mMinor >= 3 && mModule->lockAsync_ycbcr) {
result = mModule->lockAsync_ycbcr(mModule, bufferHandle, cpuUsage, accessRegion.left,
accessRegion.top, accessRegion.width,
accessRegion.height, &ycbcr, fenceFd.release());
} else {
waitFenceFd(fenceFd, "Gralloc0Hal::lockYCbCr");
if (mModule->lock_ycbcr) {
result = mModule->lock_ycbcr(mModule, bufferHandle, cpuUsage, accessRegion.left,
accessRegion.top, accessRegion.width,
accessRegion.height, &ycbcr);
} else {
result = -EINVAL;
}
}
if (result) {
return Error::BAD_VALUE;
}
outLayout->y = ycbcr.y;
outLayout->cb = ycbcr.cb;
outLayout->cr = ycbcr.cr;
outLayout->yStride = ycbcr.ystride;
outLayout->cStride = ycbcr.cstride;
outLayout->chromaStep = ycbcr.chroma_step;
return Error::NONE;
}
Error unlock(const native_handle_t* bufferHandle, base::unique_fd* outFenceFd) override {
int result;
int fenceFd = -1;
if (mMinor >= 3 && mModule->unlockAsync) {
result = mModule->unlockAsync(mModule, bufferHandle, &fenceFd);
} else {
result = mModule->unlock(mModule, bufferHandle);
}
// we always own the fenceFd even when unlock failed
outFenceFd->reset(fenceFd);
return result ? Error::BAD_VALUE : Error::NONE;
}
protected:
virtual uint64_t getValidBufferUsageMask() const {
return BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK | BufferUsage::GPU_TEXTURE |
BufferUsage::GPU_RENDER_TARGET | BufferUsage::COMPOSER_OVERLAY |
BufferUsage::COMPOSER_CLIENT_TARGET | BufferUsage::PROTECTED |
BufferUsage::COMPOSER_CURSOR | BufferUsage::VIDEO_ENCODER |
BufferUsage::CAMERA_OUTPUT | BufferUsage::CAMERA_INPUT | BufferUsage::RENDERSCRIPT |
BufferUsage::VIDEO_DECODER | BufferUsage::SENSOR_DIRECT_DATA |
BufferUsage::GPU_DATA_BUFFER | BufferUsage::VENDOR_MASK;
}
static void waitFenceFd(const base::unique_fd& fenceFd, const char* logname) {
if (fenceFd < 0) {
return;
}
const int warningTimeout = 3500;
const int error = sync_wait(fenceFd, warningTimeout);
if (error < 0 && errno == ETIME) {
ALOGE("%s: fence %d didn't signal in %u ms", logname, fenceFd.get(), warningTimeout);
sync_wait(fenceFd, -1);
}
}
const gralloc_module_t* mModule = nullptr;
uint8_t mMinor = 0;
};
} // namespace detail
using Gralloc0Hal = detail::Gralloc0HalImpl<hal::MapperHal>;
} // namespace passthrough
} // namespace V2_0
} // namespace mapper
} // namespace graphics
} // namespace hardware
} // namespace android