From 1476c7ea85c1e0334e86ab49b0d7dea59f003e3c Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Fri, 24 Jan 2020 15:05:57 -0800 Subject: [PATCH] gralloc4: adds gralloc4 support Implements the Allocator 4.0 and Mapper 4.0 interfaces. Some notable features of the 4.0 interface: - buffer metadata getter/setters - buffer flushing - buffer debugging (buffer listing and buffer id) Exempt-From-Owner-Approval: OWNERS.android is not being parsed Bug: b/146515640 Test: m && launch_cvd Test: m && launch_cvd --gpu_mode=drm_virgl Change-Id: I27f020b4f661890bcc2817deb09ffb9af1c76f1b --- Android.bp | 98 +- cros_gralloc/cros_gralloc_buffer.cc | 59 +- cros_gralloc/cros_gralloc_buffer.h | 15 +- cros_gralloc/cros_gralloc_driver.cc | 188 +++- cros_gralloc/cros_gralloc_driver.h | 16 +- cros_gralloc/cros_gralloc_handle.h | 33 +- cros_gralloc/cros_gralloc_helpers.cc | 20 +- cros_gralloc/cros_gralloc_helpers.h | 2 +- cros_gralloc/cros_gralloc_types.h | 9 +- cros_gralloc/gralloc0/gralloc0.cc | 9 +- cros_gralloc/gralloc0/tests/gralloctest.c | 9 +- cros_gralloc/gralloc4/.clang-format | 19 + cros_gralloc/gralloc4/Android.bp | 82 ++ cros_gralloc/gralloc4/CrosGralloc4Allocator.cc | 122 +++ cros_gralloc/gralloc4/CrosGralloc4Allocator.h | 26 + .../gralloc4/CrosGralloc4AllocatorService.cc | 30 + cros_gralloc/gralloc4/CrosGralloc4Mapper.cc | 1004 ++++++++++++++++++++ cros_gralloc/gralloc4/CrosGralloc4Mapper.h | 80 ++ cros_gralloc/gralloc4/CrosGralloc4Utils.cc | 772 +++++++++++++++ cros_gralloc/gralloc4/CrosGralloc4Utils.h | 41 + ...dware.graphics.allocator@4.0-service.minigbm.rc | 24 + drv.c | 22 +- drv.h | 2 + helpers.c | 11 + virgl_hw.h | 2 +- virtio_gpu.c | 436 +++++++-- 26 files changed, 2972 insertions(+), 159 deletions(-) create mode 100644 cros_gralloc/gralloc4/.clang-format create mode 100644 cros_gralloc/gralloc4/Android.bp create mode 100644 cros_gralloc/gralloc4/CrosGralloc4Allocator.cc create mode 100644 cros_gralloc/gralloc4/CrosGralloc4Allocator.h create mode 100644 cros_gralloc/gralloc4/CrosGralloc4AllocatorService.cc create mode 100644 cros_gralloc/gralloc4/CrosGralloc4Mapper.cc create mode 100644 cros_gralloc/gralloc4/CrosGralloc4Mapper.h create mode 100644 cros_gralloc/gralloc4/CrosGralloc4Utils.cc create mode 100644 cros_gralloc/gralloc4/CrosGralloc4Utils.h create mode 100644 cros_gralloc/gralloc4/android.hardware.graphics.allocator@4.0-service.minigbm.rc diff --git a/Android.bp b/Android.bp index 63a50f7..02e8e5d 100644 --- a/Android.bp +++ b/Android.bp @@ -2,17 +2,7 @@ // found in the LICENSE file. cc_defaults { - name: "gralloc.minigbm_intel_defaults", - cflags: ["-DDRV_I915"], -} - -cc_defaults { - name: "gralloc.minigbm_meson_defaults", - cflags: ["-DDRV_MESON"], -} - -cc_defaults { - name: "gralloc.minigbm_defaults", + name: "minigbm_defaults", srcs: [ "amdgpu.c", @@ -34,11 +24,6 @@ cc_defaults { "vc4.c", "vgem.c", "virtio_gpu.c", - - "cros_gralloc/cros_gralloc_buffer.cc", - "cros_gralloc/cros_gralloc_driver.cc", - "cros_gralloc/cros_gralloc_helpers.cc", - "cros_gralloc/gralloc0/gralloc0.cc", ], cflags: [ @@ -53,39 +38,79 @@ cc_defaults { ], cppflags: ["-std=c++14"], - // The preferred path for vendor HALs is /vendor/lib/hw vendor: true, - relative_install_path: "hw", header_libs: [ "libhardware_headers", "libnativebase_headers", + "libnativewindow_headers", + "libsystem_headers", + ], + + export_header_lib_headers: [ + "libhardware_headers", + "libnativebase_headers", + "libnativewindow_headers", "libsystem_headers", ], shared_libs: [ "libcutils", "libdrm", - "libnativewindow", "libsync", "liblog", ], static_libs: ["libarect"], + + export_static_lib_headers: ["libarect"], +} + +cc_defaults { + name: "minigbm_cros_gralloc_defaults", + + defaults: ["minigbm_defaults"], + + srcs: [ + "cros_gralloc/cros_gralloc_buffer.cc", + "cros_gralloc/cros_gralloc_helpers.cc", + "cros_gralloc/cros_gralloc_driver.cc", + ] +} + +cc_library_static { + name: "libminigbm", + defaults: ["minigbm_defaults"], + shared_libs: ["liblog"], + static_libs: ["libdrm"], + + srcs: [ + "gbm.c", + "gbm_helpers.c", + ], + + export_include_dirs: ["."], +} + +cc_library_static { + name: "libminigbm_cros_gralloc", + defaults: ["minigbm_cros_gralloc_defaults"], + shared_libs: ["liblog"], + static_libs: ["libdrm"], + + export_include_dirs: ["."], } cc_library_shared { name: "gralloc.minigbm", - defaults: ["gralloc.minigbm_defaults"], + defaults: ["minigbm_cros_gralloc_defaults"], + srcs: ["cros_gralloc/gralloc0/gralloc0.cc"], } cc_library_shared { name: "gralloc.minigbm_intel", - defaults: [ - "gralloc.minigbm_defaults", - "gralloc.minigbm_intel_defaults", - ], + defaults: ["minigbm_cros_gralloc_defaults"], enabled: false, arch: { x86: { @@ -95,26 +120,13 @@ cc_library_shared { enabled: true, }, }, + cflags: ["-DDRV_I915"], + srcs: ["cros_gralloc/gralloc0/gralloc0.cc"], } cc_library_shared { name: "gralloc.minigbm_meson", - defaults: [ - "gralloc.minigbm_defaults", - "gralloc.minigbm_meson_defaults", - ], -} - -cc_library_shared { - name: "libminigbm", - defaults: ["gralloc.minigbm_defaults"], - shared_libs: ["liblog"], - static_libs: ["libdrm"], - - srcs: [ - "gbm.c", - "gbm_helpers.c", - ], - - export_include_dirs: ["."], -} + defaults: ["minigbm_cros_gralloc_defaults"], + cflags: ["-DDRV_MESON"], + srcs: ["cros_gralloc/gralloc0/gralloc0.cc"], +} \ No newline at end of file diff --git a/cros_gralloc/cros_gralloc_buffer.cc b/cros_gralloc/cros_gralloc_buffer.cc index 1066edc..2982505 100644 --- a/cros_gralloc/cros_gralloc_buffer.cc +++ b/cros_gralloc/cros_gralloc_buffer.cc @@ -10,8 +10,11 @@ #include cros_gralloc_buffer::cros_gralloc_buffer(uint32_t id, struct bo *acquire_bo, - struct cros_gralloc_handle *acquire_handle) - : id_(id), bo_(acquire_bo), hnd_(acquire_handle), refcount_(1), lockcount_(0) + struct cros_gralloc_handle *acquire_handle, + int32_t reserved_region_fd, uint64_t reserved_region_size) + : id_(id), bo_(acquire_bo), hnd_(acquire_handle), refcount_(1), lockcount_(0), + reserved_region_fd_(reserved_region_fd), reserved_region_size_(reserved_region_size), + reserved_region_addr_(nullptr) { assert(bo_); num_planes_ = drv_bo_get_num_planes(bo_); @@ -26,6 +29,9 @@ cros_gralloc_buffer::~cros_gralloc_buffer() native_handle_close(&hnd_->base); delete hnd_; } + if (reserved_region_addr_) { + munmap(reserved_region_addr_, reserved_region_size_); + } } uint32_t cros_gralloc_buffer::get_id() const @@ -114,3 +120,52 @@ int32_t cros_gralloc_buffer::resource_info(uint32_t strides[DRV_MAX_PLANES], { return drv_resource_info(bo_, strides, offsets); } + +int32_t cros_gralloc_buffer::invalidate() +{ + if (lockcount_ <= 0) { + drv_log("Buffer was not locked.\n"); + return -EINVAL; + } + + if (lock_data_[0]) { + return drv_bo_invalidate(bo_, lock_data_[0]); + } + + return 0; +} + +int32_t cros_gralloc_buffer::flush() +{ + if (lockcount_ <= 0) { + drv_log("Buffer was not locked.\n"); + return -EINVAL; + } + + if (lock_data_[0]) { + return drv_bo_flush(bo_, lock_data_[0]); + } + + return 0; +} + +int32_t cros_gralloc_buffer::get_reserved_region(void **addr, uint64_t *size) +{ + if (reserved_region_fd_ <= 0) { + drv_log("Buffer does not have reserved region.\n"); + return -EINVAL; + } + + if (!reserved_region_addr_) { + reserved_region_addr_ = mmap(nullptr, reserved_region_size_, PROT_WRITE | PROT_READ, + MAP_SHARED, reserved_region_fd_, 0); + if (reserved_region_addr_ == MAP_FAILED) { + drv_log("Failed to mmap reserved region: %s.\n", strerror(errno)); + return -errno; + } + } + + *addr = reserved_region_addr_; + *size = reserved_region_size_; + return 0; +} diff --git a/cros_gralloc/cros_gralloc_buffer.h b/cros_gralloc/cros_gralloc_buffer.h index ebd72ec..8634882 100644 --- a/cros_gralloc/cros_gralloc_buffer.h +++ b/cros_gralloc/cros_gralloc_buffer.h @@ -14,7 +14,8 @@ class cros_gralloc_buffer { public: cros_gralloc_buffer(uint32_t id, struct bo *acquire_bo, - struct cros_gralloc_handle *acquire_handle); + struct cros_gralloc_handle *acquire_handle, int32_t reserved_region_fd, + uint64_t reserved_region_size); ~cros_gralloc_buffer(); uint32_t get_id() const; @@ -28,12 +29,19 @@ class cros_gralloc_buffer int32_t unlock(); int32_t resource_info(uint32_t strides[DRV_MAX_PLANES], uint32_t offsets[DRV_MAX_PLANES]); + int32_t invalidate(); + int32_t flush(); + + int32_t get_reserved_region(void **reserved_region_addr, uint64_t *reserved_region_size); + private: cros_gralloc_buffer(cros_gralloc_buffer const &); cros_gralloc_buffer operator=(cros_gralloc_buffer const &); uint32_t id_; struct bo *bo_; + + /* Note: this will be nullptr for imported/retained buffers. */ struct cros_gralloc_handle *hnd_; int32_t refcount_; @@ -41,6 +49,11 @@ class cros_gralloc_buffer uint32_t num_planes_; struct mapping *lock_data_[DRV_MAX_PLANES]; + + /* Optional additional shared memory region attached to some gralloc4 buffers. */ + int32_t reserved_region_fd_; + uint64_t reserved_region_size_; + void *reserved_region_addr_; }; #endif diff --git a/cros_gralloc/cros_gralloc_driver.cc b/cros_gralloc/cros_gralloc_driver.cc index 62b43d4..e324bce 100644 --- a/cros_gralloc/cros_gralloc_driver.cc +++ b/cros_gralloc/cros_gralloc_driver.cc @@ -5,12 +5,16 @@ */ #include "cros_gralloc_driver.h" -#include "../util.h" #include #include +#include #include +#include "../drv_priv.h" +#include "../helpers.h" +#include "../util.h" + cros_gralloc_driver::cros_gralloc_driver() : drv_(nullptr) { } @@ -90,15 +94,38 @@ bool cros_gralloc_driver::is_supported(const struct cros_gralloc_buffer_descript return (combo != nullptr); } +int32_t create_reserved_region(const std::string &buffer_name, uint64_t reserved_region_size) +{ + int32_t reserved_region_fd; + std::string reserved_region_name = buffer_name + " reserved region"; + + reserved_region_fd = memfd_create(reserved_region_name.c_str(), FD_CLOEXEC); + if (reserved_region_fd == -1) { + drv_log("Failed to create reserved region fd: %s.\n", strerror(errno)); + return -errno; + } + + if (ftruncate(reserved_region_fd, reserved_region_size)) { + drv_log("Failed to set reserved region size: %s.\n", strerror(errno)); + return -errno; + } + + return reserved_region_fd; +} + int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descriptor *descriptor, buffer_handle_t *out_handle) { uint32_t id; - uint64_t mod; size_t num_planes; + size_t num_fds; + size_t num_ints; + size_t num_bytes; uint32_t resolved_format; uint32_t bytes_per_pixel; uint64_t use_flags; + int32_t reserved_region_fd; + char *name; struct bo *bo; struct cros_gralloc_handle *hnd; @@ -140,41 +167,72 @@ int32_t cros_gralloc_driver::allocate(const struct cros_gralloc_buffer_descripto return -EINVAL; } - hnd = new cros_gralloc_handle(); num_planes = drv_bo_get_num_planes(bo); + num_fds = num_planes; + + if (descriptor->reserved_region_size > 0) { + reserved_region_fd = + create_reserved_region(descriptor->name, descriptor->reserved_region_size); + if (reserved_region_fd < 0) { + drv_bo_destroy(bo); + return reserved_region_fd; + } + num_fds += 1; + } else { + reserved_region_fd = -1; + } + num_bytes = sizeof(struct cros_gralloc_handle); + num_bytes += (descriptor->name.size() + 1); + /* + * Ensure that the total number of bytes is a multiple of sizeof(int) as + * native_handle_clone() copies data based on hnd->base.numInts. + */ + num_bytes = ALIGN(num_bytes, sizeof(int)); + num_ints = num_bytes - sizeof(native_handle_t) - num_fds; + /* + * Malloc is used as handles are ultimetly destroyed via free in + * native_handle_delete(). + */ + hnd = static_cast(malloc(num_bytes)); hnd->base.version = sizeof(hnd->base); - hnd->base.numFds = num_planes; - hnd->base.numInts = handle_data_size - num_planes; - + hnd->base.numFds = num_fds; + hnd->base.numInts = num_ints; + hnd->num_planes = num_planes; for (size_t plane = 0; plane < num_planes; plane++) { hnd->fds[plane] = drv_bo_get_plane_fd(bo, plane); hnd->strides[plane] = drv_bo_get_plane_stride(bo, plane); hnd->offsets[plane] = drv_bo_get_plane_offset(bo, plane); - - mod = drv_bo_get_plane_format_modifier(bo, plane); - hnd->format_modifiers[2 * plane] = static_cast(mod >> 32); - hnd->format_modifiers[2 * plane + 1] = static_cast(mod); + hnd->sizes[plane] = drv_bo_get_plane_size(bo, plane); } - + hnd->fds[hnd->num_planes] = reserved_region_fd; + hnd->reserved_region_size = descriptor->reserved_region_size; + static std::atomic next_buffer_id{ 1 }; + hnd->id = next_buffer_id++; hnd->width = drv_bo_get_width(bo); hnd->height = drv_bo_get_height(bo); hnd->format = drv_bo_get_format(bo); - hnd->use_flags[0] = static_cast(descriptor->use_flags >> 32); - hnd->use_flags[1] = static_cast(descriptor->use_flags); + hnd->format_modifier = drv_bo_get_plane_format_modifier(bo, 0); + hnd->use_flags = descriptor->use_flags; bytes_per_pixel = drv_bytes_per_pixel_from_format(hnd->format, 0); hnd->pixel_stride = DIV_ROUND_UP(hnd->strides[0], bytes_per_pixel); hnd->magic = cros_gralloc_magic; hnd->droid_format = descriptor->droid_format; - hnd->usage = descriptor->producer_usage; + hnd->usage = descriptor->droid_usage; + hnd->total_size = descriptor->reserved_region_size + bo->meta.total_size; + hnd->name_offset = handle_data_size; + + name = (char *)(&hnd->base.data[hnd->name_offset]); + snprintf(name, descriptor->name.size() + 1, "%s", descriptor->name.c_str()); id = drv_bo_get_plane_handle(bo, 0).u32; - auto buffer = new cros_gralloc_buffer(id, bo, hnd); + auto buffer = new cros_gralloc_buffer(id, bo, hnd, hnd->fds[hnd->num_planes], + hnd->reserved_region_size); std::lock_guard lock(mutex_); buffers_.emplace(id, buffer); handles_.emplace(hnd, std::make_pair(buffer, 1)); - *out_handle = &hnd->base; + *out_handle = reinterpret_cast(hnd); return 0; } @@ -208,18 +266,16 @@ int32_t cros_gralloc_driver::retain(buffer_handle_t handle) struct bo *bo; struct drv_import_fd_data data; data.format = hnd->format; + data.width = hnd->width; data.height = hnd->height; - data.use_flags = static_cast(hnd->use_flags[0]) << 32; - data.use_flags |= hnd->use_flags[1]; + data.use_flags = hnd->use_flags; memcpy(data.fds, hnd->fds, sizeof(data.fds)); memcpy(data.strides, hnd->strides, sizeof(data.strides)); memcpy(data.offsets, hnd->offsets, sizeof(data.offsets)); for (uint32_t plane = 0; plane < DRV_MAX_PLANES; plane++) { - data.format_modifiers[plane] = - static_cast(hnd->format_modifiers[2 * plane]) << 32; - data.format_modifiers[plane] |= hnd->format_modifiers[2 * plane + 1]; + data.format_modifiers[plane] = hnd->format_modifier; } bo = drv_bo_import(drv_, &data); @@ -228,7 +284,8 @@ int32_t cros_gralloc_driver::retain(buffer_handle_t handle) id = drv_bo_get_plane_handle(bo, 0).u32; - buffer = new cros_gralloc_buffer(id, bo, nullptr); + buffer = new cros_gralloc_buffer(id, bo, nullptr, hnd->fds[hnd->num_planes], + hnd->reserved_region_size); buffers_.emplace(id, buffer); } @@ -264,10 +321,10 @@ int32_t cros_gralloc_driver::release(buffer_handle_t handle) } int32_t cros_gralloc_driver::lock(buffer_handle_t handle, int32_t acquire_fence, - const struct rectangle *rect, uint32_t map_flags, - uint8_t *addr[DRV_MAX_PLANES]) + bool close_acquire_fence, const struct rectangle *rect, + uint32_t map_flags, uint8_t *addr[DRV_MAX_PLANES]) { - int32_t ret = cros_gralloc_sync_wait(acquire_fence); + int32_t ret = cros_gralloc_sync_wait(acquire_fence, close_acquire_fence); if (ret) return ret; @@ -313,6 +370,51 @@ int32_t cros_gralloc_driver::unlock(buffer_handle_t handle, int32_t *release_fen return buffer->unlock(); } +int32_t cros_gralloc_driver::invalidate(buffer_handle_t handle) +{ + std::lock_guard lock(mutex_); + + auto hnd = cros_gralloc_convert_handle(handle); + if (!hnd) { + drv_log("Invalid handle.\n"); + return -EINVAL; + } + + auto buffer = get_buffer(hnd); + if (!buffer) { + drv_log("Invalid Reference.\n"); + return -EINVAL; + } + + return buffer->invalidate(); +} + +int32_t cros_gralloc_driver::flush(buffer_handle_t handle, int32_t *release_fence) +{ + std::lock_guard lock(mutex_); + + auto hnd = cros_gralloc_convert_handle(handle); + if (!hnd) { + drv_log("Invalid handle.\n"); + return -EINVAL; + } + + auto buffer = get_buffer(hnd); + if (!buffer) { + drv_log("Invalid Reference.\n"); + return -EINVAL; + } + + /* + * From the ANativeWindow::dequeueBuffer documentation: + * + * "A value of -1 indicates that the caller may access the buffer immediately without + * waiting on a fence." + */ + *release_fence = -1; + return buffer->flush(); +} + int32_t cros_gralloc_driver::get_backing_store(buffer_handle_t handle, uint64_t *out_store) { std::lock_guard lock(mutex_); @@ -353,6 +455,32 @@ int32_t cros_gralloc_driver::resource_info(buffer_handle_t handle, uint32_t stri return buffer->resource_info(strides, offsets); } +int32_t cros_gralloc_driver::get_reserved_region(buffer_handle_t handle, + void **reserved_region_addr, + uint64_t *reserved_region_size) +{ + std::lock_guard lock(mutex_); + + auto hnd = cros_gralloc_convert_handle(handle); + if (!hnd) { + drv_log("Invalid handle.\n"); + return -EINVAL; + } + + auto buffer = get_buffer(hnd); + if (!buffer) { + drv_log("Invalid Reference.\n"); + return -EINVAL; + } + + return buffer->get_reserved_region(reserved_region_addr, reserved_region_size); +} + +uint32_t cros_gralloc_driver::get_resolved_drm_format(uint32_t drm_format, uint64_t usage) +{ + return drv_resolve_format(drv_, drm_format, usage); +} + cros_gralloc_buffer *cros_gralloc_driver::get_buffer(cros_gralloc_handle_t hnd) { /* Assumes driver mutex is held. */ @@ -361,3 +489,13 @@ cros_gralloc_buffer *cros_gralloc_driver::get_buffer(cros_gralloc_handle_t hnd) return nullptr; } + +void cros_gralloc_driver::for_each_handle( + const std::function &function) +{ + std::lock_guard lock(mutex_); + + for (const auto &pair : handles_) { + function(pair.first); + } +} \ No newline at end of file diff --git a/cros_gralloc/cros_gralloc_driver.h b/cros_gralloc/cros_gralloc_driver.h index f051277..d444ecd 100644 --- a/cros_gralloc/cros_gralloc_driver.h +++ b/cros_gralloc/cros_gralloc_driver.h @@ -9,6 +9,7 @@ #include "cros_gralloc_buffer.h" +#include #include #include @@ -26,14 +27,25 @@ class cros_gralloc_driver int32_t retain(buffer_handle_t handle); int32_t release(buffer_handle_t handle); - int32_t lock(buffer_handle_t handle, int32_t acquire_fence, const struct rectangle *rect, - uint32_t map_flags, uint8_t *addr[DRV_MAX_PLANES]); + int32_t lock(buffer_handle_t handle, int32_t acquire_fence, bool close_acquire_fence, + const struct rectangle *rect, uint32_t map_flags, + uint8_t *addr[DRV_MAX_PLANES]); int32_t unlock(buffer_handle_t handle, int32_t *release_fence); + int32_t invalidate(buffer_handle_t handle); + int32_t flush(buffer_handle_t handle, int32_t *release_fence); + int32_t get_backing_store(buffer_handle_t handle, uint64_t *out_store); int32_t resource_info(buffer_handle_t handle, uint32_t strides[DRV_MAX_PLANES], uint32_t offsets[DRV_MAX_PLANES]); + int32_t get_reserved_region(buffer_handle_t handle, void **reserved_region_addr, + uint64_t *reserved_region_size); + + uint32_t get_resolved_drm_format(uint32_t drm_format, uint64_t usage); + + void for_each_handle(const std::function &function); + private: cros_gralloc_driver(cros_gralloc_driver const &); cros_gralloc_driver operator=(cros_gralloc_driver const &); diff --git a/cros_gralloc/cros_gralloc_handle.h b/cros_gralloc/cros_gralloc_handle.h index cd3edfe..d2e1607 100644 --- a/cros_gralloc/cros_gralloc_handle.h +++ b/cros_gralloc/cros_gralloc_handle.h @@ -11,27 +11,40 @@ #include #define DRV_MAX_PLANES 4 - -/* - * Only use 32-bit integers in the handle. This guarantees that the handle is - * densely packed (i.e, the compiler does not insert any padding). - */ +#define DRV_MAX_FDS (DRV_MAX_PLANES + 1) struct cros_gralloc_handle { native_handle_t base; - int32_t fds[DRV_MAX_PLANES]; + /* + * File descriptors must immediately follow the native_handle_t base and used file + * descriptors must be packed at the beginning of this array to work with + * native_handle_clone(). + * + * This field contains 'num_planes' plane file descriptors followed by an optional metadata + * reserved region file descriptor if 'reserved_region_size' is greater than zero. + */ + int32_t fds[DRV_MAX_FDS]; uint32_t strides[DRV_MAX_PLANES]; uint32_t offsets[DRV_MAX_PLANES]; - uint32_t format_modifiers[2 * DRV_MAX_PLANES]; + uint32_t sizes[DRV_MAX_PLANES]; + uint32_t id; uint32_t width; uint32_t height; - uint32_t format; /* DRM format */ - uint32_t use_flags[2]; /* Buffer creation flags */ + uint32_t format; /* DRM format */ + uint64_t format_modifier; + uint64_t use_flags; /* Buffer creation flags */ uint32_t magic; uint32_t pixel_stride; int32_t droid_format; int32_t usage; /* Android usage. */ -}; + uint32_t num_planes; + uint64_t reserved_region_size; + uint64_t total_size; /* Total allocation size */ + /* + * Name is a null terminated char array located at handle->base.data[handle->name_offset]. + */ + uint32_t name_offset; +} __attribute__((packed)); typedef const struct cros_gralloc_handle *cros_gralloc_handle_t; diff --git a/cros_gralloc/cros_gralloc_helpers.cc b/cros_gralloc/cros_gralloc_helpers.cc index 73e59cb..1e05150 100644 --- a/cros_gralloc/cros_gralloc_helpers.cc +++ b/cros_gralloc/cros_gralloc_helpers.cc @@ -20,6 +20,8 @@ uint32_t cros_gralloc_convert_format(int format) return DRM_FORMAT_ARGB8888; case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED: return DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED; + case HAL_PIXEL_FORMAT_RAW16: + return DRM_FORMAT_R16; case HAL_PIXEL_FORMAT_RGB_565: return DRM_FORMAT_RGB565; case HAL_PIXEL_FORMAT_RGB_888: @@ -59,29 +61,31 @@ cros_gralloc_handle_t cros_gralloc_convert_handle(buffer_handle_t handle) return hnd; } -int32_t cros_gralloc_sync_wait(int32_t acquire_fence) +int32_t cros_gralloc_sync_wait(int32_t fence, bool close_fence) { - if (acquire_fence < 0) + if (fence < 0) return 0; /* * Wait initially for 1000 ms, and then wait indefinitely. The SYNC_IOC_WAIT * documentation states the caller waits indefinitely on the fence if timeout < 0. */ - int err = sync_wait(acquire_fence, 1000); + int err = sync_wait(fence, 1000); if (err < 0) { drv_log("Timed out on sync wait, err = %s\n", strerror(errno)); - err = sync_wait(acquire_fence, -1); + err = sync_wait(fence, -1); if (err < 0) { drv_log("sync wait error = %s\n", strerror(errno)); return -errno; } } - err = close(acquire_fence); - if (err) { - drv_log("Unable to close fence fd, err = %s\n", strerror(errno)); - return -errno; + if (close_fence) { + err = close(fence); + if (err) { + drv_log("Unable to close fence fd, err = %s\n", strerror(errno)); + return -errno; + } } return 0; diff --git a/cros_gralloc/cros_gralloc_helpers.h b/cros_gralloc/cros_gralloc_helpers.h index a55eebc..36f86ef 100644 --- a/cros_gralloc/cros_gralloc_helpers.h +++ b/cros_gralloc/cros_gralloc_helpers.h @@ -22,6 +22,6 @@ uint32_t cros_gralloc_convert_format(int32_t format); cros_gralloc_handle_t cros_gralloc_convert_handle(buffer_handle_t handle); -int32_t cros_gralloc_sync_wait(int32_t acquire_fence); +int32_t cros_gralloc_sync_wait(int32_t fence, bool close_fence); #endif diff --git a/cros_gralloc/cros_gralloc_types.h b/cros_gralloc/cros_gralloc_types.h index 1fa81de..22f58e2 100644 --- a/cros_gralloc/cros_gralloc_types.h +++ b/cros_gralloc/cros_gralloc_types.h @@ -7,14 +7,17 @@ #ifndef CROS_GRALLOC_TYPES_H #define CROS_GRALLOC_TYPES_H +#include + struct cros_gralloc_buffer_descriptor { uint32_t width; uint32_t height; - uint32_t consumer_usage; - uint32_t producer_usage; - uint32_t droid_format; + int32_t droid_format; + int32_t droid_usage; uint32_t drm_format; uint64_t use_flags; + uint64_t reserved_region_size; + std::string name; }; #endif diff --git a/cros_gralloc/gralloc0/gralloc0.cc b/cros_gralloc/gralloc0/gralloc0.cc index a70498a..170dae9 100644 --- a/cros_gralloc/gralloc0/gralloc0.cc +++ b/cros_gralloc/gralloc0/gralloc0.cc @@ -119,9 +119,10 @@ static int gralloc0_alloc(alloc_device_t *dev, int w, int h, int format, int usa descriptor.width = w; descriptor.height = h; descriptor.droid_format = format; - descriptor.producer_usage = descriptor.consumer_usage = usage; + descriptor.droid_usage = usage; descriptor.drm_format = cros_gralloc_convert_format(format); descriptor.use_flags = gralloc0_convert_usage(usage); + descriptor.reserved_region_size = 0; supported = mod->driver->is_supported(&descriptor); if (!supported && (usage & GRALLOC_USAGE_HW_COMPOSER)) { @@ -248,7 +249,7 @@ static int gralloc0_unlock(struct gralloc_module_t const *module, buffer_handle_ if (ret) return ret; - ret = cros_gralloc_sync_wait(fence_fd); + ret = cros_gralloc_sync_wait(fence_fd, /*close_acquire_fence=*/true); if (ret) return ret; @@ -359,7 +360,7 @@ static int gralloc0_lock_async(struct gralloc_module_t const *module, buffer_han assert(h >= 0); map_flags = gralloc0_convert_map_usage(usage); - ret = mod->driver->lock(handle, fence_fd, &rect, map_flags, addr); + ret = mod->driver->lock(handle, fence_fd, true, &rect, map_flags, addr); *vaddr = addr[0]; return ret; } @@ -404,7 +405,7 @@ static int gralloc0_lock_async_ycbcr(struct gralloc_module_t const *module, buff assert(h >= 0); map_flags = gralloc0_convert_map_usage(usage); - ret = mod->driver->lock(handle, fence_fd, &rect, map_flags, addr); + ret = mod->driver->lock(handle, fence_fd, true, &rect, map_flags, addr); if (ret) return ret; diff --git a/cros_gralloc/gralloc0/tests/gralloctest.c b/cros_gralloc/gralloc0/tests/gralloctest.c index 8dfcd0b..f663cd0 100644 --- a/cros_gralloc/gralloc0/tests/gralloctest.c +++ b/cros_gralloc/gralloc0/tests/gralloctest.c @@ -42,10 +42,11 @@ } while (0) /* Private API enumeration -- see */ -enum { GRALLOC_DRM_GET_STRIDE, - GRALLOC_DRM_GET_FORMAT, - GRALLOC_DRM_GET_DIMENSIONS, - GRALLOC_DRM_GET_BACKING_STORE, +enum { + GRALLOC_DRM_GET_STRIDE, + GRALLOC_DRM_GET_FORMAT, + GRALLOC_DRM_GET_DIMENSIONS, + GRALLOC_DRM_GET_BACKING_STORE, }; struct gralloctest_context { diff --git a/cros_gralloc/gralloc4/.clang-format b/cros_gralloc/gralloc4/.clang-format new file mode 100644 index 0000000..b310cc1 --- /dev/null +++ b/cros_gralloc/gralloc4/.clang-format @@ -0,0 +1,19 @@ +# Copyright 2020 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. +# +# This directory is formatted to match the format of the interfaces implemented. + +BasedOnStyle: Google +Standard: Cpp11 +AccessModifierOffset: -2 +AllowShortFunctionsOnASingleLine: Inline +ColumnLimit: 100 +CommentPragmas: NOLINT:.* +DerivePointerAlignment: false +IncludeBlocks: Preserve +IndentWidth: 4 +ContinuationIndentWidth: 8 +PointerAlignment: Left +TabWidth: 4 +UseTab: Never \ No newline at end of file diff --git a/cros_gralloc/gralloc4/Android.bp b/cros_gralloc/gralloc4/Android.bp new file mode 100644 index 0000000..a0a8622 --- /dev/null +++ b/cros_gralloc/gralloc4/Android.bp @@ -0,0 +1,82 @@ +/* + * Copyright 2020 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. + */ + +cc_binary { + name: "android.hardware.graphics.allocator@4.0-service.minigbm", + relative_install_path: "hw", + vendor: true, + init_rc: ["android.hardware.graphics.allocator@4.0-service.minigbm.rc"], + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "android.hardware.graphics.allocator@4.0", + "android.hardware.graphics.mapper@4.0", + "libbase", + "libcutils", + "libgralloctypes", + "libhidlbase", + "liblog", + "libsync", + "libutils", + ], + + static_libs: [ + "libdrm", + "libminigbm_cros_gralloc", + ], + + srcs: [ + "CrosGralloc4Allocator.cc", + "CrosGralloc4AllocatorService.cc", + "CrosGralloc4Utils.cc", + ], +} + +cc_library_shared { + name: "android.hardware.graphics.mapper@4.0-impl.minigbm", + relative_install_path: "hw", + vendor: true, + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "android.hardware.graphics.mapper@4.0", + "libbase", + "libcutils", + "libgralloctypes", + "libhidlbase", + "liblog", + "libsync", + "libutils", + ], + + static_libs: [ + "libdrm", + "libminigbm_cros_gralloc", + ], + + srcs: [ + "CrosGralloc4Mapper.cc", + "CrosGralloc4Utils.cc", + ], +} diff --git a/cros_gralloc/gralloc4/CrosGralloc4Allocator.cc b/cros_gralloc/gralloc4/CrosGralloc4Allocator.cc new file mode 100644 index 0000000..4fb7845 --- /dev/null +++ b/cros_gralloc/gralloc4/CrosGralloc4Allocator.cc @@ -0,0 +1,122 @@ +/* + * Copyright 2020 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/gralloc4/CrosGralloc4Allocator.h" + +#include +#include + +#include "cros_gralloc/cros_gralloc_helpers.h" +#include "cros_gralloc/gralloc4/CrosGralloc4Utils.h" + +using android::hardware::hidl_handle; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::graphics::common::V1_2::BufferUsage; +using android::hardware::graphics::common::V1_2::PixelFormat; +using android::hardware::graphics::mapper::V4_0::Error; + +using BufferDescriptorInfo = + android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo; + +CrosGralloc4Allocator::CrosGralloc4Allocator() : mDriver(std::make_unique()) { + if (mDriver->init()) { + drv_log("Failed to initialize driver.\n"); + mDriver = nullptr; + } +} + +Error CrosGralloc4Allocator::allocate(const BufferDescriptorInfo& descriptor, uint32_t* outStride, + hidl_handle* outHandle) { + if (!mDriver) { + drv_log("Failed to allocate. Driver is uninitialized.\n"); + return Error::NO_RESOURCES; + } + + if (!outStride || !outHandle) { + return Error::NO_RESOURCES; + } + + struct cros_gralloc_buffer_descriptor crosDescriptor; + if (convertToCrosDescriptor(descriptor, &crosDescriptor)) { + return Error::UNSUPPORTED; + } + + bool supported = mDriver->is_supported(&crosDescriptor); + if (!supported && (descriptor.usage & BufferUsage::COMPOSER_OVERLAY)) { + crosDescriptor.use_flags &= ~BO_USE_SCANOUT; + supported = mDriver->is_supported(&crosDescriptor); + } + + if (!supported) { + std::string drmFormatString = getDrmFormatString(crosDescriptor.drm_format); + std::string pixelFormatString = getPixelFormatString(descriptor.format); + std::string usageString = getUsageString(descriptor.usage); + drv_log("Unsupported combination -- pixel format: %s, drm format:%s, usage: %s\n", + pixelFormatString.c_str(), drmFormatString.c_str(), usageString.c_str()); + return Error::UNSUPPORTED; + } + + buffer_handle_t handle; + int ret = mDriver->allocate(&crosDescriptor, &handle); + if (ret) { + return Error::NO_RESOURCES; + } + + cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(handle); + if (!crosHandle) { + return Error::NO_RESOURCES; + } + + *outHandle = handle; + *outStride = crosHandle->pixel_stride; + + return Error::NONE; +} + +Return CrosGralloc4Allocator::allocate(const hidl_vec& descriptor, uint32_t count, + allocate_cb hidlCb) { + hidl_vec handles; + + if (!mDriver) { + drv_log("Failed to allocate. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, 0, handles); + return Void(); + } + + BufferDescriptorInfo description; + + int ret = android::gralloc4::decodeBufferDescriptorInfo(descriptor, &description); + if (ret) { + drv_log("Failed to allocate. Failed to decode buffer descriptor: %d.\n", ret); + hidlCb(Error::BAD_DESCRIPTOR, 0, handles); + return Void(); + } + + handles.resize(count); + + uint32_t stride = 0; + for (int i = 0; i < handles.size(); i++) { + Error err = allocate(description, &stride, &(handles[i])); + if (err != Error::NONE) { + for (int j = 0; j < i; j++) { + mDriver->release(handles[j].getNativeHandle()); + } + handles.resize(0); + hidlCb(err, 0, handles); + return Void(); + } + } + + hidlCb(Error::NONE, stride, handles); + + for (const hidl_handle& handle : handles) { + mDriver->release(handle.getNativeHandle()); + } + + return Void(); +} diff --git a/cros_gralloc/gralloc4/CrosGralloc4Allocator.h b/cros_gralloc/gralloc4/CrosGralloc4Allocator.h new file mode 100644 index 0000000..21ad7ad --- /dev/null +++ b/cros_gralloc/gralloc4/CrosGralloc4Allocator.h @@ -0,0 +1,26 @@ +/* + * Copyright 2020 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 +#include + +#include "cros_gralloc/cros_gralloc_driver.h" + +class CrosGralloc4Allocator : public android::hardware::graphics::allocator::V4_0::IAllocator { + public: + CrosGralloc4Allocator(); + + android::hardware::Return allocate(const android::hardware::hidl_vec& descriptor, + uint32_t count, allocate_cb hidl_cb) override; + + private: + android::hardware::graphics::mapper::V4_0::Error allocate( + const android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo& + description, + uint32_t* outStride, android::hardware::hidl_handle* outHandle); + + std::unique_ptr mDriver; +}; diff --git a/cros_gralloc/gralloc4/CrosGralloc4AllocatorService.cc b/cros_gralloc/gralloc4/CrosGralloc4AllocatorService.cc new file mode 100644 index 0000000..5b79860 --- /dev/null +++ b/cros_gralloc/gralloc4/CrosGralloc4AllocatorService.cc @@ -0,0 +1,30 @@ +/* + * Copyright 2020 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. + */ + +#define LOG_TAG "AllocatorService" + +#include + +#include "cros_gralloc/gralloc4/CrosGralloc4Allocator.h" + +using android::sp; +using android::hardware::configureRpcThreadpool; +using android::hardware::joinRpcThreadpool; +using android::hardware::graphics::allocator::V4_0::IAllocator; + +int main(int, char**) { + sp allocator = new CrosGralloc4Allocator(); + configureRpcThreadpool(4, true /* callerWillJoin */); + if (allocator->registerAsService() != android::NO_ERROR) { + ALOGE("failed to register graphics IAllocator 4.0 service"); + return -EINVAL; + } + + ALOGI("graphics IAllocator 4.0 service is initialized"); + android::hardware::joinRpcThreadpool(); + ALOGI("graphics IAllocator 4.0 service is terminating"); + return 0; +} diff --git a/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc b/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc new file mode 100644 index 0000000..47e24ac --- /dev/null +++ b/cros_gralloc/gralloc4/CrosGralloc4Mapper.cc @@ -0,0 +1,1004 @@ +/* + * Copyright 2020 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/gralloc4/CrosGralloc4Mapper.h" + +#include +#include +#include +#include +#include +#include + +#include "cros_gralloc/gralloc4/CrosGralloc4Utils.h" +#include "helpers.h" + +using aidl::android::hardware::graphics::common::BlendMode; +using aidl::android::hardware::graphics::common::Dataspace; +using aidl::android::hardware::graphics::common::PlaneLayout; +using aidl::android::hardware::graphics::common::Rect; +using android::hardware::hidl_handle; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::Void; +using android::hardware::graphics::common::V1_2::BufferUsage; +using android::hardware::graphics::common::V1_2::PixelFormat; +using android::hardware::graphics::mapper::V4_0::Error; +using android::hardware::graphics::mapper::V4_0::IMapper; + +CrosGralloc4Mapper::CrosGralloc4Mapper() : mDriver(std::make_unique()) { + if (mDriver->init()) { + drv_log("Failed to initialize driver.\n"); + mDriver = nullptr; + } +} + +Return CrosGralloc4Mapper::createDescriptor(const BufferDescriptorInfo& description, + createDescriptor_cb hidlCb) { + hidl_vec descriptor; + + if (description.width == 0) { + drv_log("Failed to createDescriptor. Bad width: %d.\n", description.width); + hidlCb(Error::BAD_VALUE, descriptor); + return Void(); + } + + if (description.height == 0) { + drv_log("Failed to createDescriptor. Bad height: %d.\n", description.height); + hidlCb(Error::BAD_VALUE, descriptor); + return Void(); + } + + if (description.layerCount == 0) { + drv_log("Failed to createDescriptor. Bad layer count: %d.\n", description.layerCount); + hidlCb(Error::BAD_VALUE, descriptor); + return Void(); + } + + int ret = android::gralloc4::encodeBufferDescriptorInfo(description, &descriptor); + if (ret) { + drv_log("Failed to createDescriptor. Failed to encode: %d.\n", ret); + hidlCb(Error::BAD_VALUE, descriptor); + return Void(); + } + + hidlCb(Error::NONE, descriptor); + return Void(); +} + +Return CrosGralloc4Mapper::importBuffer(const hidl_handle& handle, importBuffer_cb hidlCb) { + if (!mDriver) { + drv_log("Failed to import buffer. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + const native_handle_t* bufferHandle = handle.getNativeHandle(); + if (!bufferHandle || bufferHandle->numFds == 0) { + drv_log("Failed to importBuffer. Bad handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + native_handle_t* importedBufferHandle = native_handle_clone(bufferHandle); + if (!importedBufferHandle) { + drv_log("Failed to importBuffer. Handle clone failed.\n"); + hidlCb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + int ret = mDriver->retain(importedBufferHandle); + if (ret) { + native_handle_close(importedBufferHandle); + native_handle_delete(importedBufferHandle); + hidlCb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + hidlCb(Error::NONE, importedBufferHandle); + return Void(); +} + +Return CrosGralloc4Mapper::freeBuffer(void* rawHandle) { + if (!mDriver) { + drv_log("Failed to freeBuffer. Driver is uninitialized.\n"); + return Error::NO_RESOURCES; + } + + native_handle_t* bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to freeBuffer. Empty handle.\n"); + return Error::BAD_BUFFER; + } + + int ret = mDriver->release(bufferHandle); + if (ret) { + return Error::BAD_BUFFER; + } + + native_handle_close(bufferHandle); + native_handle_delete(bufferHandle); + return Error::NONE; +} + +Return CrosGralloc4Mapper::validateBufferSize(void* rawHandle, + const BufferDescriptorInfo& descriptor, + uint32_t stride) { + if (!mDriver) { + drv_log("Failed to validateBufferSize. Driver is uninitialized.\n"); + return Error::NO_RESOURCES; + } + + native_handle_t* bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to validateBufferSize. Empty handle.\n"); + return Error::BAD_BUFFER; + } + + cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); + if (!crosHandle) { + drv_log("Failed to validateBufferSize. Invalid handle.\n"); + return Error::BAD_BUFFER; + } + + PixelFormat crosHandleFormat = static_cast(crosHandle->droid_format); + if (descriptor.format != crosHandleFormat) { + drv_log("Failed to validateBufferSize. Format mismatch.\n"); + return Error::BAD_BUFFER; + } + + if (descriptor.width != crosHandle->width) { + drv_log("Failed to validateBufferSize. Width mismatch (%d vs %d).\n", descriptor.width, + crosHandle->width); + return Error::BAD_VALUE; + } + + if (descriptor.height != crosHandle->height) { + drv_log("Failed to validateBufferSize. Height mismatch (%d vs %d).\n", descriptor.height, + crosHandle->height); + return Error::BAD_VALUE; + } + + if (stride != crosHandle->pixel_stride) { + drv_log("Failed to validateBufferSize. Stride mismatch (%d vs %d).\n", stride, + crosHandle->pixel_stride); + return Error::BAD_VALUE; + } + + return Error::NONE; +} + +Return CrosGralloc4Mapper::getTransportSize(void* rawHandle, getTransportSize_cb hidlCb) { + if (!mDriver) { + drv_log("Failed to getTransportSize. Driver is uninitialized.\n"); + hidlCb(Error::BAD_BUFFER, 0, 0); + return Void(); + } + + native_handle_t* bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to getTransportSize. Bad handle.\n"); + hidlCb(Error::BAD_BUFFER, 0, 0); + return Void(); + } + + // No local process data is currently stored on the native handle. + hidlCb(Error::NONE, bufferHandle->numFds, bufferHandle->numInts); + return Void(); +} + +Return CrosGralloc4Mapper::lock(void* rawBuffer, uint64_t cpuUsage, const Rect& region, + const hidl_handle& acquireFence, lock_cb hidlCb) { + if (!mDriver) { + drv_log("Failed to lock. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawBuffer); + if (!bufferHandle) { + drv_log("Failed to lock. Empty handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + if (cpuUsage == 0) { + drv_log("Failed to lock. Bad cpu usage: %" PRIu64 ".\n", cpuUsage); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + uint32_t mapUsage = 0; + int ret = convertToMapUsage(cpuUsage, &mapUsage); + if (ret) { + drv_log("Failed to lock. Convert usage failed.\n"); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); + if (crosHandle == nullptr) { + drv_log("Failed to lock. Invalid handle.\n"); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + if (region.left < 0) { + drv_log("Failed to lock. Invalid region: negative left value %d.\n", region.left); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + if (region.top < 0) { + drv_log("Failed to lock. Invalid region: negative top value %d.\n", region.top); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + if (region.width < 0) { + drv_log("Failed to lock. Invalid region: negative width value %d.\n", region.width); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + if (region.height < 0) { + drv_log("Failed to lock. Invalid region: negative height value %d.\n", region.height); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + if (region.width > crosHandle->width) { + drv_log("Failed to lock. Invalid region: width greater than buffer width (%d vs %d).\n", + region.width, crosHandle->width); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + if (region.height > crosHandle->height) { + drv_log("Failed to lock. Invalid region: height greater than buffer height (%d vs %d).\n", + region.height, crosHandle->height); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + struct rectangle rect = {static_cast(region.left), static_cast(region.top), + static_cast(region.width), + static_cast(region.height)}; + + // An access region of all zeros means the entire buffer. + if (rect.x == 0 && rect.y == 0 && rect.width == 0 && rect.height == 0) { + rect.width = crosHandle->width; + rect.height = crosHandle->height; + } + + int acquireFenceFd = -1; + ret = convertToFenceFd(acquireFence, &acquireFenceFd); + if (ret) { + drv_log("Failed to lock. Bad acquire fence.\n"); + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + uint8_t* addr[DRV_MAX_PLANES]; + ret = mDriver->lock(bufferHandle, acquireFenceFd, /*close_acquire_fence=*/false, &rect, + mapUsage, addr); + if (ret) { + hidlCb(Error::BAD_VALUE, nullptr); + return Void(); + } + + hidlCb(Error::NONE, addr[0]); + return Void(); +} + +Return CrosGralloc4Mapper::unlock(void* rawHandle, unlock_cb hidlCb) { + if (!mDriver) { + drv_log("Failed to unlock. Driver is uninitialized.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to unlock. Empty handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + int releaseFenceFd = -1; + int ret = mDriver->unlock(bufferHandle, &releaseFenceFd); + if (ret) { + drv_log("Failed to unlock.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + hidl_handle releaseFenceHandle; + ret = convertToFenceHandle(releaseFenceFd, &releaseFenceHandle); + if (ret) { + drv_log("Failed to unlock. Failed to convert release fence to handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + hidlCb(Error::NONE, releaseFenceHandle); + return Void(); +} + +Return CrosGralloc4Mapper::flushLockedBuffer(void* rawHandle, flushLockedBuffer_cb hidlCb) { + if (!mDriver) { + drv_log("Failed to flushLockedBuffer. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, nullptr); + return Void(); + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to flushLockedBuffer. Empty handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + int releaseFenceFd = -1; + int ret = mDriver->flush(bufferHandle, &releaseFenceFd); + if (ret) { + drv_log("Failed to flushLockedBuffer. Flush failed.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + hidl_handle releaseFenceHandle; + ret = convertToFenceHandle(releaseFenceFd, &releaseFenceHandle); + if (ret) { + drv_log("Failed to flushLockedBuffer. Failed to convert release fence to handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr); + return Void(); + } + + hidlCb(Error::NONE, releaseFenceHandle); + return Void(); +} + +Return CrosGralloc4Mapper::rereadLockedBuffer(void* rawHandle) { + if (!mDriver) { + drv_log("Failed to rereadLockedBuffer. Driver is uninitialized.\n"); + return Error::NO_RESOURCES; + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to rereadLockedBuffer. Empty handle.\n"); + return Error::BAD_BUFFER; + } + + int ret = mDriver->invalidate(bufferHandle); + if (ret) { + drv_log("Failed to rereadLockedBuffer. Failed to invalidate.\n"); + return Error::BAD_BUFFER; + } + + return Error::NONE; +} + +Return CrosGralloc4Mapper::isSupported(const BufferDescriptorInfo& descriptor, + isSupported_cb hidlCb) { + if (!mDriver) { + drv_log("Failed to isSupported. Driver is uninitialized.\n"); + hidlCb(Error::BAD_VALUE, false); + return Void(); + } + + struct cros_gralloc_buffer_descriptor crosDescriptor; + if (convertToCrosDescriptor(descriptor, &crosDescriptor)) { + hidlCb(Error::NONE, false); + return Void(); + } + + bool supported = mDriver->is_supported(&crosDescriptor); + if (!supported) { + crosDescriptor.use_flags &= ~BO_USE_SCANOUT; + supported = mDriver->is_supported(&crosDescriptor); + } + + hidlCb(Error::NONE, supported); + return Void(); +} + +Return CrosGralloc4Mapper::get(void* rawHandle, const MetadataType& metadataType, + get_cb hidlCb) { + hidl_vec encodedMetadata; + + if (!mDriver) { + drv_log("Failed to get. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, encodedMetadata); + return Void(); + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to get. Empty handle.\n"); + hidlCb(Error::BAD_BUFFER, encodedMetadata); + return Void(); + } + + cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); + if (!crosHandle) { + drv_log("Failed to get. Invalid handle.\n"); + hidlCb(Error::BAD_BUFFER, encodedMetadata); + return Void(); + } + + get(crosHandle, metadataType, hidlCb); + return Void(); +} + +Return CrosGralloc4Mapper::get(cros_gralloc_handle_t crosHandle, + const MetadataType& metadataType, get_cb hidlCb) { + hidl_vec encodedMetadata; + + if (!mDriver) { + drv_log("Failed to get. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, encodedMetadata); + return Void(); + } + + if (!crosHandle) { + drv_log("Failed to get. Invalid handle.\n"); + hidlCb(Error::BAD_BUFFER, encodedMetadata); + return Void(); + } + + android::status_t status = android::NO_ERROR; + if (metadataType == android::gralloc4::MetadataType_BufferId) { + status = android::gralloc4::encodeBufferId(crosHandle->id, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Name) { + const char* name = (const char*)(&crosHandle->base.data[crosHandle->name_offset]); + status = android::gralloc4::encodeName(name, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Width) { + status = android::gralloc4::encodeWidth(crosHandle->width, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Height) { + status = android::gralloc4::encodeHeight(crosHandle->height, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_LayerCount) { + status = android::gralloc4::encodeLayerCount(1, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_PixelFormatRequested) { + PixelFormat pixelFormat = static_cast(crosHandle->droid_format); + status = android::gralloc4::encodePixelFormatRequested(pixelFormat, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_PixelFormatFourCC) { + status = android::gralloc4::encodePixelFormatFourCC(crosHandle->format, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_PixelFormatModifier) { + status = android::gralloc4::encodePixelFormatModifier(crosHandle->format_modifier, + &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Usage) { + uint64_t usage = static_cast(crosHandle->usage); + status = android::gralloc4::encodeUsage(usage, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_AllocationSize) { + status = android::gralloc4::encodeAllocationSize(crosHandle->total_size, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_ProtectedContent) { + uint64_t hasProtectedContent = crosHandle->usage & BufferUsage::PROTECTED ? 1 : 0; + status = android::gralloc4::encodeProtectedContent(hasProtectedContent, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Compression) { + status = android::gralloc4::encodeCompression(android::gralloc4::Compression_None, + &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Interlaced) { + status = android::gralloc4::encodeInterlaced(android::gralloc4::Interlaced_None, + &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_ChromaSiting) { + status = android::gralloc4::encodeChromaSiting(android::gralloc4::ChromaSiting_None, + &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_PlaneLayouts) { + std::vector planeLayouts; + getPlaneLayouts(crosHandle->format, &planeLayouts); + + for (size_t plane = 0; plane < planeLayouts.size(); plane++) { + PlaneLayout& planeLayout = planeLayouts[plane]; + planeLayout.offsetInBytes = crosHandle->offsets[plane]; + planeLayout.strideInBytes = crosHandle->strides[plane]; + planeLayout.totalSizeInBytes = crosHandle->sizes[plane]; + planeLayout.widthInSamples = crosHandle->width; + planeLayout.heightInSamples = crosHandle->height; + } + + status = android::gralloc4::encodePlaneLayouts(planeLayouts, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Crop) { + std::vector crops; + for (size_t plane = 0; plane < crosHandle->num_planes; plane++) { + aidl::android::hardware::graphics::common::Rect crop; + crop.left = 0; + crop.top = 0; + crop.right = crosHandle->width; + crop.bottom = crosHandle->height; + crops.push_back(crop); + } + + status = android::gralloc4::encodeCrop(crops, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Dataspace) { + status = android::gralloc4::encodeDataspace(Dataspace::UNKNOWN, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_BlendMode) { + status = android::gralloc4::encodeBlendMode(BlendMode::INVALID, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Smpte2086) { + status = android::gralloc4::encodeSmpte2086(std::nullopt, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Cta861_3) { + status = android::gralloc4::encodeCta861_3(std::nullopt, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Smpte2094_40) { + status = android::gralloc4::encodeSmpte2094_40(std::nullopt, &encodedMetadata); + } else { + hidlCb(Error::UNSUPPORTED, encodedMetadata); + return Void(); + } + + if (status != android::NO_ERROR) { + hidlCb(Error::NO_RESOURCES, encodedMetadata); + drv_log("Failed to get. Failed to encode metadata.\n"); + return Void(); + } + + hidlCb(Error::NONE, encodedMetadata); + return Void(); +} + +Return CrosGralloc4Mapper::set(void* rawHandle, const MetadataType& metadataType, + const hidl_vec& /*metadata*/) { + if (!mDriver) { + drv_log("Failed to set. Driver is uninitialized.\n"); + return Error::NO_RESOURCES; + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to set. Empty handle.\n"); + return Error::BAD_BUFFER; + } + + cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); + if (!crosHandle) { + drv_log("Failed to set. Invalid handle.\n"); + return Error::BAD_BUFFER; + } + + if (metadataType == android::gralloc4::MetadataType_BufferId) { + return Error::BAD_VALUE; + } else if (metadataType == android::gralloc4::MetadataType_Name) { + return Error::BAD_VALUE; + } else if (metadataType == android::gralloc4::MetadataType_Width) { + return Error::BAD_VALUE; + } else if (metadataType == android::gralloc4::MetadataType_Height) { + return Error::BAD_VALUE; + } else if (metadataType == android::gralloc4::MetadataType_LayerCount) { + return Error::BAD_VALUE; + } else if (metadataType == android::gralloc4::MetadataType_PixelFormatRequested) { + return Error::BAD_VALUE; + } else if (metadataType == android::gralloc4::MetadataType_Usage) { + return Error::BAD_VALUE; + } + + return Error::UNSUPPORTED; +} + +int CrosGralloc4Mapper::getResolvedDrmFormat(PixelFormat pixelFormat, uint64_t bufferUsage, + uint32_t* outDrmFormat) { + uint32_t drmFormat; + if (convertToDrmFormat(pixelFormat, &drmFormat)) { + std::string pixelFormatString = getPixelFormatString(pixelFormat); + drv_log("Failed to getResolvedDrmFormat. Failed to convert format %s\n", + pixelFormatString.c_str()); + return -1; + } + + uint64_t usage; + if (convertToBufferUsage(bufferUsage, &usage)) { + std::string usageString = getUsageString(bufferUsage); + drv_log("Failed to getResolvedDrmFormat. Failed to convert usage %s\n", + usageString.c_str()); + return -1; + } + + uint32_t resolvedDrmFormat = mDriver->get_resolved_drm_format(drmFormat, usage); + if (resolvedDrmFormat == DRM_FORMAT_INVALID) { + std::string drmFormatString = getDrmFormatString(drmFormat); + drv_log("Failed to getResolvedDrmFormat. Failed to resolve drm format %s\n", + drmFormatString.c_str()); + return -1; + } + + *outDrmFormat = resolvedDrmFormat; + + return 0; +} + +Return CrosGralloc4Mapper::getFromBufferDescriptorInfo( + const BufferDescriptorInfo& descriptor, const MetadataType& metadataType, + getFromBufferDescriptorInfo_cb hidlCb) { + hidl_vec encodedMetadata; + + if (!mDriver) { + drv_log("Failed to getFromBufferDescriptorInfo. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, encodedMetadata); + return Void(); + } + + android::status_t status = android::NO_ERROR; + if (metadataType == android::gralloc4::MetadataType_Name) { + status = android::gralloc4::encodeName(descriptor.name, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Width) { + status = android::gralloc4::encodeWidth(descriptor.width, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Height) { + status = android::gralloc4::encodeHeight(descriptor.height, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_LayerCount) { + status = android::gralloc4::encodeLayerCount(1, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_PixelFormatRequested) { + status = android::gralloc4::encodePixelFormatRequested(descriptor.format, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_PixelFormatFourCC) { + uint32_t drmFormat; + if (getResolvedDrmFormat(descriptor.format, descriptor.usage, &drmFormat)) { + hidlCb(Error::BAD_VALUE, encodedMetadata); + return Void(); + } + status = android::gralloc4::encodePixelFormatFourCC(drmFormat, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Usage) { + status = android::gralloc4::encodeUsage(descriptor.usage, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_ProtectedContent) { + uint64_t hasProtectedContent = descriptor.usage & BufferUsage::PROTECTED ? 1 : 0; + status = android::gralloc4::encodeProtectedContent(hasProtectedContent, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Compression) { + status = android::gralloc4::encodeCompression(android::gralloc4::Compression_None, + &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Interlaced) { + status = android::gralloc4::encodeInterlaced(android::gralloc4::Interlaced_None, + &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_ChromaSiting) { + status = android::gralloc4::encodeChromaSiting(android::gralloc4::ChromaSiting_None, + &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Crop) { + uint32_t drmFormat; + if (getResolvedDrmFormat(descriptor.format, descriptor.usage, &drmFormat)) { + hidlCb(Error::BAD_VALUE, encodedMetadata); + return Void(); + } + + size_t numPlanes = drv_num_planes_from_format(drmFormat); + + std::vector crops; + for (size_t plane = 0; plane < numPlanes; plane++) { + aidl::android::hardware::graphics::common::Rect crop; + crop.left = 0; + crop.top = 0; + crop.right = descriptor.width; + crop.bottom = descriptor.height; + crops.push_back(crop); + } + status = android::gralloc4::encodeCrop(crops, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Dataspace) { + status = android::gralloc4::encodeDataspace(Dataspace::UNKNOWN, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_BlendMode) { + status = android::gralloc4::encodeBlendMode(BlendMode::INVALID, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Smpte2086) { + status = android::gralloc4::encodeSmpte2086(std::nullopt, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Cta861_3) { + status = android::gralloc4::encodeCta861_3(std::nullopt, &encodedMetadata); + } else if (metadataType == android::gralloc4::MetadataType_Smpte2094_40) { + status = android::gralloc4::encodeSmpte2094_40(std::nullopt, &encodedMetadata); + } else { + hidlCb(Error::UNSUPPORTED, encodedMetadata); + return Void(); + } + + if (status != android::NO_ERROR) { + hidlCb(Error::NO_RESOURCES, encodedMetadata); + return Void(); + } + + hidlCb(Error::NONE, encodedMetadata); + return Void(); +} + +Return CrosGralloc4Mapper::listSupportedMetadataTypes(listSupportedMetadataTypes_cb hidlCb) { + hidl_vec supported; + + if (!mDriver) { + drv_log("Failed to listSupportedMetadataTypes. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, supported); + return Void(); + } + + supported = hidl_vec({ + { + android::gralloc4::MetadataType_BufferId, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Name, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Width, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Height, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_LayerCount, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_PixelFormatRequested, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_PixelFormatFourCC, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_PixelFormatModifier, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Usage, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_AllocationSize, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_ProtectedContent, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Compression, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Interlaced, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_ChromaSiting, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_PlaneLayouts, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Dataspace, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_BlendMode, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Smpte2086, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Cta861_3, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + { + android::gralloc4::MetadataType_Smpte2094_40, + "", + /*isGettable=*/true, + /*isSettable=*/false, + }, + }); + + hidlCb(Error::NONE, supported); + return Void(); +} + +Return CrosGralloc4Mapper::dumpBuffer(void* rawHandle, dumpBuffer_cb hidlCb) { + BufferDump bufferDump; + + if (!mDriver) { + drv_log("Failed to dumpBuffer. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, bufferDump); + return Void(); + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to dumpBuffer. Empty handle.\n"); + hidlCb(Error::BAD_BUFFER, bufferDump); + return Void(); + } + + cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); + if (!crosHandle) { + drv_log("Failed to dumpBuffer. Invalid handle.\n"); + hidlCb(Error::BAD_BUFFER, bufferDump); + return Void(); + } + + return dumpBuffer(crosHandle, hidlCb); +} + +Return CrosGralloc4Mapper::dumpBuffer(cros_gralloc_handle_t crosHandle, + dumpBuffer_cb hidlCb) { + BufferDump bufferDump; + + if (!mDriver) { + drv_log("Failed to dumpBuffer. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, bufferDump); + return Void(); + } + + if (!crosHandle) { + drv_log("Failed to dumpBuffer. Invalid handle.\n"); + hidlCb(Error::BAD_BUFFER, bufferDump); + return Void(); + } + + std::vector metadataDumps; + + MetadataType metadataType = android::gralloc4::MetadataType_BufferId; + auto metadata_get_callback = [&](Error, hidl_vec metadata) { + MetadataDump metadataDump; + metadataDump.metadataType = metadataType; + metadataDump.metadata = metadata; + metadataDumps.push_back(metadataDump); + }; + + metadataType = android::gralloc4::MetadataType_BufferId; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_Name; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_Width; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_Height; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_LayerCount; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_PixelFormatRequested; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_PixelFormatFourCC; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_PixelFormatModifier; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_Usage; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_AllocationSize; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_ProtectedContent; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_Compression; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_Interlaced; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_ChromaSiting; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_PlaneLayouts; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_Dataspace; + get(crosHandle, metadataType, metadata_get_callback); + + metadataType = android::gralloc4::MetadataType_BlendMode; + get(crosHandle, metadataType, metadata_get_callback); + + bufferDump.metadataDump = metadataDumps; + hidlCb(Error::NONE, bufferDump); + return Void(); +} + +Return CrosGralloc4Mapper::dumpBuffers(dumpBuffers_cb hidlCb) { + std::vector bufferDumps; + + if (!mDriver) { + drv_log("Failed to dumpBuffers. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, bufferDumps); + return Void(); + } + + Error error = Error::NONE; + + auto handleCallback = [&](cros_gralloc_handle_t crosHandle) { + auto dumpBufferCallback = [&](Error err, BufferDump bufferDump) { + error = err; + if (error == Error::NONE) { + bufferDumps.push_back(bufferDump); + } + }; + + dumpBuffer(crosHandle, dumpBufferCallback); + }; + mDriver->for_each_handle(handleCallback); + + hidlCb(error, bufferDumps); + return Void(); +} + +Return CrosGralloc4Mapper::getReservedRegion(void* rawHandle, getReservedRegion_cb hidlCb) { + if (!mDriver) { + drv_log("Failed to getReservedRegion. Driver is uninitialized.\n"); + hidlCb(Error::NO_RESOURCES, nullptr, 0); + return Void(); + } + + buffer_handle_t bufferHandle = reinterpret_cast(rawHandle); + if (!bufferHandle) { + drv_log("Failed to getReservedRegion. Empty handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr, 0); + return Void(); + } + + cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle); + if (!crosHandle) { + drv_log("Failed to getReservedRegion. Invalid handle.\n"); + hidlCb(Error::BAD_BUFFER, nullptr, 0); + return Void(); + } + + void* reservedRegionAddr = nullptr; + uint64_t reservedRegionSize = 0; + int ret = mDriver->get_reserved_region(bufferHandle, &reservedRegionAddr, &reservedRegionSize); + if (ret) { + drv_log("Failed to getReservedRegion.\n"); + hidlCb(Error::BAD_BUFFER, nullptr, 0); + return Void(); + } + + hidlCb(Error::NONE, reservedRegionAddr, reservedRegionSize); + return Void(); +} + +android::hardware::graphics::mapper::V4_0::IMapper* HIDL_FETCH_IMapper(const char* /*name*/) { + return static_cast(new CrosGralloc4Mapper); +} diff --git a/cros_gralloc/gralloc4/CrosGralloc4Mapper.h b/cros_gralloc/gralloc4/CrosGralloc4Mapper.h new file mode 100644 index 0000000..b318930 --- /dev/null +++ b/cros_gralloc/gralloc4/CrosGralloc4Mapper.h @@ -0,0 +1,80 @@ +/* + * Copyright 2020 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 + +#include "cros_gralloc/cros_gralloc_driver.h" +#include "cros_gralloc/cros_gralloc_handle.h" + +class CrosGralloc4Mapper : public android::hardware::graphics::mapper::V4_0::IMapper { + public: + CrosGralloc4Mapper(); + + android::hardware::Return createDescriptor(const BufferDescriptorInfo& description, + createDescriptor_cb hidlCb) override; + + android::hardware::Return importBuffer(const android::hardware::hidl_handle& rawHandle, + importBuffer_cb hidlCb) override; + + android::hardware::Return freeBuffer( + void* rawHandle) override; + + android::hardware::Return validateBufferSize( + void* rawHandle, const BufferDescriptorInfo& descriptor, uint32_t stride) override; + + android::hardware::Return getTransportSize(void* rawHandle, + getTransportSize_cb hidlCb) override; + + android::hardware::Return lock(void* rawHandle, uint64_t cpuUsage, + const Rect& accessRegion, + const android::hardware::hidl_handle& acquireFence, + lock_cb hidlCb) override; + + android::hardware::Return unlock(void* rawHandle, unlock_cb hidlCb) override; + + android::hardware::Return flushLockedBuffer(void* rawHandle, + flushLockedBuffer_cb hidlCb) override; + + android::hardware::Return rereadLockedBuffer( + void* rawHandle) override; + + android::hardware::Return isSupported(const BufferDescriptorInfo& descriptor, + isSupported_cb hidlCb) override; + + android::hardware::Return get(void* rawHandle, const MetadataType& metadataType, + get_cb hidlCb) override; + + android::hardware::Return set( + void* rawHandle, const MetadataType& metadataType, + const android::hardware::hidl_vec& metadata) override; + + android::hardware::Return getFromBufferDescriptorInfo( + const BufferDescriptorInfo& descriptor, const MetadataType& metadataType, + getFromBufferDescriptorInfo_cb hidlCb) override; + + android::hardware::Return listSupportedMetadataTypes( + listSupportedMetadataTypes_cb hidlCb) override; + + android::hardware::Return dumpBuffer(void* rawHandle, dumpBuffer_cb hidlCb) override; + android::hardware::Return dumpBuffers(dumpBuffers_cb hidlCb) override; + + android::hardware::Return getReservedRegion(void* rawHandle, + getReservedRegion_cb hidlCb) override; + + private: + android::hardware::Return get(cros_gralloc_handle_t crosHandle, + const MetadataType& metadataType, get_cb hidlCb); + + android::hardware::Return dumpBuffer(cros_gralloc_handle_t crosHandle, + dumpBuffer_cb hidlCb); + + int getResolvedDrmFormat(android::hardware::graphics::common::V1_2::PixelFormat pixelFormat, + uint64_t bufferUsage, uint32_t* outDrmFormat); + + std::unique_ptr mDriver; +}; + +extern "C" android::hardware::graphics::mapper::V4_0::IMapper* HIDL_FETCH_IMapper(const char* name); diff --git a/cros_gralloc/gralloc4/CrosGralloc4Utils.cc b/cros_gralloc/gralloc4/CrosGralloc4Utils.cc new file mode 100644 index 0000000..8931164 --- /dev/null +++ b/cros_gralloc/gralloc4/CrosGralloc4Utils.cc @@ -0,0 +1,772 @@ +/* + * Copyright 2020 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/gralloc4/CrosGralloc4Utils.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "cros_gralloc/cros_gralloc_helpers.h" + +using aidl::android::hardware::graphics::common::PlaneLayout; +using aidl::android::hardware::graphics::common::PlaneLayoutComponent; +using aidl::android::hardware::graphics::common::PlaneLayoutComponentType; +using android::hardware::hidl_bitfield; +using android::hardware::hidl_handle; +using android::hardware::graphics::common::V1_2::BufferUsage; +using android::hardware::graphics::common::V1_2::PixelFormat; + +using BufferDescriptorInfo = + android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo; + +std::string getDrmFormatString(uint32_t drmFormat) { + switch (drmFormat) { + case DRM_FORMAT_ABGR1555: + return "DRM_FORMAT_ABGR1555"; + case DRM_FORMAT_ABGR2101010: + return "DRM_FORMAT_ABGR2101010"; + case DRM_FORMAT_ABGR4444: + return "DRM_FORMAT_ABGR4444"; + case DRM_FORMAT_ABGR8888: + return "DRM_FORMAT_ABGR8888"; + case DRM_FORMAT_ARGB1555: + return "DRM_FORMAT_ARGB1555"; + case DRM_FORMAT_ARGB2101010: + return "DRM_FORMAT_ARGB2101010"; + case DRM_FORMAT_ARGB4444: + return "DRM_FORMAT_ARGB4444"; + case DRM_FORMAT_ARGB8888: + return "DRM_FORMAT_ARGB8888"; + case DRM_FORMAT_AYUV: + return "DRM_FORMAT_AYUV"; + case DRM_FORMAT_BGR233: + return "DRM_FORMAT_BGR233"; + case DRM_FORMAT_BGR565: + return "DRM_FORMAT_BGR565"; + case DRM_FORMAT_BGR888: + return "DRM_FORMAT_BGR888"; + case DRM_FORMAT_BGRA1010102: + return "DRM_FORMAT_BGRA1010102"; + case DRM_FORMAT_BGRA4444: + return "DRM_FORMAT_BGRA4444"; + case DRM_FORMAT_BGRA5551: + return "DRM_FORMAT_BGRA5551"; + case DRM_FORMAT_BGRA8888: + return "DRM_FORMAT_BGRA8888"; + case DRM_FORMAT_BGRX1010102: + return "DRM_FORMAT_BGRX1010102"; + case DRM_FORMAT_BGRX4444: + return "DRM_FORMAT_BGRX4444"; + case DRM_FORMAT_BGRX5551: + return "DRM_FORMAT_BGRX5551"; + case DRM_FORMAT_BGRX8888: + return "DRM_FORMAT_BGRX8888"; + case DRM_FORMAT_C8: + return "DRM_FORMAT_C8"; + case DRM_FORMAT_GR88: + return "DRM_FORMAT_GR88"; + case DRM_FORMAT_NV12: + return "DRM_FORMAT_NV12"; + case DRM_FORMAT_NV21: + return "DRM_FORMAT_NV21"; + case DRM_FORMAT_R8: + return "DRM_FORMAT_R8"; + case DRM_FORMAT_RG88: + return "DRM_FORMAT_RG88"; + case DRM_FORMAT_RGB332: + return "DRM_FORMAT_RGB332"; + case DRM_FORMAT_RGB565: + return "DRM_FORMAT_RGB565"; + case DRM_FORMAT_RGB888: + return "DRM_FORMAT_RGB888"; + case DRM_FORMAT_RGBA1010102: + return "DRM_FORMAT_RGBA1010102"; + case DRM_FORMAT_RGBA4444: + return "DRM_FORMAT_RGBA4444"; + case DRM_FORMAT_RGBA5551: + return "DRM_FORMAT_RGBA5551"; + case DRM_FORMAT_RGBA8888: + return "DRM_FORMAT_RGBA8888"; + case DRM_FORMAT_RGBX1010102: + return "DRM_FORMAT_RGBX1010102"; + case DRM_FORMAT_RGBX4444: + return "DRM_FORMAT_RGBX4444"; + case DRM_FORMAT_RGBX5551: + return "DRM_FORMAT_RGBX5551"; + case DRM_FORMAT_RGBX8888: + return "DRM_FORMAT_RGBX8888"; + case DRM_FORMAT_UYVY: + return "DRM_FORMAT_UYVY"; + case DRM_FORMAT_VYUY: + return "DRM_FORMAT_VYUY"; + case DRM_FORMAT_XBGR1555: + return "DRM_FORMAT_XBGR1555"; + case DRM_FORMAT_XBGR2101010: + return "DRM_FORMAT_XBGR2101010"; + case DRM_FORMAT_XBGR4444: + return "DRM_FORMAT_XBGR4444"; + case DRM_FORMAT_XBGR8888: + return "DRM_FORMAT_XBGR8888"; + case DRM_FORMAT_XRGB1555: + return "DRM_FORMAT_XRGB1555"; + case DRM_FORMAT_XRGB2101010: + return "DRM_FORMAT_XRGB2101010"; + case DRM_FORMAT_XRGB4444: + return "DRM_FORMAT_XRGB4444"; + case DRM_FORMAT_XRGB8888: + return "DRM_FORMAT_XRGB8888"; + case DRM_FORMAT_YUYV: + return "DRM_FORMAT_YUYV"; + case DRM_FORMAT_YVU420: + return "DRM_FORMAT_YVU420"; + case DRM_FORMAT_YVYU: + return "DRM_FORMAT_YVYU"; + } + return android::base::StringPrintf("Unknown(%d)", drmFormat); +} + +std::string getPixelFormatString(PixelFormat format) { + switch (format) { + case PixelFormat::BGRA_8888: + return "PixelFormat::BGRA_8888"; + case PixelFormat::BLOB: + return "PixelFormat::BLOB"; + case PixelFormat::DEPTH_16: + return "PixelFormat::DEPTH_16"; + case PixelFormat::DEPTH_24: + return "PixelFormat::DEPTH_24"; + case PixelFormat::DEPTH_24_STENCIL_8: + return "PixelFormat::DEPTH_24_STENCIL_8"; + case PixelFormat::DEPTH_32F: + return "PixelFormat::DEPTH_24"; + case PixelFormat::DEPTH_32F_STENCIL_8: + return "PixelFormat::DEPTH_24_STENCIL_8"; + case PixelFormat::HSV_888: + return "PixelFormat::HSV_888"; + case PixelFormat::IMPLEMENTATION_DEFINED: + return "PixelFormat::IMPLEMENTATION_DEFINED"; + case PixelFormat::RAW10: + return "PixelFormat::RAW10"; + case PixelFormat::RAW12: + return "PixelFormat::RAW12"; + case PixelFormat::RAW16: + return "PixelFormat::RAW16"; + case PixelFormat::RAW_OPAQUE: + return "PixelFormat::RAW_OPAQUE"; + case PixelFormat::RGBA_1010102: + return "PixelFormat::RGBA_1010102"; + case PixelFormat::RGBA_8888: + return "PixelFormat::RGBA_8888"; + case PixelFormat::RGBA_FP16: + return "PixelFormat::RGBA_FP16"; + case PixelFormat::RGBX_8888: + return "PixelFormat::RGBX_8888"; + case PixelFormat::RGB_565: + return "PixelFormat::RGB_565"; + case PixelFormat::RGB_888: + return "PixelFormat::RGB_888"; + case PixelFormat::STENCIL_8: + return "PixelFormat::STENCIL_8"; + case PixelFormat::Y16: + return "PixelFormat::Y16"; + case PixelFormat::Y8: + return "PixelFormat::Y8"; + case PixelFormat::YCBCR_420_888: + return "PixelFormat::YCBCR_420_888"; + case PixelFormat::YCBCR_422_I: + return "PixelFormat::YCBCR_422_I"; + case PixelFormat::YCBCR_422_SP: + return "PixelFormat::YCBCR_422_SP"; + case PixelFormat::YCBCR_P010: + return "PixelFormat::YCBCR_P010"; + case PixelFormat::YCRCB_420_SP: + return "PixelFormat::YCRCB_420_SP"; + case PixelFormat::YV12: + return "PixelFormat::YV12"; + } + return android::base::StringPrintf("PixelFormat::Unknown(%d)", static_cast(format)); +} + +std::string getUsageString(hidl_bitfield bufferUsage) { + using Underlying = typename std::underlying_type::type; + + Underlying usage = static_cast(bufferUsage); + + std::vector usages; + if (usage & BufferUsage::CAMERA_INPUT) { + usage &= ~static_cast(BufferUsage::CAMERA_INPUT); + usages.push_back("BufferUsage::CAMERA_INPUT"); + } + if (usage & BufferUsage::CAMERA_OUTPUT) { + usage &= ~static_cast(BufferUsage::CAMERA_OUTPUT); + usages.push_back("BufferUsage::CAMERA_OUTPUT"); + } + if (usage & BufferUsage::COMPOSER_CURSOR) { + usage &= ~static_cast(BufferUsage::COMPOSER_CURSOR); + usages.push_back("BufferUsage::COMPOSER_CURSOR"); + } + if (usage & BufferUsage::COMPOSER_OVERLAY) { + usage &= ~static_cast(BufferUsage::COMPOSER_OVERLAY); + usages.push_back("BufferUsage::COMPOSER_OVERLAY"); + } + if (usage & BufferUsage::CPU_READ_OFTEN) { + usage &= ~static_cast(BufferUsage::CPU_READ_OFTEN); + usages.push_back("BufferUsage::CPU_READ_OFTEN"); + } + if (usage & BufferUsage::CPU_READ_NEVER) { + usage &= ~static_cast(BufferUsage::CPU_READ_NEVER); + usages.push_back("BufferUsage::CPU_READ_NEVER"); + } + if (usage & BufferUsage::CPU_READ_RARELY) { + usage &= ~static_cast(BufferUsage::CPU_READ_RARELY); + usages.push_back("BufferUsage::CPU_READ_RARELY"); + } + if (usage & BufferUsage::CPU_WRITE_NEVER) { + usage &= ~static_cast(BufferUsage::CPU_WRITE_NEVER); + usages.push_back("BufferUsage::CPU_WRITE_NEVER"); + } + if (usage & BufferUsage::CPU_WRITE_OFTEN) { + usage &= ~static_cast(BufferUsage::CPU_WRITE_OFTEN); + usages.push_back("BufferUsage::CPU_WRITE_OFTEN"); + } + if (usage & BufferUsage::CPU_WRITE_RARELY) { + usage &= ~static_cast(BufferUsage::CPU_WRITE_RARELY); + usages.push_back("BufferUsage::CPU_WRITE_RARELY"); + } + if (usage & BufferUsage::GPU_RENDER_TARGET) { + usage &= ~static_cast(BufferUsage::GPU_RENDER_TARGET); + usages.push_back("BufferUsage::GPU_RENDER_TARGET"); + } + if (usage & BufferUsage::GPU_TEXTURE) { + usage &= ~static_cast(BufferUsage::GPU_TEXTURE); + usages.push_back("BufferUsage::GPU_TEXTURE"); + } + if (usage & BufferUsage::PROTECTED) { + usage &= ~static_cast(BufferUsage::PROTECTED); + usages.push_back("BufferUsage::PROTECTED"); + } + if (usage & BufferUsage::RENDERSCRIPT) { + usage &= ~static_cast(BufferUsage::RENDERSCRIPT); + usages.push_back("BufferUsage::RENDERSCRIPT"); + } + if (usage & BufferUsage::VIDEO_DECODER) { + usage &= ~static_cast(BufferUsage::VIDEO_DECODER); + usages.push_back("BufferUsage::VIDEO_DECODER"); + } + if (usage & BufferUsage::VIDEO_ENCODER) { + usage &= ~static_cast(BufferUsage::VIDEO_ENCODER); + usages.push_back("BufferUsage::VIDEO_ENCODER"); + } + + if (usage) { + usages.push_back(android::base::StringPrintf("UnknownUsageBits-%" PRIu64, usage)); + } + + return android::base::Join(usages, '|'); +} + +int convertToDrmFormat(PixelFormat format, uint32_t* outDrmFormat) { + switch (format) { + case PixelFormat::BGRA_8888: + *outDrmFormat = DRM_FORMAT_ARGB8888; + return 0; + /** + * Choose DRM_FORMAT_R8 because requires the buffers + * with a format HAL_PIXEL_FORMAT_BLOB have a height of 1, and width + * equal to their size in bytes. + */ + case PixelFormat::BLOB: + *outDrmFormat = DRM_FORMAT_R8; + return 0; + case PixelFormat::DEPTH_16: + return -EINVAL; + case PixelFormat::DEPTH_24: + return -EINVAL; + case PixelFormat::DEPTH_24_STENCIL_8: + return -EINVAL; + case PixelFormat::DEPTH_32F: + return -EINVAL; + case PixelFormat::DEPTH_32F_STENCIL_8: + return -EINVAL; + case PixelFormat::HSV_888: + return -EINVAL; + case PixelFormat::IMPLEMENTATION_DEFINED: + *outDrmFormat = DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED; + return 0; + case PixelFormat::RAW10: + return -EINVAL; + case PixelFormat::RAW12: + return -EINVAL; + case PixelFormat::RAW16: + *outDrmFormat = DRM_FORMAT_R16; + return 0; + /* TODO use blob */ + case PixelFormat::RAW_OPAQUE: + return -EINVAL; + case PixelFormat::RGBA_1010102: + *outDrmFormat = DRM_FORMAT_ABGR2101010; + return 0; + case PixelFormat::RGBA_8888: + *outDrmFormat = DRM_FORMAT_ABGR8888; + return 0; + case PixelFormat::RGBA_FP16: + *outDrmFormat = DRM_FORMAT_ABGR16161616F; + return 0; + case PixelFormat::RGBX_8888: + *outDrmFormat = DRM_FORMAT_XBGR8888; + return 0; + case PixelFormat::RGB_565: + *outDrmFormat = DRM_FORMAT_RGB565; + return 0; + case PixelFormat::RGB_888: + *outDrmFormat = DRM_FORMAT_RGB888; + return 0; + case PixelFormat::STENCIL_8: + return -EINVAL; + case PixelFormat::Y16: + *outDrmFormat = DRM_FORMAT_R16; + return 0; + case PixelFormat::Y8: + *outDrmFormat = DRM_FORMAT_R8; + return 0; + case PixelFormat::YCBCR_420_888: + *outDrmFormat = DRM_FORMAT_FLEX_YCbCr_420_888; + return 0; + case PixelFormat::YCBCR_422_SP: + return -EINVAL; + case PixelFormat::YCBCR_422_I: + return -EINVAL; + case PixelFormat::YCBCR_P010: + *outDrmFormat = DRM_FORMAT_P010; + return 0; + case PixelFormat::YCRCB_420_SP: + *outDrmFormat = DRM_FORMAT_NV21; + return 0; + case PixelFormat::YV12: + *outDrmFormat = DRM_FORMAT_YVU420_ANDROID; + return 0; + }; + return -EINVAL; +} + +int convertToBufferUsage(uint64_t grallocUsage, uint64_t* outBufferUsage) { + uint64_t bufferUsage = BO_USE_NONE; + + if ((grallocUsage & BufferUsage::CPU_READ_MASK) == + static_cast(BufferUsage::CPU_READ_RARELY)) { + bufferUsage |= BO_USE_SW_READ_RARELY; + } + if ((grallocUsage & BufferUsage::CPU_READ_MASK) == + static_cast(BufferUsage::CPU_READ_OFTEN)) { + bufferUsage |= BO_USE_SW_READ_OFTEN; + } + if ((grallocUsage & BufferUsage::CPU_WRITE_MASK) == + static_cast(BufferUsage::CPU_WRITE_RARELY)) { + bufferUsage |= BO_USE_SW_WRITE_RARELY; + } + if ((grallocUsage & BufferUsage::CPU_WRITE_MASK) == + static_cast(BufferUsage::CPU_WRITE_OFTEN)) { + bufferUsage |= BO_USE_SW_WRITE_OFTEN; + } + if (grallocUsage & BufferUsage::GPU_TEXTURE) { + bufferUsage |= BO_USE_TEXTURE; + } + if (grallocUsage & BufferUsage::GPU_RENDER_TARGET) { + bufferUsage |= BO_USE_RENDERING; + } + if (grallocUsage & BufferUsage::COMPOSER_OVERLAY) { + /* HWC wants to use display hardware, but can defer to OpenGL. */ + bufferUsage |= BO_USE_SCANOUT | BO_USE_TEXTURE; + } + if (grallocUsage & BufferUsage::PROTECTED) { + bufferUsage |= BO_USE_PROTECTED; + } + if (grallocUsage & BufferUsage::COMPOSER_CURSOR) { + bufferUsage |= BO_USE_NONE; + } + if (grallocUsage & BufferUsage::VIDEO_ENCODER) { + /*HACK: See b/30054495 */ + bufferUsage |= BO_USE_SW_READ_OFTEN; + } + if (grallocUsage & BufferUsage::CAMERA_OUTPUT) { + bufferUsage |= BO_USE_CAMERA_WRITE; + } + if (grallocUsage & BufferUsage::CAMERA_INPUT) { + bufferUsage |= BO_USE_CAMERA_READ; + } + if (grallocUsage & BufferUsage::RENDERSCRIPT) { + bufferUsage |= BO_USE_RENDERSCRIPT; + } + if (grallocUsage & BufferUsage::VIDEO_DECODER) { + bufferUsage |= BO_USE_HW_VIDEO_DECODER; + } + + *outBufferUsage = bufferUsage; + return 0; +} + +int convertToCrosDescriptor(const BufferDescriptorInfo& descriptor, + struct cros_gralloc_buffer_descriptor* outCrosDescriptor) { + outCrosDescriptor->name = descriptor.name; + outCrosDescriptor->width = descriptor.width; + outCrosDescriptor->height = descriptor.height; + outCrosDescriptor->droid_format = static_cast(descriptor.format); + outCrosDescriptor->droid_usage = descriptor.usage; + outCrosDescriptor->reserved_region_size = descriptor.reservedSize; + + if (convertToDrmFormat(descriptor.format, &outCrosDescriptor->drm_format)) { + std::string pixelFormatString = getPixelFormatString(descriptor.format); + drv_log("Failed to convert descriptor. Unsupported fomat %s\n", pixelFormatString.c_str()); + return -1; + } + if (convertToBufferUsage(descriptor.usage, &outCrosDescriptor->use_flags)) { + std::string usageString = getUsageString(descriptor.usage); + drv_log("Failed to convert descriptor. Unsupported usage flags %s\n", usageString.c_str()); + return -1; + } + return 0; +} + +int convertToMapUsage(uint64_t grallocUsage, uint32_t* outMapUsage) { + uint32_t mapUsage = BO_MAP_NONE; + + if (grallocUsage & BufferUsage::CPU_READ_MASK) { + mapUsage |= BO_MAP_READ; + } + if (grallocUsage & BufferUsage::CPU_WRITE_MASK) { + mapUsage |= BO_MAP_WRITE; + } + + *outMapUsage = mapUsage; + return 0; +} + +int convertToFenceFd(const hidl_handle& fenceHandle, int* outFenceFd) { + if (!outFenceFd) { + return -EINVAL; + } + + const native_handle_t* nativeHandle = fenceHandle.getNativeHandle(); + if (nativeHandle && nativeHandle->numFds > 1) { + return -EINVAL; + } + + *outFenceFd = (nativeHandle && nativeHandle->numFds == 1) ? nativeHandle->data[0] : -1; + return 0; +} + +int convertToFenceHandle(int fenceFd, hidl_handle* outFenceHandle) { + if (!outFenceHandle) { + return -EINVAL; + } + if (fenceFd < 0) { + return 0; + } + + NATIVE_HANDLE_DECLARE_STORAGE(handleStorage, 1, 0); + auto fenceHandle = native_handle_init(handleStorage, 1, 0); + fenceHandle->data[0] = fenceFd; + + *outFenceHandle = fenceHandle; + return 0; +} + +const std::unordered_map>& GetPlaneLayoutsMap() { + static const auto* kPlaneLayoutsMap = + new std::unordered_map>({ + {DRM_FORMAT_ABGR8888, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 0, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_G, + .offsetInBits = 8, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_B, + .offsetInBits = 16, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_A, + .offsetInBits = 24, + .sizeInBits = 8}}, + .sampleIncrementInBits = 32, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_ABGR2101010, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 0, + .sizeInBits = 10}, + {.type = android::gralloc4::PlaneLayoutComponentType_G, + .offsetInBits = 10, + .sizeInBits = 10}, + {.type = android::gralloc4::PlaneLayoutComponentType_B, + .offsetInBits = 20, + .sizeInBits = 10}, + {.type = android::gralloc4::PlaneLayoutComponentType_A, + .offsetInBits = 30, + .sizeInBits = 2}}, + .sampleIncrementInBits = 32, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_ABGR16161616F, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 0, + .sizeInBits = 16}, + {.type = android::gralloc4::PlaneLayoutComponentType_G, + .offsetInBits = 16, + .sizeInBits = 16}, + {.type = android::gralloc4::PlaneLayoutComponentType_B, + .offsetInBits = 32, + .sizeInBits = 16}, + {.type = android::gralloc4::PlaneLayoutComponentType_A, + .offsetInBits = 48, + .sizeInBits = 16}}, + .sampleIncrementInBits = 64, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_ARGB8888, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_B, + .offsetInBits = 0, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_G, + .offsetInBits = 8, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 16, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_A, + .offsetInBits = 24, + .sizeInBits = 8}}, + .sampleIncrementInBits = 32, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_NV12, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_Y, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }, + { + .components = + {{.type = android::gralloc4::PlaneLayoutComponentType_CB, + .offsetInBits = 0, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_CR, + .offsetInBits = 8, + .sizeInBits = 8}}, + .sampleIncrementInBits = 16, + .horizontalSubsampling = 2, + .verticalSubsampling = 2, + }}}, + + {DRM_FORMAT_NV21, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_Y, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }, + { + .components = + {{.type = android::gralloc4::PlaneLayoutComponentType_CR, + .offsetInBits = 0, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_CB, + .offsetInBits = 8, + .sizeInBits = 8}}, + .sampleIncrementInBits = 16, + .horizontalSubsampling = 2, + .verticalSubsampling = 2, + }}}, + + {DRM_FORMAT_P010, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_Y, + .offsetInBits = 6, + .sizeInBits = 10}}, + .sampleIncrementInBits = 16, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }, + { + .components = + {{.type = android::gralloc4::PlaneLayoutComponentType_CB, + .offsetInBits = 6, + .sizeInBits = 10}, + {.type = android::gralloc4::PlaneLayoutComponentType_CR, + .offsetInBits = 22, + .sizeInBits = 10}}, + .sampleIncrementInBits = 32, + .horizontalSubsampling = 2, + .verticalSubsampling = 2, + }}}, + + {DRM_FORMAT_R8, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_R16, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 0, + .sizeInBits = 16}}, + .sampleIncrementInBits = 16, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_RGB565, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 0, + .sizeInBits = 5}, + {.type = android::gralloc4::PlaneLayoutComponentType_G, + .offsetInBits = 5, + .sizeInBits = 6}, + {.type = android::gralloc4::PlaneLayoutComponentType_B, + .offsetInBits = 11, + .sizeInBits = 5}}, + .sampleIncrementInBits = 16, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_RGB888, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 0, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_G, + .offsetInBits = 8, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_B, + .offsetInBits = 16, + .sizeInBits = 8}}, + .sampleIncrementInBits = 24, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_XBGR8888, + {{ + .components = {{.type = android::gralloc4::PlaneLayoutComponentType_B, + .offsetInBits = 0, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_G, + .offsetInBits = 8, + .sizeInBits = 8}, + {.type = android::gralloc4::PlaneLayoutComponentType_R, + .offsetInBits = 16, + .sizeInBits = 8}}, + .sampleIncrementInBits = 32, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }}}, + + {DRM_FORMAT_YVU420, + { + { + .components = {{.type = android::gralloc4:: + PlaneLayoutComponentType_Y, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }, + { + .components = {{.type = android::gralloc4:: + PlaneLayoutComponentType_CB, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 2, + .verticalSubsampling = 2, + }, + { + .components = {{.type = android::gralloc4:: + PlaneLayoutComponentType_CR, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 2, + .verticalSubsampling = 2, + }, + }}, + + {DRM_FORMAT_YVU420_ANDROID, + { + { + .components = {{.type = android::gralloc4:: + PlaneLayoutComponentType_Y, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 1, + .verticalSubsampling = 1, + }, + { + .components = {{.type = android::gralloc4:: + PlaneLayoutComponentType_CR, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 2, + .verticalSubsampling = 2, + }, + { + .components = {{.type = android::gralloc4:: + PlaneLayoutComponentType_CB, + .offsetInBits = 0, + .sizeInBits = 8}}, + .sampleIncrementInBits = 8, + .horizontalSubsampling = 2, + .verticalSubsampling = 2, + }, + }}, + }); + return *kPlaneLayoutsMap; +} + +int getPlaneLayouts(uint32_t drmFormat, std::vector* outPlaneLayouts) { + const auto& planeLayoutsMap = GetPlaneLayoutsMap(); + const auto it = planeLayoutsMap.find(drmFormat); + if (it == planeLayoutsMap.end()) { + drv_log("Unknown plane layout for format %d\n", drmFormat); + return -1; + } + + *outPlaneLayouts = it->second; + return 0; +} \ No newline at end of file diff --git a/cros_gralloc/gralloc4/CrosGralloc4Utils.h b/cros_gralloc/gralloc4/CrosGralloc4Utils.h new file mode 100644 index 0000000..094ef74 --- /dev/null +++ b/cros_gralloc/gralloc4/CrosGralloc4Utils.h @@ -0,0 +1,41 @@ +/* + * Copyright 2020 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 +#include + +#include +#include +#include + +#include "cros_gralloc/cros_gralloc_types.h" + +std::string getDrmFormatString(uint32_t drmFormat); + +std::string getPixelFormatString(android::hardware::graphics::common::V1_2::PixelFormat format); + +std::string getUsageString( + android::hardware::hidl_bitfield + usage); + +int convertToDrmFormat(android::hardware::graphics::common::V1_2::PixelFormat format, + uint32_t* outDrmFormat); + +int convertToBufferUsage(uint64_t grallocUsage, uint64_t* outBufferUsage); + +int convertToCrosDescriptor( + const android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo& descriptor, + struct cros_gralloc_buffer_descriptor* outCrosDescriptor); + +int convertToMapUsage(uint64_t grallocUsage, uint32_t* outMapUsage); + +int convertToFenceFd(const android::hardware::hidl_handle& fence_handle, int* out_fence_fd); + +int convertToFenceHandle(int fence_fd, android::hardware::hidl_handle* out_fence_handle); + +int getPlaneLayouts( + uint32_t drm_format, + std::vector* out_layouts); \ No newline at end of file diff --git a/cros_gralloc/gralloc4/android.hardware.graphics.allocator@4.0-service.minigbm.rc b/cros_gralloc/gralloc4/android.hardware.graphics.allocator@4.0-service.minigbm.rc new file mode 100644 index 0000000..a96a6e1 --- /dev/null +++ b/cros_gralloc/gralloc4/android.hardware.graphics.allocator@4.0-service.minigbm.rc @@ -0,0 +1,24 @@ +# +# Copyright 2020 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. +# + +service vendor.graphics.allocator-4-0 /vendor/bin/hw/android.hardware.graphics.allocator@4.0-service.minigbm + interface android.hardware.graphics.allocator@4.0::IAllocator default + class hal animation + user system + group graphics drmrpc + capabilities SYS_NICE + onrestart restart surfaceflinger + writepid /dev/cpuset/system-background/tasks diff --git a/drv.c b/drv.c index 920cf4d..636cd07 100644 --- a/drv.c +++ b/drv.c @@ -117,7 +117,7 @@ static const struct backend *drv_get_backend(int fd) #ifdef DRV_VC4 &backend_vc4, #endif - &backend_vgem, &backend_virtio_gpu, + &backend_vgem, &backend_virtio_gpu, }; for (i = 0; i < ARRAY_SIZE(backend_list); i++) { @@ -558,6 +558,21 @@ int drv_bo_invalidate(struct bo *bo, struct mapping *mapping) return ret; } +int drv_bo_flush(struct bo *bo, struct mapping *mapping) +{ + int ret = 0; + + assert(mapping); + assert(mapping->vma); + assert(mapping->refcount > 0); + assert(mapping->vma->refcount > 0); + + if (bo->drv->backend->bo_flush) + ret = bo->drv->backend->bo_flush(bo, mapping); + + return ret; +} + int drv_bo_flush_or_unmap(struct bo *bo, struct mapping *mapping) { int ret = 0; @@ -648,6 +663,11 @@ uint32_t drv_bo_get_format(struct bo *bo) return bo->meta.format; } +size_t drv_bo_get_total_size(struct bo *bo) +{ + return bo->meta.total_size; +} + uint32_t drv_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags) { if (drv->backend->resolve_format) diff --git a/drv.h b/drv.h index 2b86aad..f19f9de 100644 --- a/drv.h +++ b/drv.h @@ -145,6 +145,8 @@ int drv_bo_unmap(struct bo *bo, struct mapping *mapping); int drv_bo_invalidate(struct bo *bo, struct mapping *mapping); +int drv_bo_flush(struct bo *bo, struct mapping *mapping); + int drv_bo_flush_or_unmap(struct bo *bo, struct mapping *mapping); uint32_t drv_bo_get_width(struct bo *bo); diff --git a/helpers.c b/helpers.c index fed4af9..17b1765 100644 --- a/helpers.c +++ b/helpers.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include "drv_priv.h" @@ -92,6 +94,9 @@ static const struct planar_layout *layout_from_format(uint32_t format) case DRM_FORMAT_RGB332: return &packed_1bpp_layout; + case DRM_FORMAT_R16: + return &packed_2bpp_layout; + case DRM_FORMAT_YVU420: case DRM_FORMAT_YVU420_ANDROID: return &triplanar_yuv_420_layout; @@ -312,6 +317,11 @@ int drv_dumb_bo_create_ex(struct bo *bo, uint32_t width, uint32_t height, uint32 aligned_width = width; aligned_height = height; switch (format) { + case DRM_FORMAT_R16: + /* HAL_PIXEL_FORMAT_Y16 requires that the buffer's width be 16 pixel + * aligned. See hardware/interfaces/graphics/common/1.0/types.hal. */ + aligned_width = ALIGN(width, 16); + break; case DRM_FORMAT_YVU420_ANDROID: /* HAL_PIXEL_FORMAT_YV12 requires that the buffer's height not * be aligned. Update 'height' so that drv_bo_from_format below @@ -327,6 +337,7 @@ int drv_dumb_bo_create_ex(struct bo *bo, uint32_t width, uint32_t height, uint32 break; case DRM_FORMAT_YVU420: case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: /* Adjust the height to include room for chroma planes */ aligned_height = 3 * DIV_ROUND_UP(height, 2); break; diff --git a/virgl_hw.h b/virgl_hw.h index 145780b..1c493d1 100644 --- a/virgl_hw.h +++ b/virgl_hw.h @@ -69,7 +69,7 @@ enum virgl_formats { VIRGL_FORMAT_R8_UNORM = 64, VIRGL_FORMAT_R8G8_UNORM = 65, - + VIRGL_FORMAT_R8G8B8_UNORM = 66, VIRGL_FORMAT_R8G8B8A8_UNORM = 67, VIRGL_FORMAT_R8_SNORM = 74, diff --git a/virtio_gpu.c b/virtio_gpu.c index 4dbcc4f..83d46d3 100644 --- a/virtio_gpu.c +++ b/virtio_gpu.c @@ -4,6 +4,7 @@ * found in the LICENSE file. */ +#include #include #include #include @@ -50,21 +51,27 @@ static const uint32_t render_target_formats[] = { DRM_FORMAT_ABGR8888, DRM_FORMA DRM_FORMAT_RGB565, DRM_FORMAT_XBGR8888, DRM_FORMAT_XRGB8888 }; -static const uint32_t dumb_texture_source_formats[] = { DRM_FORMAT_R8, DRM_FORMAT_YVU420, - DRM_FORMAT_NV12, - DRM_FORMAT_YVU420_ANDROID }; +static const uint32_t dumb_texture_source_formats[] = { + DRM_FORMAT_R8, DRM_FORMAT_R16, DRM_FORMAT_YVU420, + DRM_FORMAT_NV12, DRM_FORMAT_NV21, DRM_FORMAT_YVU420_ANDROID +}; -static const uint32_t texture_source_formats[] = { DRM_FORMAT_NV12, DRM_FORMAT_R8, DRM_FORMAT_RG88, - DRM_FORMAT_YVU420_ANDROID }; +static const uint32_t texture_source_formats[] = { DRM_FORMAT_NV12, DRM_FORMAT_NV21, + DRM_FORMAT_R8, DRM_FORMAT_R16, + DRM_FORMAT_RG88, DRM_FORMAT_YVU420_ANDROID }; struct virtio_gpu_priv { int caps_is_v2; union virgl_caps caps; + int host_gbm_enabled; }; static uint32_t translate_format(uint32_t drm_fourcc) { switch (drm_fourcc) { + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: + return VIRGL_FORMAT_R8G8B8_UNORM; case DRM_FORMAT_XRGB8888: return VIRGL_FORMAT_B8G8R8X8_UNORM; case DRM_FORMAT_ARGB8888: @@ -73,6 +80,8 @@ static uint32_t translate_format(uint32_t drm_fourcc) return VIRGL_FORMAT_R8G8B8X8_UNORM; case DRM_FORMAT_ABGR8888: return VIRGL_FORMAT_R8G8B8A8_UNORM; + case DRM_FORMAT_ABGR16161616F: + return VIRGL_FORMAT_R16G16B16A16_UNORM; case DRM_FORMAT_RGB565: return VIRGL_FORMAT_B5G6R5_UNORM; case DRM_FORMAT_R8: @@ -81,6 +90,8 @@ static uint32_t translate_format(uint32_t drm_fourcc) return VIRGL_FORMAT_R8G8_UNORM; case DRM_FORMAT_NV12: return VIRGL_FORMAT_NV12; + case DRM_FORMAT_NV21: + return VIRGL_FORMAT_NV21; case DRM_FORMAT_YVU420: case DRM_FORMAT_YVU420_ANDROID: return VIRGL_FORMAT_YV12; @@ -89,8 +100,8 @@ static uint32_t translate_format(uint32_t drm_fourcc) } } -static bool virtio_gpu_supports_format(struct virgl_supported_format_mask *supported, - uint32_t drm_format) +static bool virtio_gpu_bitmask_supports_format(struct virgl_supported_format_mask *supported, + uint32_t drm_format) { uint32_t virgl_format = translate_format(drm_format); if (!virgl_format) { @@ -102,6 +113,243 @@ static bool virtio_gpu_supports_format(struct virgl_supported_format_mask *suppo return supported->bitmask[bitmask_index] & (1 << bit_index); } +// The metadata generated here for emulated buffers is slightly different than the metadata +// generated by drv_bo_from_format. In order to simplify transfers in the flush and invalidate +// functions below, the emulated buffers are oversized. For example, ignoring stride alignment +// requirements to demonstrate, a 6x6 YUV420 image buffer might have the following layout from +// drv_bo_from_format: +// +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | U | U | U | U | U | U | +// | U | U | U | V | V | V | +// | V | V | V | V | V | V | +// +// where each plane immediately follows the previous plane in memory. This layout makes it +// difficult to compute the transfers needed for example when the middle 2x2 region of the +// image is locked and needs to be flushed/invalidated. +// +// Emulated multi-plane buffers instead have a layout of: +// +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | Y | Y | Y | Y | Y | Y | +// | U | U | U | | | | +// | U | U | U | | | | +// | U | U | U | | | | +// | V | V | V | | | | +// | V | V | V | | | | +// | V | V | V | | | | +// +// where each plane is placed as a sub-image (albeit with a very large stride) in order to +// simplify transfers into 3 sub-image transfers for the above example. +// +// Additional note: the V-plane is not placed to the right of the U-plane due to some +// observed failures in media framework code which assumes the V-plane is not +// "row-interlaced" with the U-plane. +static void virtio_gpu_get_emulated_metadata(const struct bo *bo, struct bo_metadata *metadata) +{ + uint32_t y_plane_height; + uint32_t c_plane_height; + uint32_t original_width = bo->meta.width; + uint32_t original_height = bo->meta.height; + + metadata->format = DRM_FORMAT_R8; + switch (bo->meta.format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + // Bi-planar + metadata->num_planes = 2; + + y_plane_height = original_height; + c_plane_height = DIV_ROUND_UP(original_height, 2); + + metadata->width = original_width; + metadata->height = y_plane_height + c_plane_height; + + // Y-plane (full resolution) + metadata->strides[0] = metadata->width; + metadata->offsets[0] = 0; + metadata->sizes[0] = metadata->width * y_plane_height; + + // CbCr-plane (half resolution, interleaved, placed below Y-plane) + metadata->strides[1] = metadata->width; + metadata->offsets[1] = metadata->offsets[0] + metadata->sizes[0]; + metadata->sizes[1] = metadata->width * c_plane_height; + + metadata->total_size = metadata->width * metadata->height; + break; + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU420_ANDROID: + // Tri-planar + metadata->num_planes = 3; + + y_plane_height = original_height; + c_plane_height = DIV_ROUND_UP(original_height, 2); + + metadata->width = ALIGN(original_width, 32); + metadata->height = y_plane_height + (2 * c_plane_height); + + // Y-plane (full resolution) + metadata->strides[0] = metadata->width; + metadata->offsets[0] = 0; + metadata->sizes[0] = metadata->width * original_height; + + // Cb-plane (half resolution, placed below Y-plane) + metadata->strides[1] = metadata->width; + metadata->offsets[1] = metadata->offsets[0] + metadata->sizes[0]; + metadata->sizes[1] = metadata->width * c_plane_height; + + // Cr-plane (half resolution, placed below Cb-plane) + metadata->strides[2] = metadata->width; + metadata->offsets[2] = metadata->offsets[1] + metadata->sizes[1]; + metadata->sizes[2] = metadata->width * c_plane_height; + + metadata->total_size = metadata->width * metadata->height; + break; + default: + break; + } +} + +struct virtio_transfers_params { + size_t xfers_needed; + struct rectangle xfer_boxes[DRV_MAX_PLANES]; +}; + +static void virtio_gpu_get_emulated_transfers_params(const struct bo *bo, + const struct rectangle *transfer_box, + struct virtio_transfers_params *xfer_params) +{ + uint32_t y_plane_height; + uint32_t c_plane_height; + struct bo_metadata emulated_metadata; + + if (transfer_box->x == 0 && transfer_box->y == 0 && transfer_box->width == bo->meta.width && + transfer_box->height == bo->meta.height) { + virtio_gpu_get_emulated_metadata(bo, &emulated_metadata); + + xfer_params->xfers_needed = 1; + xfer_params->xfer_boxes[0].x = 0; + xfer_params->xfer_boxes[0].y = 0; + xfer_params->xfer_boxes[0].width = emulated_metadata.width; + xfer_params->xfer_boxes[0].height = emulated_metadata.height; + + return; + } + + switch (bo->meta.format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + // Bi-planar + xfer_params->xfers_needed = 2; + + y_plane_height = bo->meta.height; + c_plane_height = DIV_ROUND_UP(bo->meta.height, 2); + + // Y-plane (full resolution) + xfer_params->xfer_boxes[0].x = transfer_box->x; + xfer_params->xfer_boxes[0].y = transfer_box->y; + xfer_params->xfer_boxes[0].width = transfer_box->width; + xfer_params->xfer_boxes[0].height = transfer_box->height; + + // CbCr-plane (half resolution, interleaved, placed below Y-plane) + xfer_params->xfer_boxes[1].x = transfer_box->x; + xfer_params->xfer_boxes[1].y = transfer_box->y + y_plane_height; + xfer_params->xfer_boxes[1].width = transfer_box->width; + xfer_params->xfer_boxes[1].height = DIV_ROUND_UP(transfer_box->height, 2); + + break; + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YVU420_ANDROID: + // Tri-planar + xfer_params->xfers_needed = 3; + + y_plane_height = bo->meta.height; + c_plane_height = DIV_ROUND_UP(bo->meta.height, 2); + + // Y-plane (full resolution) + xfer_params->xfer_boxes[0].x = transfer_box->x; + xfer_params->xfer_boxes[0].y = transfer_box->y; + xfer_params->xfer_boxes[0].width = transfer_box->width; + xfer_params->xfer_boxes[0].height = transfer_box->height; + + // Cb-plane (half resolution, placed below Y-plane) + xfer_params->xfer_boxes[1].x = transfer_box->x; + xfer_params->xfer_boxes[1].y = transfer_box->y + y_plane_height; + xfer_params->xfer_boxes[1].width = DIV_ROUND_UP(transfer_box->width, 2); + xfer_params->xfer_boxes[1].height = DIV_ROUND_UP(transfer_box->height, 2); + + // Cr-plane (half resolution, placed below Cb-plane) + xfer_params->xfer_boxes[2].x = transfer_box->x; + xfer_params->xfer_boxes[2].y = transfer_box->y + y_plane_height + c_plane_height; + xfer_params->xfer_boxes[2].width = DIV_ROUND_UP(transfer_box->width, 2); + xfer_params->xfer_boxes[2].height = DIV_ROUND_UP(transfer_box->height, 2); + + break; + } +} + +static bool virtio_gpu_supports_combination_natively(struct driver *drv, uint32_t drm_format, + uint64_t use_flags) +{ + struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + + if (priv->caps.max_version == 0) { + return true; + } + + if ((use_flags & BO_USE_RENDERING) && + !virtio_gpu_bitmask_supports_format(&priv->caps.v1.render, drm_format)) { + return false; + } + + if ((use_flags & BO_USE_TEXTURE) && + !virtio_gpu_bitmask_supports_format(&priv->caps.v1.sampler, drm_format)) { + return false; + } + + if ((use_flags & BO_USE_SCANOUT) && priv->caps_is_v2 && + !virtio_gpu_bitmask_supports_format(&priv->caps.v2.scanout, drm_format)) { + return false; + } + + return true; +} + +// For virtio backends that do not support formats natively (e.g. multi-planar formats are not +// supported in virglrenderer when gbm is unavailable on the host machine), whether or not the +// format and usage combination can be handled as a blob (byte buffer). +static bool virtio_gpu_supports_combination_through_emulation(struct driver *drv, + uint32_t drm_format, + uint64_t use_flags) +{ + struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; + + // Only enable emulation on non-gbm virtio backends. + if (priv->host_gbm_enabled) { + return false; + } + + if (use_flags & (BO_USE_RENDERING | BO_USE_SCANOUT)) { + return false; + } + + if (!virtio_gpu_supports_combination_natively(drv, DRM_FORMAT_R8, use_flags)) { + return false; + } + + return drm_format == DRM_FORMAT_NV12 || drm_format == DRM_FORMAT_NV21 || + drm_format == DRM_FORMAT_YVU420 || drm_format == DRM_FORMAT_YVU420_ANDROID; +} + // Adds the given buffer combination to the list of supported buffer combinations if the // combination is supported by the virtio backend. static void virtio_gpu_add_combination(struct driver *drv, uint32_t drm_format, @@ -110,22 +358,18 @@ static void virtio_gpu_add_combination(struct driver *drv, uint32_t drm_format, struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; if (features[feat_3d].enabled && priv->caps.max_version >= 1) { - if ((use_flags & BO_USE_RENDERING) && - !virtio_gpu_supports_format(&priv->caps.v1.render, drm_format)) { - drv_log("Skipping unsupported render format: %d\n", drm_format); - return; + if ((use_flags & BO_USE_SCANOUT) && priv->caps_is_v2 && + !virtio_gpu_supports_combination_natively(drv, drm_format, use_flags)) { + drv_log("Scanout format: %d\n", drm_format); + use_flags &= ~BO_USE_SCANOUT; } - if ((use_flags & BO_USE_TEXTURE) && - !virtio_gpu_supports_format(&priv->caps.v1.sampler, drm_format)) { - drv_log("Skipping unsupported texture format: %d\n", drm_format); + if (!virtio_gpu_supports_combination_natively(drv, drm_format, use_flags) && + !virtio_gpu_supports_combination_through_emulation(drv, drm_format, + use_flags)) { + drv_log("Skipping unsupported combination format:%d\n", drm_format); return; } - if ((use_flags & BO_USE_SCANOUT) && priv->caps_is_v2 && - !virtio_gpu_supports_format(&priv->caps.v2.scanout, drm_format)) { - drv_log("Unsupported scanout format: %d\n", drm_format); - use_flags &= ~BO_USE_SCANOUT; - } } drv_add_combination(drv, drm_format, metadata, use_flags); @@ -196,11 +440,30 @@ static int virtio_virgl_bo_create(struct bo *bo, uint32_t width, uint32_t height uint64_t use_flags) { int ret; + size_t i; uint32_t stride; struct drm_virtgpu_resource_create res_create; + struct bo_metadata emulated_metadata; - stride = drv_stride_from_format(format, width, 0); - drv_bo_from_format(bo, stride, height, format); + if (virtio_gpu_supports_combination_natively(bo->drv, format, use_flags)) { + stride = drv_stride_from_format(format, width, 0); + drv_bo_from_format(bo, stride, height, format); + } else { + assert( + virtio_gpu_supports_combination_through_emulation(bo->drv, format, use_flags)); + + virtio_gpu_get_emulated_metadata(bo, &emulated_metadata); + + format = emulated_metadata.format; + width = emulated_metadata.width; + height = emulated_metadata.height; + for (i = 0; i < emulated_metadata.num_planes; i++) { + bo->meta.strides[i] = emulated_metadata.strides[i]; + bo->meta.offsets[i] = emulated_metadata.offsets[i]; + bo->meta.sizes[i] = emulated_metadata.sizes[i]; + } + bo->meta.total_size = emulated_metadata.total_size; + } /* * Setting the target is intended to ensure this resource gets bound as a 2D @@ -290,26 +553,39 @@ static int virtio_gpu_get_caps(struct driver *drv, union virgl_caps *caps, int * return ret; } -static int virtio_gpu_init(struct driver *drv) +static void virtio_gpu_init_features_and_caps(struct driver *drv) { - int ret; - struct virtio_gpu_priv *priv; + struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)drv->priv; - priv = calloc(1, sizeof(*priv)); - drv->priv = priv; for (uint32_t i = 0; i < ARRAY_SIZE(features); i++) { struct drm_virtgpu_getparam params = { 0 }; params.param = features[i].feature; params.value = (uint64_t)(uintptr_t)&features[i].enabled; - ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GETPARAM, ¶ms); + int ret = drmIoctl(drv->fd, DRM_IOCTL_VIRTGPU_GETPARAM, ¶ms); if (ret) drv_log("DRM_IOCTL_VIRTGPU_GET_PARAM failed with %s\n", strerror(errno)); } if (features[feat_3d].enabled) { virtio_gpu_get_caps(drv, &priv->caps, &priv->caps_is_v2); + } + // Multi-planar formats are currently only supported in virglrenderer through gbm. + priv->host_gbm_enabled = + virtio_gpu_supports_combination_natively(drv, DRM_FORMAT_NV12, BO_USE_TEXTURE); +} + +static int virtio_gpu_init(struct driver *drv) +{ + struct virtio_gpu_priv *priv; + + priv = calloc(1, sizeof(*priv)); + drv->priv = priv; + + virtio_gpu_init_features_and_caps(drv); + + if (features[feat_3d].enabled) { /* This doesn't mean host can scanout everything, it just means host * hypervisor can show it. */ virtio_gpu_add_combinations(drv, render_target_formats, @@ -336,16 +612,29 @@ static int virtio_gpu_init(struct driver *drv) &LINEAR_METADATA, BO_USE_TEXTURE_MASK); virtio_gpu_add_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA, BO_USE_SW_MASK | BO_USE_LINEAR); + virtio_gpu_add_combination(drv, DRM_FORMAT_NV21, &LINEAR_METADATA, + BO_USE_SW_MASK | BO_USE_LINEAR); } /* Android CTS tests require this. */ + virtio_gpu_add_combination(drv, DRM_FORMAT_RGB888, &LINEAR_METADATA, BO_USE_SW_MASK); virtio_gpu_add_combination(drv, DRM_FORMAT_BGR888, &LINEAR_METADATA, BO_USE_SW_MASK); + virtio_gpu_add_combination(drv, DRM_FORMAT_ABGR16161616F, &LINEAR_METADATA, + BO_USE_SW_MASK | BO_USE_TEXTURE_MASK); drv_modify_combination(drv, DRM_FORMAT_NV12, &LINEAR_METADATA, BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER | BO_USE_HW_VIDEO_ENCODER); + drv_modify_combination(drv, DRM_FORMAT_NV21, &LINEAR_METADATA, + BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER | + BO_USE_HW_VIDEO_ENCODER); + drv_modify_combination(drv, DRM_FORMAT_YVU420, &LINEAR_METADATA, + BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER | + BO_USE_HW_VIDEO_ENCODER | BO_USE_RENDERSCRIPT); drv_modify_combination(drv, DRM_FORMAT_R8, &LINEAR_METADATA, BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER); + drv_modify_combination(drv, DRM_FORMAT_R16, &LINEAR_METADATA, + BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER); return drv_modify_linear_combinations(drv); } @@ -384,8 +673,11 @@ static void *virtio_gpu_bo_map(struct bo *bo, struct vma *vma, size_t plane, uin static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) { int ret; + size_t i; struct drm_virtgpu_3d_transfer_from_host xfer; struct drm_virtgpu_3d_wait waitcmd; + struct virtio_transfers_params xfer_params; + struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)bo->drv->priv; if (!features[feat_3d].enabled) return 0; @@ -397,27 +689,44 @@ static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) memset(&xfer, 0, sizeof(xfer)); xfer.bo_handle = mapping->vma->handle; - xfer.box.x = mapping->rect.x; - xfer.box.y = mapping->rect.y; - xfer.box.w = mapping->rect.width; - xfer.box.h = mapping->rect.height; - xfer.box.d = 1; if ((bo->meta.use_flags & BO_USE_RENDERING) == 0) { - // Unfortunately, the kernel doesn't actually pass the guest layer_stride and - // guest stride to the host (compare virtio_gpu.h and virtgpu_drm.h). For gbm - // based resources, we can work around this by using the level field to pass - // the stride to virglrenderer's gbm transfer code. However, we need to avoid - // doing this for resources which don't rely on that transfer code, which is - // resources with the BO_USE_RENDERING flag set. + // Unfortunately, the kernel doesn't actually pass the guest layer_stride + // and guest stride to the host (compare virtio_gpu.h and virtgpu_drm.h). + // For gbm based resources, we can work around this by using the level field + // to pass the stride to virglrenderer's gbm transfer code. However, we need + // to avoid doing this for resources which don't rely on that transfer code, + // which is resources with the BO_USE_RENDERING flag set. // TODO(b/145993887): Send also stride when the patches are landed - xfer.level = bo->meta.strides[0]; + if (priv->host_gbm_enabled) { + xfer.level = bo->meta.strides[0]; + } } - ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST, &xfer); - if (ret) { - drv_log("DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST failed with %s\n", strerror(errno)); - return -errno; + if (virtio_gpu_supports_combination_natively(bo->drv, bo->meta.format, + bo->meta.use_flags)) { + xfer_params.xfers_needed = 1; + xfer_params.xfer_boxes[0] = mapping->rect; + } else { + assert(virtio_gpu_supports_combination_through_emulation(bo->drv, bo->meta.format, + bo->meta.use_flags)); + + virtio_gpu_get_emulated_transfers_params(bo, &mapping->rect, &xfer_params); + } + + for (i = 0; i < xfer_params.xfers_needed; i++) { + xfer.box.x = xfer_params.xfer_boxes[i].x; + xfer.box.y = xfer_params.xfer_boxes[i].y; + xfer.box.w = xfer_params.xfer_boxes[i].width; + xfer.box.h = xfer_params.xfer_boxes[i].height; + xfer.box.d = 1; + + ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST, &xfer); + if (ret) { + drv_log("DRM_IOCTL_VIRTGPU_TRANSFER_FROM_HOST failed with %s\n", + strerror(errno)); + return -errno; + } } // The transfer needs to complete before invalidate returns so that any host changes @@ -437,8 +746,11 @@ static int virtio_gpu_bo_invalidate(struct bo *bo, struct mapping *mapping) static int virtio_gpu_bo_flush(struct bo *bo, struct mapping *mapping) { int ret; + size_t i; struct drm_virtgpu_3d_transfer_to_host xfer; struct drm_virtgpu_3d_wait waitcmd; + struct virtio_transfers_params xfer_params; + struct virtio_gpu_priv *priv = (struct virtio_gpu_priv *)bo->drv->priv; if (!features[feat_3d].enabled) return 0; @@ -448,21 +760,38 @@ static int virtio_gpu_bo_flush(struct bo *bo, struct mapping *mapping) memset(&xfer, 0, sizeof(xfer)); xfer.bo_handle = mapping->vma->handle; - xfer.box.x = mapping->rect.x; - xfer.box.y = mapping->rect.y; - xfer.box.w = mapping->rect.width; - xfer.box.h = mapping->rect.height; - xfer.box.d = 1; // Unfortunately, the kernel doesn't actually pass the guest layer_stride and // guest stride to the host (compare virtio_gpu.h and virtgpu_drm.h). We can use // the level to work around this. - xfer.level = bo->meta.strides[0]; + if (priv->host_gbm_enabled) { + xfer.level = bo->meta.strides[0]; + } - ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST, &xfer); - if (ret) { - drv_log("DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST failed with %s\n", strerror(errno)); - return -errno; + if (virtio_gpu_supports_combination_natively(bo->drv, bo->meta.format, + bo->meta.use_flags)) { + xfer_params.xfers_needed = 1; + xfer_params.xfer_boxes[0] = mapping->rect; + } else { + assert(virtio_gpu_supports_combination_through_emulation(bo->drv, bo->meta.format, + bo->meta.use_flags)); + + virtio_gpu_get_emulated_transfers_params(bo, &mapping->rect, &xfer_params); + } + + for (i = 0; i < xfer_params.xfers_needed; i++) { + xfer.box.x = xfer_params.xfer_boxes[i].x; + xfer.box.y = xfer_params.xfer_boxes[i].y; + xfer.box.w = xfer_params.xfer_boxes[i].width; + xfer.box.h = xfer_params.xfer_boxes[i].height; + xfer.box.d = 1; + + ret = drmIoctl(bo->drv->fd, DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST, &xfer); + if (ret) { + drv_log("DRM_IOCTL_VIRTGPU_TRANSFER_TO_HOST failed with %s\n", + strerror(errno)); + return -errno; + } } // If the buffer is only accessed by the host GPU, then the flush is ordered @@ -485,7 +814,6 @@ static int virtio_gpu_bo_flush(struct bo *bo, struct mapping *mapping) static uint32_t virtio_gpu_resolve_format(struct driver *drv, uint32_t format, uint64_t use_flags) { - switch (format) { case DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED: /* Camera subsystem requires NV12. */ -- 2.11.0