blob: 98082fb81e39beaf0d15a90a9cebcd0408470abd [file] [log] [blame]
/*
**
** Copyright 2009, 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_TAG "GraphicBufferAllocator"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <ui/GraphicBufferAllocator.h>
#include <limits.h>
#include <stdio.h>
#include <grallocusage/GrallocUsageConversion.h>
#include <android-base/stringprintf.h>
#include <log/log.h>
#include <utils/Singleton.h>
#include <utils/Trace.h>
#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
#include <ui/Gralloc3.h>
#include <ui/Gralloc4.h>
#include <ui/Gralloc5.h>
#include <ui/GraphicBufferMapper.h>
namespace android {
// ---------------------------------------------------------------------------
using base::StringAppendF;
ANDROID_SINGLETON_STATIC_INSTANCE( GraphicBufferAllocator )
Mutex GraphicBufferAllocator::sLock;
KeyedVector<buffer_handle_t,
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
switch (mMapper.getMapperVersion()) {
case GraphicBufferMapper::GRALLOC_5:
mAllocator = std::make_unique<const Gralloc5Allocator>(
reinterpret_cast<const Gralloc5Mapper&>(mMapper.getGrallocMapper()));
break;
case GraphicBufferMapper::GRALLOC_4:
mAllocator = std::make_unique<const Gralloc4Allocator>(
reinterpret_cast<const Gralloc4Mapper&>(mMapper.getGrallocMapper()));
break;
case GraphicBufferMapper::GRALLOC_3:
mAllocator = std::make_unique<const Gralloc3Allocator>(
reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
break;
case GraphicBufferMapper::GRALLOC_2:
mAllocator = std::make_unique<const Gralloc2Allocator>(
reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
break;
}
LOG_ALWAYS_FATAL_IF(!mAllocator->isLoaded(),
"Failed to load matching allocator for mapper version %d",
mMapper.getMapperVersion());
}
GraphicBufferAllocator::~GraphicBufferAllocator() {}
uint64_t GraphicBufferAllocator::getTotalSize() const {
Mutex::Autolock _l(sLock);
uint64_t total = 0;
for (size_t i = 0; i < sAllocList.size(); ++i) {
total += sAllocList.valueAt(i).size;
}
return total;
}
void GraphicBufferAllocator::dump(std::string& result, bool less) const {
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
uint64_t total = 0;
result.append("GraphicBufferAllocator buffers:\n");
const size_t count = list.size();
StringAppendF(&result, "%14s | %11s | %18s | %s | %8s | %10s | %s\n", "Handle", "Size",
"W (Stride) x H", "Layers", "Format", "Usage", "Requestor");
for (size_t i = 0; i < count; i++) {
const alloc_rec_t& rec(list.valueAt(i));
std::string sizeStr = (rec.size)
? base::StringPrintf("%7.2f KiB", static_cast<double>(rec.size) / 1024.0)
: "unknown";
StringAppendF(&result, "%14p | %11s | %4u (%4u) x %4u | %6u | %8X | 0x%8" PRIx64 " | %s\n",
list.keyAt(i), sizeStr.c_str(), rec.width, rec.stride, rec.height,
rec.layerCount, rec.format, rec.usage, rec.requestorName.c_str());
total += rec.size;
}
StringAppendF(&result, "Total allocated by GraphicBufferAllocator (estimate): %.2f KB\n",
static_cast<double>(total) / 1024.0);
result.append(mAllocator->dumpDebugInfo(less));
}
void GraphicBufferAllocator::dumpToSystemLog(bool less) {
std::string s;
GraphicBufferAllocator::getInstance().dump(s, less);
ALOGD("%s", s.c_str());
}
auto GraphicBufferAllocator::allocate(const AllocationRequest& request) -> AllocationResult {
ATRACE_CALL();
if (!request.width || !request.height) {
return AllocationResult(BAD_VALUE);
}
const auto width = request.width;
const auto height = request.height;
const uint32_t bpp = bytesPerPixel(request.format);
if (std::numeric_limits<size_t>::max() / width / height < static_cast<size_t>(bpp)) {
ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
"usage %" PRIx64 ": Requesting too large a buffer size",
request.width, request.height, request.layerCount, request.format, request.usage);
return AllocationResult(BAD_VALUE);
}
if (request.layerCount < 1) {
return AllocationResult(BAD_VALUE);
}
auto result = mAllocator->allocate(request);
if (result.status == UNKNOWN_TRANSACTION) {
if (!request.extras.empty()) {
ALOGE("Failed to allocate with additional options, allocator version mis-match? "
"gralloc version = %d",
(int)mMapper.getMapperVersion());
return result;
}
// If there's no additional options, fall back to previous allocate version
result.status = mAllocator->allocate(request.requestorName, request.width, request.height,
request.format, request.layerCount, request.usage,
&result.stride, &result.handle, request.importBuffer);
}
if (result.status != NO_ERROR) {
ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
"usage %" PRIx64 ": %d",
request.width, request.height, request.layerCount, request.format, request.usage,
result.status);
return result;
}
if (!request.importBuffer) {
return result;
}
size_t bufSize;
// if stride has no meaning or is too large,
// approximate size with the input width instead
if ((result.stride) != 0 &&
std::numeric_limits<size_t>::max() / height / (result.stride) < static_cast<size_t>(bpp)) {
bufSize = static_cast<size_t>(width) * height * bpp;
} else {
bufSize = static_cast<size_t>((result.stride)) * height * bpp;
}
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
alloc_rec_t rec;
rec.width = width;
rec.height = height;
rec.stride = result.stride;
rec.format = request.format;
rec.layerCount = request.layerCount;
rec.usage = request.usage;
rec.size = bufSize;
rec.requestorName = request.requestorName;
list.add(result.handle, rec);
return result;
}
status_t GraphicBufferAllocator::allocateHelper(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
buffer_handle_t* handle, uint32_t* stride,
std::string requestorName, bool importBuffer) {
ATRACE_CALL();
// make sure to not allocate a N x 0 or 0 x N buffer, since this is
// allowed from an API stand-point allocate a 1x1 buffer instead.
if (!width || !height)
width = height = 1;
const uint32_t bpp = bytesPerPixel(format);
if (std::numeric_limits<size_t>::max() / width / height < static_cast<size_t>(bpp)) {
ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
"usage %" PRIx64 ": Requesting too large a buffer size",
width, height, layerCount, format, usage);
return BAD_VALUE;
}
// Ensure that layerCount is valid.
if (layerCount < 1) {
layerCount = 1;
}
// TODO(b/72323293, b/72703005): Remove these invalid bits from callers
usage &= ~static_cast<uint64_t>((1 << 10) | (1 << 13));
status_t error = mAllocator->allocate(requestorName, width, height, format, layerCount, usage,
stride, handle, importBuffer);
if (error != NO_ERROR) {
ALOGE("Failed to allocate (%u x %u) layerCount %u format %d "
"usage %" PRIx64 ": %d",
width, height, layerCount, format, usage, error);
return error;
}
if (!importBuffer) {
return NO_ERROR;
}
size_t bufSize;
// if stride has no meaning or is too large,
// approximate size with the input width instead
if ((*stride) != 0 &&
std::numeric_limits<size_t>::max() / height / (*stride) < static_cast<size_t>(bpp)) {
bufSize = static_cast<size_t>(width) * height * bpp;
} else {
bufSize = static_cast<size_t>((*stride)) * height * bpp;
}
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
alloc_rec_t rec;
rec.width = width;
rec.height = height;
rec.stride = *stride;
rec.format = format;
rec.layerCount = layerCount;
rec.usage = usage;
rec.size = bufSize;
rec.requestorName = std::move(requestorName);
list.add(*handle, rec);
return NO_ERROR;
}
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
buffer_handle_t* handle, uint32_t* stride,
std::string requestorName) {
return allocateHelper(width, height, format, layerCount, usage, handle, stride, requestorName,
true);
}
status_t GraphicBufferAllocator::allocateRawHandle(uint32_t width, uint32_t height,
PixelFormat format, uint32_t layerCount,
uint64_t usage, buffer_handle_t* handle,
uint32_t* stride, std::string requestorName) {
return allocateHelper(width, height, format, layerCount, usage, handle, stride, requestorName,
false);
}
// DEPRECATED
status_t GraphicBufferAllocator::allocate(uint32_t width, uint32_t height, PixelFormat format,
uint32_t layerCount, uint64_t usage,
buffer_handle_t* handle, uint32_t* stride,
uint64_t /*graphicBufferId*/, std::string requestorName) {
return allocateHelper(width, height, format, layerCount, usage, handle, stride, requestorName,
true);
}
status_t GraphicBufferAllocator::free(buffer_handle_t handle)
{
ATRACE_CALL();
// We allocated a buffer from the allocator and imported it into the
// mapper to get the handle. We just need to free the handle now.
mMapper.freeBuffer(handle);
Mutex::Autolock _l(sLock);
KeyedVector<buffer_handle_t, alloc_rec_t>& list(sAllocList);
list.removeItem(handle);
return NO_ERROR;
}
// ---------------------------------------------------------------------------
}; // namespace android