We've been back and forth on the semantics of the flag API many times, and the current situation is confusing. Change the drivers so every combination defines a distinct type of buffer. That means if the same format is in the combination list three times, the tiling or format modifiers of one of those combinations must be different from the other two. Let's add a priority variable in struct supported_combination that breaks ties. For example, if a consumer specifies BO_USE_TEXTURE, we of course can texture from both linear and tiled buffers, but because a tiled buffer's priority is greater, it will be chosen. If a consumer specifies BO_USE_TEXTURE | BO_USE_SW_WRITE_OFTEN, the tiled combination won't have the BO_USE_SW_WRITE_OFTEN flag and the linear combination will be chosen. We expect drivers to modify the combinations after querying KMS. This is clunky using linked lists, so get rid of list.h and use arrays. BUG=chromium:616275 TEST=all the following compiles: emerge-cyan minigbm/arc-cros-gralloc emerge-oak minigbm/arc-cros-gralloc emerge-veyron_minnie-cheets minigbm/arc-cros-gralloc emerge-peach_pi minigbm emerge-nyan_big minigbm emerge-jadeite minigbm Tested with gbmtest on cyan, checked if Chrome boots Change-Id: Ib3fccf6f0cb86c8ded45924297df3c06f8e49271 Reviewed-on: https://chromium-review.googlesource.com/448252 Commit-Ready: Gurchetan Singh <gurchetansingh@chromium.org> Tested-by: Gurchetan Singh <gurchetansingh@chromium.org> Reviewed-by: Stéphane Marchesin <marcheu@chromium.org>
204 lines
5.4 KiB
C++
204 lines
5.4 KiB
C++
/*
|
|
* 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)
|
|
{
|
|
uint64_t drv_usage;
|
|
uint32_t drv_format;
|
|
struct combination *combo;
|
|
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);
|
|
|
|
combo = drv_get_combination(drv, drv_format, drv_usage);
|
|
|
|
if (!combo && (usage & GRALLOC_USAGE_HW_COMPOSER)) {
|
|
drv_usage &= ~BO_USE_SCANOUT;
|
|
combo = drv_get_combination(drv, drv_format, drv_usage);
|
|
}
|
|
|
|
if (!combo) {
|
|
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;
|
|
}
|