cros_gralloc: Adds gralloc 3.0 support
Implements the allocator 3.0 and mapper 3.0 interfaces
which:
- Implements HIDL interface directly (older versions
are wrapped in a passthrough HIDL interface)
- Adds isSupported() to allow checking for format and
usage combination support before allocating.
Adds emulated multi-planar buffer support to virtio
backend for non gbm enabled hosts.
Updates cros_gralloc_handle to use uint64_t instead of
two uint32_t for some members.
Updates cros_gralloc_handle to have a single format
modifier.
Replaces Android makefiles with Android bp files.
BUG=b:146515640
TEST=run Cuttlefish w/ gralloc3 and run CTS tests
Change-Id: I43ed9788a2413201bddce17ffb69b76006ef39fd
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/2273554
Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: Jason Macnak <natsu@google.com>
Commit-Queue: Jason Macnak <natsu@google.com>
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..bd7a639
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+
+cc_defaults {
+ name: "minigbm_defaults",
+
+ srcs: [
+ "amdgpu.c",
+ "drv.c",
+ "evdi.c",
+ "exynos.c",
+ "helpers_array.c",
+ "helpers.c",
+ "i915.c",
+ "marvell.c",
+ "mediatek.c",
+ "meson.c",
+ "msm.c",
+ "nouveau.c",
+ "radeon.c",
+ "rockchip.c",
+ "tegra.c",
+ "udl.c",
+ "vc4.c",
+ "vgem.c",
+ "virtio_gpu.c",
+ ],
+
+ cflags: [
+ "-D_GNU_SOURCE=1",
+ "-D_FILE_OFFSET_BITS=64",
+ "-Wall",
+ "-Wsign-compare",
+ "-Wpointer-arith",
+ "-Wcast-qual",
+ "-Wcast-align",
+ "-Wno-unused-parameter",
+ ],
+
+ cppflags: ["-std=c++14"],
+
+ vendor: true,
+
+ 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_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_gralloc",
+ defaults: ["minigbm_gralloc_defaults"],
+ shared_libs: ["liblog"],
+ static_libs: ["libdrm"],
+
+ export_include_dirs: ["."],
+}
+
+cc_library_shared {
+ name: "gralloc.minigbm",
+ defaults: ["minigbm_gralloc_defaults"],
+ srcs: ["cros_gralloc/gralloc0/gralloc0.cc"],
+}
+
+cc_library_shared {
+ name: "gralloc.minigbm_intel",
+ defaults: ["minigbm_gralloc_defaults"],
+ enabled: false,
+ arch: {
+ x86: {
+ enabled: true,
+ },
+ x86_64: {
+ enabled: true,
+ },
+ },
+ cflags: ["-DDRV_I915"],
+ srcs: ["cros_gralloc/gralloc0/gralloc0.cc"],
+}
+
+cc_library_shared {
+ name: "gralloc.minigbm_meson",
+ defaults: ["minigbm_gralloc_defaults"],
+ cflags: ["-DDRV_MESON"],
+ srcs: ["cros_gralloc/gralloc0/gralloc0.cc"],
+}
\ No newline at end of file
diff --git a/cros_gralloc/Makefile b/cros_gralloc/Makefile
index 17e884f..c95ad2c 100644
--- a/cros_gralloc/Makefile
+++ b/cros_gralloc/Makefile
@@ -16,9 +16,9 @@
LIBDRM_CFLAGS := $(shell $(PKG_CONFIG) --cflags libdrm)
LIBDRM_LIBS := $(shell $(PKG_CONFIG) --libs libdrm)
-CPPFLAGS += -Wall -fPIC -Werror -flto $(LIBDRM_CFLAGS)
+CPPFLAGS += -Wall -fPIC -Werror -flto $(LIBDRM_CFLAGS) -D_GNU_SOURCE=1
CXXFLAGS += -std=c++14
-CFLAGS += -std=c99
+CFLAGS += -std=c99 -D_GNU_SOURCE=1
LIBS += -shared -lcutils -lhardware -lsync $(LIBDRM_LIBS)
OBJS = $(foreach source, $(SOURCES), $(addsuffix .o, $(basename $(source))))
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 <sys/mman.h>
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 @@
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 @@
{
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..cb6cb4b 100644
--- a/cros_gralloc/cros_gralloc_buffer.h
+++ b/cros_gralloc/cros_gralloc_buffer.h
@@ -14,7 +14,8 @@
{
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 @@
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 @@
uint32_t num_planes_;
struct mapping *lock_data_[DRV_MAX_PLANES];
+
+ /* Optional additional shared memory region attached to some gralloc 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..e32704a 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 <cstdlib>
#include <fcntl.h>
+#include <sys/mman.h>
#include <xf86drm.h>
+#include "../drv_priv.h"
+#include "../helpers.h"
+#include "../util.h"
+
cros_gralloc_driver::cros_gralloc_driver() : drv_(nullptr)
{
}
@@ -90,15 +94,43 @@
return (combo != nullptr);
}
+int32_t create_reserved_region(const std::string &buffer_name, uint64_t reserved_region_size)
+{
+ std::string reserved_region_name = buffer_name + " reserved region";
+
+#ifdef __NR_memfd_create
+ int32_t 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;
+#else
+ drv_log("Failed to create reserved region '%s': memfd_create not available.",
+ reserved_region_name.c_str());
+ return -1;
+#endif
+}
+
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 +172,72 @@
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 ultimately destroyed via free in
+ * native_handle_delete().
+ */
+ hnd = static_cast<struct cros_gralloc_handle *>(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<uint32_t>(mod >> 32);
- hnd->format_modifiers[2 * plane + 1] = static_cast<uint32_t>(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<uint32_t> 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<uint32_t>(descriptor->use_flags >> 32);
- hnd->use_flags[1] = static_cast<uint32_t>(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<std::mutex> lock(mutex_);
buffers_.emplace(id, buffer);
handles_.emplace(hnd, std::make_pair(buffer, 1));
- *out_handle = &hnd->base;
+ *out_handle = reinterpret_cast<buffer_handle_t>(hnd);
return 0;
}
@@ -208,18 +271,16 @@
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<uint64_t>(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<uint64_t>(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 +289,8 @@
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 +326,10 @@
}
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 +375,51 @@
return buffer->unlock();
}
+int32_t cros_gralloc_driver::invalidate(buffer_handle_t handle)
+{
+ std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lock(mutex_);
@@ -353,6 +460,32 @@
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<std::mutex> 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 +494,13 @@
return nullptr;
}
+
+void cros_gralloc_driver::for_each_handle(
+ const std::function<void(cros_gralloc_handle_t)> &function)
+{
+ std::lock_guard<std::mutex> 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 <functional>
#include <mutex>
#include <unordered_map>
@@ -26,14 +27,25 @@
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<void(cros_gralloc_handle_t)> &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 <cutils/native_handle.h>
#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 @@
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 @@
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 @@
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 <string>
+
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 9f24a5d..98ce8c6 100644
--- a/cros_gralloc/gralloc0/gralloc0.cc
+++ b/cros_gralloc/gralloc0/gralloc0.cc
@@ -119,9 +119,10 @@
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 @@
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 @@
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 @@
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 <gralloc_drm.h> */
-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/gralloc3/.clang-format b/cros_gralloc/gralloc3/.clang-format
new file mode 100644
index 0000000..534cd32
--- /dev/null
+++ b/cros_gralloc/gralloc3/.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/gralloc3/Android.bp b/cros_gralloc/gralloc3/Android.bp
new file mode 100644
index 0000000..96317ed
--- /dev/null
+++ b/cros_gralloc/gralloc3/Android.bp
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+cc_binary {
+ name: "android.hardware.graphics.allocator@3.0-service.minigbm",
+ relative_install_path: "hw",
+ vendor: true,
+ init_rc: ["android.hardware.graphics.allocator@3.0-service.minigbm.rc"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.mapper@3.0",
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libdrm",
+ "libminigbm_gralloc",
+ ],
+
+ srcs: [
+ "CrosGralloc3Allocator.cc",
+ "CrosGralloc3AllocatorService.cc",
+ "CrosGralloc3Utils.cc",
+ ],
+}
+
+cc_library_shared {
+ name: "android.hardware.graphics.mapper@3.0-impl.minigbm",
+ relative_install_path: "hw",
+ vendor: true,
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "android.hardware.graphics.mapper@3.0",
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+
+ static_libs: [
+ "libdrm",
+ "libminigbm_gralloc",
+ ],
+
+ srcs: [
+ "CrosGralloc3Mapper.cc",
+ "CrosGralloc3Utils.cc",
+ ],
+}
diff --git a/cros_gralloc/gralloc3/CrosGralloc3Allocator.cc b/cros_gralloc/gralloc3/CrosGralloc3Allocator.cc
new file mode 100644
index 0000000..6ee5f21
--- /dev/null
+++ b/cros_gralloc/gralloc3/CrosGralloc3Allocator.cc
@@ -0,0 +1,128 @@
+/*
+ * 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/gralloc3/CrosGralloc3Allocator.h"
+
+#include <optional>
+
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+
+#include "cros_gralloc/cros_gralloc_helpers.h"
+#include "cros_gralloc/gralloc3/CrosGralloc3Utils.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::V3_0::Error;
+
+using BufferDescriptorInfo =
+ android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo;
+
+CrosGralloc3Allocator::CrosGralloc3Allocator() : mDriver(std::make_unique<cros_gralloc_driver>()) {
+ if (mDriver->init()) {
+ drv_log("Failed to initialize driver.\n");
+ mDriver = nullptr;
+ }
+}
+
+Error CrosGralloc3Allocator::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<void> CrosGralloc3Allocator::allocate(const hidl_vec<uint32_t>& encoded, uint32_t count,
+ allocate_cb hidlCb) {
+ hidl_vec<hidl_handle> handles;
+
+ if (!mDriver) {
+ drv_log("Failed to allocate. Driver is uninitialized.\n");
+ hidlCb(Error::NO_RESOURCES, 0, handles);
+ return Void();
+ }
+
+ auto descriptor_opt = decodeBufferDescriptorInfo(encoded);
+ if (!descriptor_opt) {
+ drv_log("Failed to allocate. Failed to decode buffer descriptor.\n");
+ hidlCb(Error::BAD_DESCRIPTOR, 0, handles);
+ return Void();
+ }
+
+ BufferDescriptorInfo descriptor = *descriptor_opt;
+
+ handles.resize(count);
+
+ uint32_t stride = 0;
+ for (int i = 0; i < handles.size(); i++) {
+ Error err = allocate(descriptor, &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();
+}
+
+Return<void> CrosGralloc3Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+ hidl_cb("CrosGralloc3Allocator::dumpDebugInfo unimplemented.");
+ return Void();
+}
diff --git a/cros_gralloc/gralloc3/CrosGralloc3Allocator.h b/cros_gralloc/gralloc3/CrosGralloc3Allocator.h
new file mode 100644
index 0000000..655143c
--- /dev/null
+++ b/cros_gralloc/gralloc3/CrosGralloc3Allocator.h
@@ -0,0 +1,29 @@
+/*
+ * 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 <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+
+#include "cros_gralloc/cros_gralloc_driver.h"
+
+class CrosGralloc3Allocator : public android::hardware::graphics::allocator::V3_0::IAllocator {
+ public:
+ CrosGralloc3Allocator();
+
+ android::hardware::Return<void> allocate(
+ const android::hardware::hidl_vec<uint32_t>& descriptor, uint32_t count,
+ allocate_cb hidl_cb) override;
+
+ android::hardware::Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+
+ private:
+ android::hardware::graphics::mapper::V3_0::Error allocate(
+ const android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo&
+ description,
+ uint32_t* outStride, android::hardware::hidl_handle* outHandle);
+
+ std::unique_ptr<cros_gralloc_driver> mDriver;
+};
diff --git a/cros_gralloc/gralloc3/CrosGralloc3AllocatorService.cc b/cros_gralloc/gralloc3/CrosGralloc3AllocatorService.cc
new file mode 100644
index 0000000..daab508
--- /dev/null
+++ b/cros_gralloc/gralloc3/CrosGralloc3AllocatorService.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 <hidl/LegacySupport.h>
+
+#include "cros_gralloc/gralloc3/CrosGralloc3Allocator.h"
+
+using android::sp;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::graphics::allocator::V3_0::IAllocator;
+
+int main(int, char**) {
+ sp<IAllocator> allocator = new CrosGralloc3Allocator();
+ configureRpcThreadpool(4, true /* callerWillJoin */);
+ if (allocator->registerAsService() != android::NO_ERROR) {
+ ALOGE("failed to register graphics IAllocator 3.0 service");
+ return -EINVAL;
+ }
+
+ ALOGI("graphics IAllocator 3.0 service is initialized");
+ android::hardware::joinRpcThreadpool();
+ ALOGI("graphics IAllocator 3.0 service is terminating");
+ return 0;
+}
diff --git a/cros_gralloc/gralloc3/CrosGralloc3Mapper.cc b/cros_gralloc/gralloc3/CrosGralloc3Mapper.cc
new file mode 100644
index 0000000..5149e4a
--- /dev/null
+++ b/cros_gralloc/gralloc3/CrosGralloc3Mapper.cc
@@ -0,0 +1,488 @@
+/*
+ * 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/gralloc3/CrosGralloc3Mapper.h"
+
+#include <cutils/native_handle.h>
+
+#include "cros_gralloc/gralloc3/CrosGralloc3Utils.h"
+#include "helpers.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::V3_0::Error;
+using android::hardware::graphics::mapper::V3_0::IMapper;
+using android::hardware::graphics::mapper::V3_0::YCbCrLayout;
+
+CrosGralloc3Mapper::CrosGralloc3Mapper() : mDriver(std::make_unique<cros_gralloc_driver>()) {
+ if (mDriver->init()) {
+ drv_log("Failed to initialize driver.\n");
+ mDriver = nullptr;
+ }
+}
+
+Return<void> CrosGralloc3Mapper::createDescriptor(const BufferDescriptorInfo& description,
+ createDescriptor_cb hidlCb) {
+ hidl_vec<uint32_t> 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();
+ }
+
+ auto descriptor_opt = encodeBufferDescriptorInfo(description);
+ if (!descriptor_opt) {
+ drv_log("Failed to createDescriptor. Failed to encodeBufferDescriptorInfo\n");
+ hidlCb(Error::BAD_VALUE, descriptor);
+ return Void();
+ }
+
+ descriptor = *descriptor_opt;
+ hidlCb(Error::NONE, descriptor);
+ return Void();
+}
+
+Return<void> CrosGralloc3Mapper::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<Error> CrosGralloc3Mapper::freeBuffer(void* rawHandle) {
+ if (!mDriver) {
+ drv_log("Failed to freeBuffer. Driver is uninitialized.\n");
+ return Error::NO_RESOURCES;
+ }
+
+ native_handle_t* bufferHandle = reinterpret_cast<native_handle_t*>(rawHandle);
+ if (!bufferHandle) {
+ drv_log("Failed to freeBuffer. Empty handle.\n");
+ return Error::BAD_BUFFER;
+ }
+
+ int ret = mDriver->release(bufferHandle);
+ if (ret) {
+ drv_log("Failed to freeBuffer.\n");
+ return Error::BAD_BUFFER;
+ }
+
+ native_handle_close(bufferHandle);
+ native_handle_delete(bufferHandle);
+ return Error::NONE;
+}
+
+Return<Error> CrosGralloc3Mapper::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<native_handle_t*>(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<PixelFormat>(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<void> CrosGralloc3Mapper::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<native_handle_t*>(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<void> CrosGralloc3Mapper::lock(void* rawHandle, uint64_t cpuUsage, const Rect& accessRegion,
+ const hidl_handle& acquireFence, lock_cb hidlCb) {
+ if (!mDriver) {
+ drv_log("Failed to lock. Driver is uninitialized.\n");
+ hidlCb(Error::NO_RESOURCES, nullptr, 0, 0);
+ return Void();
+ }
+
+ buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
+ if (!bufferHandle) {
+ drv_log("Failed to lock. Empty handle.\n");
+ hidlCb(Error::BAD_BUFFER, nullptr, 0, 0);
+ 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_BUFFER, nullptr, 0, 0);
+ return Void();
+ }
+
+ LockResult result = lockInternal(crosHandle, cpuUsage, accessRegion, acquireFence);
+ if (result.error != Error::NONE) {
+ drv_log("Failed to lock. Failed to lockInternal.\n");
+ hidlCb(result.error, nullptr, 0, 0);
+ return Void();
+ }
+
+ int32_t bytesPerPixel = drv_bytes_per_pixel_from_format(crosHandle->format, 0);
+ int32_t bytesPerStride = static_cast<int32_t>(crosHandle->strides[0]);
+
+ hidlCb(Error::NONE, result.mapped[0], bytesPerPixel, bytesPerStride);
+ return Void();
+}
+
+Return<void> CrosGralloc3Mapper::lockYCbCr(void* rawHandle, uint64_t cpuUsage,
+ const Rect& accessRegion,
+ const android::hardware::hidl_handle& acquireFence,
+ lockYCbCr_cb hidlCb) {
+ YCbCrLayout ycbcr = {};
+
+ if (!mDriver) {
+ drv_log("Failed to lock. Driver is uninitialized.\n");
+ hidlCb(Error::NO_RESOURCES, ycbcr);
+ return Void();
+ }
+
+ buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(rawHandle);
+ if (!bufferHandle) {
+ drv_log("Failed to lockYCbCr. Empty handle.\n");
+ hidlCb(Error::BAD_BUFFER, ycbcr);
+ return Void();
+ }
+
+ cros_gralloc_handle_t crosHandle = cros_gralloc_convert_handle(bufferHandle);
+ if (crosHandle == nullptr) {
+ drv_log("Failed to lockYCbCr. Invalid handle.\n");
+ hidlCb(Error::BAD_BUFFER, ycbcr);
+ return Void();
+ }
+
+ LockResult result = lockInternal(crosHandle, cpuUsage, accessRegion, acquireFence);
+ if (result.error != Error::NONE) {
+ drv_log("Failed to lockYCbCr. Failed to lockInternal.\n");
+ hidlCb(result.error, ycbcr);
+ return Void();
+ }
+
+ switch (crosHandle->format) {
+ case DRM_FORMAT_NV12: {
+ ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
+ ycbcr.cb = result.mapped[0] + crosHandle->offsets[1];
+ ycbcr.cr = result.mapped[0] + crosHandle->offsets[1] + 1;
+ ycbcr.yStride = crosHandle->strides[0];
+ ycbcr.cStride = crosHandle->strides[1];
+ ycbcr.chromaStep = 2;
+ break;
+ }
+ case DRM_FORMAT_NV21: {
+ ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
+ ycbcr.cb = result.mapped[0] + crosHandle->offsets[1] + 1;
+ ycbcr.cr = result.mapped[0] + crosHandle->offsets[1];
+ ycbcr.yStride = crosHandle->strides[0];
+ ycbcr.cStride = crosHandle->strides[1];
+ ycbcr.chromaStep = 2;
+ break;
+ }
+ case DRM_FORMAT_YVU420: {
+ ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
+ ycbcr.cb = result.mapped[0] + crosHandle->offsets[1];
+ ycbcr.cr = result.mapped[0] + crosHandle->offsets[2];
+ ycbcr.yStride = crosHandle->strides[0];
+ ycbcr.cStride = crosHandle->strides[1];
+ ycbcr.chromaStep = 1;
+ break;
+ }
+ case DRM_FORMAT_YVU420_ANDROID: {
+ ycbcr.y = result.mapped[0] + crosHandle->offsets[0];
+ ycbcr.cb = result.mapped[0] + crosHandle->offsets[2];
+ ycbcr.cr = result.mapped[0] + crosHandle->offsets[1];
+ ycbcr.yStride = crosHandle->strides[0];
+ ycbcr.cStride = crosHandle->strides[1];
+ ycbcr.chromaStep = 1;
+ break;
+ }
+ default: {
+ std::string format = getDrmFormatString(crosHandle->format);
+ drv_log("Failed to lockYCbCr. Unhandled format: %s\n", format.c_str());
+ hidlCb(Error::BAD_BUFFER, ycbcr);
+ return Void();
+ }
+ }
+
+ hidlCb(Error::NONE, ycbcr);
+ return Void();
+}
+
+CrosGralloc3Mapper::LockResult CrosGralloc3Mapper::lockInternal(
+ cros_gralloc_handle_t crosHandle, uint64_t cpuUsage, const Rect& region,
+ const android::hardware::hidl_handle& acquireFence) {
+ LockResult result = {};
+
+ if (!mDriver) {
+ drv_log("Failed to lock. Driver is uninitialized.\n");
+ result.error = Error::NO_RESOURCES;
+ return result;
+ }
+
+ if (cpuUsage == 0) {
+ drv_log("Failed to lock. Bad cpu usage: %" PRIu64 ".\n", cpuUsage);
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ uint32_t mapUsage = 0;
+ int ret = convertToMapUsage(cpuUsage, &mapUsage);
+ if (ret) {
+ drv_log("Failed to lock. Convert usage failed.\n");
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ if (region.left < 0) {
+ drv_log("Failed to lock. Invalid region: negative left value %d.\n", region.left);
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ if (region.top < 0) {
+ drv_log("Failed to lock. Invalid region: negative top value %d.\n", region.top);
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ if (region.width < 0) {
+ drv_log("Failed to lock. Invalid region: negative width value %d.\n", region.width);
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ if (region.height < 0) {
+ drv_log("Failed to lock. Invalid region: negative height value %d.\n", region.height);
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ 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);
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ 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);
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ struct rectangle rect = {static_cast<uint32_t>(region.left), static_cast<uint32_t>(region.top),
+ static_cast<uint32_t>(region.width),
+ static_cast<uint32_t>(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");
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ buffer_handle_t bufferHandle = reinterpret_cast<buffer_handle_t>(crosHandle);
+ ret = mDriver->lock(bufferHandle, acquireFenceFd, false, &rect, mapUsage, result.mapped);
+ if (ret) {
+ result.error = Error::BAD_VALUE;
+ return result;
+ }
+
+ result.error = Error::NONE;
+ return result;
+}
+
+Return<void> CrosGralloc3Mapper::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<buffer_handle_t>(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<void> CrosGralloc3Mapper::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();
+}
+
+int CrosGralloc3Mapper::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;
+}
+
+android::hardware::graphics::mapper::V3_0::IMapper* HIDL_FETCH_IMapper(const char* /*name*/) {
+ return static_cast<android::hardware::graphics::mapper::V3_0::IMapper*>(new CrosGralloc3Mapper);
+}
diff --git a/cros_gralloc/gralloc3/CrosGralloc3Mapper.h b/cros_gralloc/gralloc3/CrosGralloc3Mapper.h
new file mode 100644
index 0000000..7ec92d5
--- /dev/null
+++ b/cros_gralloc/gralloc3/CrosGralloc3Mapper.h
@@ -0,0 +1,64 @@
+/*
+ * 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 <android/hardware/graphics/mapper/3.0/IMapper.h>
+
+#include <optional>
+
+#include "cros_gralloc/cros_gralloc_driver.h"
+#include "cros_gralloc/cros_gralloc_handle.h"
+
+class CrosGralloc3Mapper : public android::hardware::graphics::mapper::V3_0::IMapper {
+ public:
+ CrosGralloc3Mapper();
+
+ android::hardware::Return<void> createDescriptor(const BufferDescriptorInfo& description,
+ createDescriptor_cb hidlCb) override;
+
+ android::hardware::Return<void> importBuffer(const android::hardware::hidl_handle& rawHandle,
+ importBuffer_cb hidlCb) override;
+
+ android::hardware::Return<android::hardware::graphics::mapper::V3_0::Error> freeBuffer(
+ void* rawHandle) override;
+
+ android::hardware::Return<android::hardware::graphics::mapper::V3_0::Error> validateBufferSize(
+ void* rawHandle, const BufferDescriptorInfo& descriptor, uint32_t stride) override;
+
+ android::hardware::Return<void> getTransportSize(void* rawHandle,
+ getTransportSize_cb hidlCb) override;
+
+ android::hardware::Return<void> lock(void* rawHandle, uint64_t cpuUsage,
+ const Rect& accessRegion,
+ const android::hardware::hidl_handle& acquireFence,
+ lock_cb hidlCb) override;
+
+ android::hardware::Return<void> lockYCbCr(void* rawHandle, uint64_t cpuUsage,
+ const Rect& accessRegion,
+ const android::hardware::hidl_handle& acquireFence,
+ lockYCbCr_cb _hidl_cb) override;
+
+ android::hardware::Return<void> unlock(void* rawHandle, unlock_cb hidlCb) override;
+
+ android::hardware::Return<void> isSupported(const BufferDescriptorInfo& descriptor,
+ isSupported_cb hidlCb) override;
+
+ private:
+ int getResolvedDrmFormat(android::hardware::graphics::common::V1_2::PixelFormat pixelFormat,
+ uint64_t bufferUsage, uint32_t* outDrmFormat);
+
+ struct LockResult {
+ android::hardware::graphics::mapper::V3_0::Error error;
+
+ uint8_t* mapped[DRV_MAX_PLANES];
+ };
+ LockResult lockInternal(cros_gralloc_handle_t crosHandle, uint64_t cpuUsage,
+ const Rect& accessRegion,
+ const android::hardware::hidl_handle& acquireFence);
+
+ std::unique_ptr<cros_gralloc_driver> mDriver;
+};
+
+extern "C" android::hardware::graphics::mapper::V3_0::IMapper* HIDL_FETCH_IMapper(const char* name);
diff --git a/cros_gralloc/gralloc3/CrosGralloc3Utils.cc b/cros_gralloc/gralloc3/CrosGralloc3Utils.cc
new file mode 100644
index 0000000..c2b40e2
--- /dev/null
+++ b/cros_gralloc/gralloc3/CrosGralloc3Utils.cc
@@ -0,0 +1,507 @@
+/*
+ * 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/gralloc3/CrosGralloc3Utils.h"
+
+#include <array>
+#include <limits>
+#include <unordered_map>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <cutils/native_handle.h>
+
+#include "cros_gralloc/cros_gralloc_helpers.h"
+
+using android::hardware::hidl_bitfield;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::common::V1_2::PixelFormat;
+
+using BufferDescriptorInfo =
+ android::hardware::graphics::mapper::V3_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_FLEX_IMPLEMENTATION_DEFINED:
+ return "DRM_FORMAT_FLEX_IMPLEMENTATION_DEFINED";
+ 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_YVU420_ANDROID:
+ 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<uint32_t>(format));
+}
+
+std::string getUsageString(hidl_bitfield<BufferUsage> bufferUsage) {
+ using Underlying = typename std::underlying_type<BufferUsage>::type;
+
+ Underlying usage = static_cast<Underlying>(bufferUsage);
+
+ std::vector<std::string> usages;
+ if (usage & BufferUsage::CAMERA_INPUT) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CAMERA_INPUT);
+ usages.push_back("BufferUsage::CAMERA_INPUT");
+ }
+ if (usage & BufferUsage::CAMERA_OUTPUT) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CAMERA_OUTPUT);
+ usages.push_back("BufferUsage::CAMERA_OUTPUT");
+ }
+ if (usage & BufferUsage::COMPOSER_CURSOR) {
+ usage &= ~static_cast<Underlying>(BufferUsage::COMPOSER_CURSOR);
+ usages.push_back("BufferUsage::COMPOSER_CURSOR");
+ }
+ if (usage & BufferUsage::COMPOSER_OVERLAY) {
+ usage &= ~static_cast<Underlying>(BufferUsage::COMPOSER_OVERLAY);
+ usages.push_back("BufferUsage::COMPOSER_OVERLAY");
+ }
+ if (usage & BufferUsage::CPU_READ_OFTEN) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CPU_READ_OFTEN);
+ usages.push_back("BufferUsage::CPU_READ_OFTEN");
+ }
+ if (usage & BufferUsage::CPU_READ_NEVER) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CPU_READ_NEVER);
+ usages.push_back("BufferUsage::CPU_READ_NEVER");
+ }
+ if (usage & BufferUsage::CPU_READ_RARELY) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CPU_READ_RARELY);
+ usages.push_back("BufferUsage::CPU_READ_RARELY");
+ }
+ if (usage & BufferUsage::CPU_WRITE_NEVER) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CPU_WRITE_NEVER);
+ usages.push_back("BufferUsage::CPU_WRITE_NEVER");
+ }
+ if (usage & BufferUsage::CPU_WRITE_OFTEN) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CPU_WRITE_OFTEN);
+ usages.push_back("BufferUsage::CPU_WRITE_OFTEN");
+ }
+ if (usage & BufferUsage::CPU_WRITE_RARELY) {
+ usage &= ~static_cast<Underlying>(BufferUsage::CPU_WRITE_RARELY);
+ usages.push_back("BufferUsage::CPU_WRITE_RARELY");
+ }
+ if (usage & BufferUsage::GPU_RENDER_TARGET) {
+ usage &= ~static_cast<Underlying>(BufferUsage::GPU_RENDER_TARGET);
+ usages.push_back("BufferUsage::GPU_RENDER_TARGET");
+ }
+ if (usage & BufferUsage::GPU_TEXTURE) {
+ usage &= ~static_cast<Underlying>(BufferUsage::GPU_TEXTURE);
+ usages.push_back("BufferUsage::GPU_TEXTURE");
+ }
+ if (usage & BufferUsage::PROTECTED) {
+ usage &= ~static_cast<Underlying>(BufferUsage::PROTECTED);
+ usages.push_back("BufferUsage::PROTECTED");
+ }
+ if (usage & BufferUsage::RENDERSCRIPT) {
+ usage &= ~static_cast<Underlying>(BufferUsage::RENDERSCRIPT);
+ usages.push_back("BufferUsage::RENDERSCRIPT");
+ }
+ if (usage & BufferUsage::VIDEO_DECODER) {
+ usage &= ~static_cast<Underlying>(BufferUsage::VIDEO_DECODER);
+ usages.push_back("BufferUsage::VIDEO_DECODER");
+ }
+ if (usage & BufferUsage::VIDEO_ENCODER) {
+ usage &= ~static_cast<Underlying>(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 <system/graphics.h> 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<uint64_t>(BufferUsage::CPU_READ_RARELY)) {
+ bufferUsage |= BO_USE_SW_READ_RARELY;
+ }
+ if ((grallocUsage & BufferUsage::CPU_READ_MASK) ==
+ static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN)) {
+ bufferUsage |= BO_USE_SW_READ_OFTEN;
+ }
+ if ((grallocUsage & BufferUsage::CPU_WRITE_MASK) ==
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY)) {
+ bufferUsage |= BO_USE_SW_WRITE_RARELY;
+ }
+ if ((grallocUsage & BufferUsage::CPU_WRITE_MASK) ==
+ static_cast<uint64_t>(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 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 convertToCrosDescriptor(const BufferDescriptorInfo& descriptor,
+ struct cros_gralloc_buffer_descriptor* outCrosDescriptor) {
+ outCrosDescriptor->width = descriptor.width;
+ outCrosDescriptor->height = descriptor.height;
+ outCrosDescriptor->droid_format = static_cast<int32_t>(descriptor.format);
+ outCrosDescriptor->droid_usage = descriptor.usage;
+ outCrosDescriptor->reserved_region_size = 0;
+
+ if (convertToDrmFormat(descriptor.format, &outCrosDescriptor->drm_format)) {
+ std::string pixelFormatString = getPixelFormatString(descriptor.format);
+ drv_log("Failed to convert descriptor. Unsupported format %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 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;
+}
+
+std::optional<BufferDescriptorInfo> decodeBufferDescriptorInfo(const hidl_vec<uint32_t>& encoded) {
+ if (encoded.size() != 5) {
+ drv_log("Failed to decodeBufferDescriptorInfo. Invalid size: %d.\n", encoded.size());
+ return {};
+ }
+
+ BufferDescriptorInfo descriptor;
+ descriptor.width = encoded[0];
+ descriptor.height = encoded[1];
+ descriptor.layerCount = encoded[2];
+ descriptor.format = static_cast<PixelFormat>(encoded[3]);
+ descriptor.usage = encoded[4];
+ return std::move(descriptor);
+}
+
+std::optional<hidl_vec<uint32_t>> encodeBufferDescriptorInfo(const BufferDescriptorInfo& info) {
+ hidl_vec<uint32_t> encoded;
+ encoded.resize(5);
+ encoded[0] = info.width;
+ encoded[1] = info.height;
+ encoded[2] = info.layerCount;
+ encoded[3] = static_cast<uint32_t>(info.format);
+ encoded[4] = info.usage & std::numeric_limits<uint32_t>::max();
+ return std::move(encoded);
+}
\ No newline at end of file
diff --git a/cros_gralloc/gralloc3/CrosGralloc3Utils.h b/cros_gralloc/gralloc3/CrosGralloc3Utils.h
new file mode 100644
index 0000000..ca09404
--- /dev/null
+++ b/cros_gralloc/gralloc3/CrosGralloc3Utils.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 <optional>
+#include <string>
+#include <vector>
+
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.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<android::hardware::graphics::common::V1_2::BufferUsage>
+ usage);
+
+int convertToDrmFormat(android::hardware::graphics::common::V1_2::PixelFormat format,
+ uint32_t* outDrmFormat);
+
+int convertToBufferUsage(uint64_t grallocUsage, uint64_t* outBufferUsage);
+
+int convertToMapUsage(uint64_t grallocUsage, uint32_t* outMapUsage);
+
+int convertToCrosDescriptor(
+ const android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo& descriptor,
+ struct cros_gralloc_buffer_descriptor* outCrosDescriptor);
+
+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);
+
+std::optional<android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo>
+decodeBufferDescriptorInfo(const android::hardware::hidl_vec<uint32_t>& encoded);
+
+std::optional<android::hardware::hidl_vec<uint32_t>> encodeBufferDescriptorInfo(
+ const android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo& info);
diff --git a/cros_gralloc/gralloc3/android.hardware.graphics.allocator@3.0-service.minigbm.rc b/cros_gralloc/gralloc3/android.hardware.graphics.allocator@3.0-service.minigbm.rc
new file mode 100644
index 0000000..7377cee
--- /dev/null
+++ b/cros_gralloc/gralloc3/android.hardware.graphics.allocator@3.0-service.minigbm.rc
@@ -0,0 +1,14 @@
+#
+# 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.
+#
+
+service vendor.graphics.allocator-3-0 /vendor/bin/hw/android.hardware.graphics.allocator@3.0-service.minigbm
+ interface android.hardware.graphics.allocator@3.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 @@
#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 @@
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 @@
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_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 <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <xf86drm.h>
#include "drv_priv.h"
@@ -92,6 +94,9 @@
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 @@
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 @@
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 1f4572c..7f4a63f 100644
--- a/virgl_hw.h
+++ b/virgl_hw.h
@@ -69,7 +69,7 @@
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 d510b43..4e83366 100644
--- a/virtio_gpu.c
+++ b/virtio_gpu.c
@@ -4,6 +4,7 @@
* found in the LICENSE file.
*/
+#include <assert.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
@@ -50,21 +51,27 @@
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 @@
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 @@
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 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 @@
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 @@
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);
@@ -214,11 +458,30 @@
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
@@ -308,26 +571,39 @@
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,
@@ -354,17 +630,39 @@
&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_ABGR8888, &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_XBGR8888, &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_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_R16, &LINEAR_METADATA,
+ BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER);
drv_modify_combination(drv, DRM_FORMAT_R8, &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);
+ drv_modify_combination(drv, DRM_FORMAT_YVU420_ANDROID, &LINEAR_METADATA,
+ BO_USE_CAMERA_READ | BO_USE_CAMERA_WRITE | BO_USE_HW_VIDEO_DECODER |
+ BO_USE_HW_VIDEO_ENCODER);
return drv_modify_linear_combinations(drv);
}
@@ -403,8 +701,11 @@
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;
@@ -416,11 +717,6 @@
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 (mapping->rect.x || mapping->rect.y) {
/*
@@ -435,20 +731,42 @@
}
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
@@ -468,8 +786,11 @@
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;
@@ -479,11 +800,6 @@
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 (mapping->rect.x || mapping->rect.y) {
/*
@@ -500,12 +816,34 @@
// 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
@@ -528,7 +866,6 @@
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. */
@@ -544,7 +881,7 @@
if (features[feat_3d].enabled)
return DRM_FORMAT_NV12;
else
- return DRM_FORMAT_YVU420;
+ return DRM_FORMAT_YVU420_ANDROID;
default:
return format;
}