blob: 97c8186f8c67307d3135d9acdefb034000406843 [file] [log] [blame]
/*
* Copyright 2016 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "cros_gralloc.h"
static struct cros_gralloc_bo *cros_gralloc_bo_create(struct driver *drv,
int width, int height,
int format, int usage)
{
int32_t supported;
uint64_t drv_usage;
uint32_t drv_format;
struct cros_gralloc_bo *bo;
drv_format = cros_gralloc_convert_format(format);
drv_format = drv_resolve_format(drv, drv_format);
drv_usage = cros_gralloc_convert_flags(usage);
supported = drv_is_combination_supported(drv, drv_format, drv_usage,
DRM_FORMAT_MOD_NONE);
if (!supported && (drv_usage & BO_USE_SCANOUT)) {
drv_usage &= ~BO_USE_SCANOUT;
supported = drv_is_combination_supported(drv, drv_format,
drv_usage,
DRM_FORMAT_MOD_NONE);
}
if (!supported && (drv_usage & BO_USE_RENDERING) &&
(drv_usage && (BO_USE_SW_READ_OFTEN | BO_USE_SW_WRITE_OFTEN))) {
drv_usage &= ~BO_USE_RENDERING;
supported = drv_is_combination_supported(drv, drv_format,
drv_usage,
DRM_FORMAT_MOD_NONE);
}
if (!supported) {
cros_gralloc_error("Unsupported combination -- HAL format: %u, "
"HAL flags: %u, drv_format: %u, "
"drv_flags: %llu", format, usage,
drv_format, drv_usage);
return NULL;
}
bo = new cros_gralloc_bo();
memset(bo, 0, sizeof(*bo));
bo->bo = drv_bo_create(drv, width, height, drv_format, drv_usage);
if (!bo->bo) {
delete bo;
cros_gralloc_error("Failed to create bo.");
return NULL;
}
/*
* If there is a desire for more than one kernel buffer, this can be
* removed once the ArcCodec and Wayland service have the ability to
* send more than one fd. GL/Vulkan drivers may also have to modified.
*/
if (drv_num_buffers_per_bo(bo->bo) != 1) {
drv_bo_destroy(bo->bo);
delete bo;
cros_gralloc_error("Can only support one buffer per bo.");
return NULL;
}
bo->refcount = 1;
return bo;
}
static struct cros_gralloc_handle *cros_gralloc_handle_from_bo(struct bo *bo)
{
uint64_t mod;
size_t num_planes;
struct cros_gralloc_handle *hnd;
hnd = new cros_gralloc_handle();
memset(hnd, 0, sizeof(*hnd));
num_planes = drv_bo_get_num_planes(bo);
hnd->base.version = sizeof(hnd->base);
hnd->base.numFds = num_planes;
hnd->base.numInts = num_ints_handle() - num_planes;
for (size_t p = 0; p < num_planes; p++) {
hnd->fds[p] = drv_bo_get_plane_fd(bo, p);
hnd->strides[p] = drv_bo_get_plane_stride(bo, p);
hnd->offsets[p] = drv_bo_get_plane_offset(bo, p);
hnd->sizes[p] = drv_bo_get_plane_size(bo, p);
mod = drv_bo_get_plane_format_modifier(bo, p);
hnd->format_modifiers[p] = static_cast<uint32_t>(mod >> 32);
hnd->format_modifiers[p+1] = static_cast<uint32_t>(mod);
}
hnd->width = drv_bo_get_width(bo);
hnd->height = drv_bo_get_height(bo);
hnd->format = drv_bo_get_format(bo);
hnd->magic = cros_gralloc_magic();
hnd->pixel_stride = hnd->strides[0];
hnd->pixel_stride /= drv_stride_from_format(hnd->format, 1, 0);
return hnd;
}
static int cros_gralloc_alloc(alloc_device_t *dev, int w, int h, int format,
int usage, buffer_handle_t *handle, int *stride)
{
auto mod = (struct cros_gralloc_module *) dev->common.module;
std::lock_guard<std::mutex> lock(mod->mutex);
auto bo = cros_gralloc_bo_create(mod->drv, w, h, format, usage);
if (!bo)
return CROS_GRALLOC_ERROR_NO_RESOURCES;
auto hnd = cros_gralloc_handle_from_bo(bo->bo);
hnd->droid_format = static_cast<int32_t>(format);
hnd->usage = static_cast<int32_t>(usage);
mod->handles[hnd].registrations = 0;
mod->handles[hnd].bo = bo;
bo->hnd = hnd;
mod->buffers[drv_bo_get_plane_handle(bo->bo, 0).u32] = bo;
*stride = static_cast<int>(hnd->pixel_stride);
*handle = &hnd->base;
return CROS_GRALLOC_ERROR_NONE;
}
static int cros_gralloc_free(alloc_device_t *dev, buffer_handle_t handle)
{
struct cros_gralloc_bo *bo;
auto hnd = (struct cros_gralloc_handle *) handle;
auto mod = (struct cros_gralloc_module *) dev->common.module;
std::lock_guard<std::mutex> lock(mod->mutex);
if (cros_gralloc_validate_handle(hnd)) {
cros_gralloc_error("Invalid handle.");
return CROS_GRALLOC_ERROR_BAD_HANDLE;
}
if (cros_gralloc_validate_reference(mod, hnd, &bo)) {
cros_gralloc_error("Invalid Reference.");
return CROS_GRALLOC_ERROR_BAD_HANDLE;
}
if (mod->handles[hnd].registrations > 0) {
cros_gralloc_error("Deallocating before unregistering.");
return CROS_GRALLOC_ERROR_BAD_HANDLE;
}
return cros_gralloc_decrement_reference_count(mod, bo);
}
static int cros_gralloc_close(struct hw_device_t *dev)
{
auto mod = (struct cros_gralloc_module *) dev->module;
auto alloc = (struct alloc_device_t *) dev;
std::lock_guard<std::mutex> lock(mod->mutex);
if (mod->drv) {
drv_destroy(mod->drv);
mod->drv = NULL;
}
mod->buffers.clear();
mod->handles.clear();
delete alloc;
return CROS_GRALLOC_ERROR_NONE;
}
int cros_gralloc_open(const struct hw_module_t *mod, const char *name,
struct hw_device_t **dev)
{
auto module = (struct cros_gralloc_module *) mod;
std::lock_guard<std::mutex> lock(module->mutex);
if (module->drv)
return CROS_GRALLOC_ERROR_NONE;
if (strcmp(name, GRALLOC_HARDWARE_GPU0)) {
cros_gralloc_error("Incorrect device name - %s.", name);
return CROS_GRALLOC_ERROR_UNSUPPORTED;
}
if (cros_gralloc_rendernode_open(&module->drv)) {
cros_gralloc_error("Failed to open render node.");
return CROS_GRALLOC_ERROR_NO_RESOURCES;
}
auto alloc = new alloc_device_t();
memset(alloc, 0, sizeof(*alloc));
alloc->alloc = cros_gralloc_alloc;
alloc->free = cros_gralloc_free;
alloc->common.tag = HARDWARE_DEVICE_TAG;
alloc->common.version = 0;
alloc->common.module = (hw_module_t*) mod;
alloc->common.close = cros_gralloc_close;
*dev = &alloc->common;
return CROS_GRALLOC_ERROR_NONE;
}