From dd22cc0b8ab8b355c4463e5fe6c94d0d38cb4a65 Mon Sep 17 00:00:00 2001 From: Ryan Neph Date: Tue, 31 Oct 2023 14:14:32 -0700 Subject: [PATCH] vm_tools: sommelier: refactor format metadata helpers Unify format metadata helpers around a single format table so it is clear which formats are supported, and that all metadata is available. Callers of any format helper are expected to first ensure that a format is available by calling `sl_(shm|drm)_format_is_supported(format)`. BUG=b:234899270 TEST=vkcube in VM Change-Id: I75bb39c26eb6cefb4cd6943a4cc395af4c8c3eb7 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/5005506 Tested-by: Ryan Neph Commit-Queue: Ryan Neph Reviewed-by: Chloe Pelling --- BUILD.gn | 1 + compositor/sommelier-compositor.cc | 8 +- compositor/sommelier-formats.cc | 156 +++++++++++++++++++++++++++ compositor/sommelier-formats.h | 32 ++++++ compositor/sommelier-linux-dmabuf.cc | 10 +- compositor/sommelier-shm.cc | 107 ++---------------- meson.build | 1 + sommelier-xshape.cc | 8 +- sommelier.cc | 38 ------- sommelier.h | 7 -- 10 files changed, 212 insertions(+), 156 deletions(-) create mode 100644 compositor/sommelier-formats.cc create mode 100644 compositor/sommelier-formats.h diff --git a/BUILD.gn b/BUILD.gn index c8bba34..25c46dc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -104,6 +104,7 @@ static_library("libsommelier") { "compositor/sommelier-compositor.cc", "compositor/sommelier-dmabuf-sync.cc", "compositor/sommelier-drm.cc", + "compositor/sommelier-formats.cc", "compositor/sommelier-linux-dmabuf.cc", "compositor/sommelier-mmap.cc", "compositor/sommelier-shm.cc", diff --git a/compositor/sommelier-compositor.cc b/compositor/sommelier-compositor.cc index 9ee315d..01ecedc 100644 --- a/compositor/sommelier-compositor.cc +++ b/compositor/sommelier-compositor.cc @@ -8,6 +8,7 @@ #include "../sommelier-transform.h" // NOLINT(build/include_directory) #include "../sommelier-xshape.h" // NOLINT(build/include_directory) #include "sommelier-dmabuf-sync.h" // NOLINT(build/include_directory) +#include "sommelier-formats.h" // NOLINT(build/include_directory) #include #include @@ -158,6 +159,7 @@ static void sl_host_surface_attach(struct wl_client* client, // Transfer the flag and shape data over to the surface // if we are working on a shaped window if (window_shaped) { + assert(sl_shm_format_is_supported(host_buffer->shm_format)); host->contents_shaped = true; pixman_region32_copy(&host->contents_shape, &window->shape_rectangles); } else { @@ -196,8 +198,8 @@ static void sl_host_surface_attach(struct wl_client* client, size_t height = host_buffer->height; uint32_t shm_format = window_shaped ? WL_SHM_FORMAT_ARGB8888 : host_buffer->shm_format; - size_t bpp = sl_shm_bpp_for_shm_format(shm_format); - size_t num_planes = sl_shm_num_planes_for_shm_format(shm_format); + size_t bpp = sl_shm_format_bpp(shm_format); + size_t num_planes = sl_shm_format_num_planes(shm_format); host->current_buffer = new sl_output_buffer(); wl_list_insert(&host->released_buffers, &host->current_buffer->link); @@ -230,7 +232,7 @@ static void sl_host_surface_attach(struct wl_client* client, create_info.width = static_cast<__u32>(width); create_info.height = static_cast<__u32>(height); - create_info.drm_format = sl_drm_format_for_shm_format(shm_format); + create_info.drm_format = sl_shm_format_to_drm_format(shm_format); rv = host->ctx->channel->allocate(create_info, create_output); if (rv) { diff --git a/compositor/sommelier-formats.cc b/compositor/sommelier-formats.cc new file mode 100644 index 0000000..bb7da1d --- /dev/null +++ b/compositor/sommelier-formats.cc @@ -0,0 +1,156 @@ +// Copyright 2023 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "../sommelier.h" // NOLINT(build/include_directory) +#include "sommelier-formats.h" // NOLINT(build/include_directory) + +#include +#include +#include + +size_t (*plane_y_subsampling_func)(size_t plane); +int (*plane_offset_func)(size_t plane); + +struct sl_format_metadata { + uint32_t drm_format; + uint32_t shm_format; + + size_t bpp; + uint32_t num_planes; + + size_t plane_y_subsampling; + size_t (*plane_y_subsampling_func)(size_t plane); + + int plane_offset; + int (*plane_offset_func)(size_t plane, size_t height, size_t stride); +}; + +static size_t nv12_plane_y_subsampling(size_t plane) { + assert(plane < 2); + return plane == 0 ? 1 : 2; +} + +static int nv12_plane_offset(size_t plane, size_t height, size_t stride) { + const size_t offset[] = {0, 1}; + assert(plane < ARRAY_SIZE(offset)); + return offset[plane] * height * stride; +} + +#define SINGLE_PLANE_FORMAT(format_suffix, _bpp) \ + { \ + .drm_format = DRM_FORMAT_##format_suffix, \ + .shm_format = WL_SHM_FORMAT_##format_suffix, .bpp = _bpp, .num_planes = 1, \ + .plane_y_subsampling = 1, .plane_offset = 0, \ + } + +static struct sl_format_metadata* last_accessed_format = nullptr; +static struct sl_format_metadata format_table[] = { + { + .drm_format = DRM_FORMAT_NV12, + .shm_format = WL_SHM_FORMAT_NV12, + .bpp = 1, + .num_planes = 2, + .plane_y_subsampling_func = nv12_plane_y_subsampling, + .plane_offset_func = nv12_plane_offset, + }, + SINGLE_PLANE_FORMAT(RGB565, 2), + SINGLE_PLANE_FORMAT(XRGB8888, 4), + SINGLE_PLANE_FORMAT(ARGB8888, 4), + SINGLE_PLANE_FORMAT(XBGR8888, 4), + SINGLE_PLANE_FORMAT(ABGR8888, 4), +}; + +static struct sl_format_metadata* get_metadata_for_format(uint32_t format, + bool is_drm_format) { + // format is a wl_shm::format if is_drm_format == false + // is a drm fourcc format otherwise + uint32_t test_format; + + if (last_accessed_format) { + test_format = is_drm_format ? last_accessed_format->drm_format + : last_accessed_format->shm_format; + if (format == test_format) + return last_accessed_format; + } + + for (auto& meta : format_table) { + uint32_t test_format = is_drm_format ? meta.drm_format : meta.shm_format; + if (format == test_format) { + last_accessed_format = &meta; + return &meta; + } + } + + return nullptr; +} + +bool sl_drm_format_is_supported(uint32_t format) { + return !!get_metadata_for_format(format, /*is_drm_format=*/true); +} + +bool sl_shm_format_is_supported(uint32_t format) { + return !!get_metadata_for_format(format, /*is_drm_format=*/false); +} + +uint32_t sl_shm_format_from_drm_format(uint32_t drm_format) { + struct sl_format_metadata* meta = get_metadata_for_format(drm_format, true); + assert(meta); + return meta->shm_format; +} + +uint32_t sl_shm_format_to_drm_format(uint32_t shm_format) { + struct sl_format_metadata* meta = get_metadata_for_format(shm_format, false); + assert(meta); + return meta->drm_format; +} + +size_t sl_shm_format_bpp(uint32_t format) { + struct sl_format_metadata* meta = get_metadata_for_format(format, false); + assert(meta); + return meta->bpp; +} + +size_t sl_shm_format_num_planes(uint32_t format) { + struct sl_format_metadata* meta = get_metadata_for_format(format, false); + assert(meta); + return meta->num_planes; +} + +size_t sl_shm_format_plane_y_subsampling(uint32_t format, size_t plane) { + struct sl_format_metadata* meta = get_metadata_for_format(format, false); + assert(meta); + return meta->plane_y_subsampling_func ? meta->plane_y_subsampling_func(plane) + : meta->plane_y_subsampling; +} + +int sl_shm_format_plane_offset(uint32_t format, + size_t plane, + size_t height, + size_t stride) { + struct sl_format_metadata* meta = get_metadata_for_format(format, false); + assert(meta); + return meta->plane_offset_func + ? meta->plane_offset_func(plane, height, stride) + : meta->plane_offset; +} + +static size_t sl_shm_format_plane_size(uint32_t format, + size_t plane, + size_t height, + size_t stride) { + return height / sl_shm_format_plane_y_subsampling(format, plane) * stride; +} + +size_t sl_shm_format_size(uint32_t format, size_t height, size_t stride) { + size_t i, num_planes = sl_shm_format_num_planes(format); + size_t total_size = 0; + + for (i = 0; i < num_planes; ++i) { + size_t size = sl_shm_format_plane_size(format, i, height, stride); + size_t offset = sl_shm_format_plane_offset(format, i, height, stride); + total_size = MAX(total_size, size + offset); + } + + return total_size; +} diff --git a/compositor/sommelier-formats.h b/compositor/sommelier-formats.h new file mode 100644 index 0000000..34a6944 --- /dev/null +++ b/compositor/sommelier-formats.h @@ -0,0 +1,32 @@ +// Copyright 2023 The ChromiumOS Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef VM_TOOLS_SOMMELIER_COMPOSITOR_SOMMELIER_FORMATS_H_ +#define VM_TOOLS_SOMMELIER_COMPOSITOR_SOMMELIER_FORMATS_H_ + +#include +#include + +bool sl_drm_format_is_supported(uint32_t format); + +bool sl_shm_format_is_supported(uint32_t format); + +uint32_t sl_shm_format_from_drm_format(uint32_t drm_format); + +uint32_t sl_shm_format_to_drm_format(uint32_t shm_format); + +size_t sl_shm_format_bpp(uint32_t format); + +size_t sl_shm_format_num_planes(uint32_t format); + +size_t sl_shm_format_plane_y_subsampling(uint32_t format, size_t plane); + +int sl_shm_format_plane_offset(uint32_t format, + size_t plane, + size_t height, + size_t stride); + +size_t sl_shm_format_size(uint32_t format, size_t height, size_t stride); + +#endif // VM_TOOLS_SOMMELIER_COMPOSITOR_SOMMELIER_FORMATS_H_ diff --git a/compositor/sommelier-linux-dmabuf.cc b/compositor/sommelier-linux-dmabuf.cc index 005164f..df135a7 100644 --- a/compositor/sommelier-linux-dmabuf.cc +++ b/compositor/sommelier-linux-dmabuf.cc @@ -8,6 +8,7 @@ #include "../sommelier.h" // NOLINT(build/include_directory) #include "../virtualization/linux-headers/virtgpu_drm.h" // NOLINT(build/include_directory) #include "sommelier-dmabuf-sync.h" // NOLINT(build/include_directory) +#include "sommelier-formats.h" // NOLINT(build/include_directory) #include "sommelier-linux-dmabuf.h" // NOLINT(build/include_directory) #include "linux-dmabuf-unstable-v1-client-protocol.h" // NOLINT(build/include_directory) @@ -25,7 +26,8 @@ struct sl_host_buffer* sl_linux_dmabuf_create_host_buffer( if (create_info->is_virtgpu_buffer) { host_buffer->sync_point = sl_sync_point_create(create_info->dmabuf_fd); host_buffer->sync_point->sync = sl_dmabuf_sync; - host_buffer->shm_format = sl_shm_format_for_drm_format(create_info->format); + host_buffer->shm_format = + sl_shm_format_from_drm_format(create_info->format); // Create our DRM PRIME mmap container // This is simply a container that records necessary information @@ -40,11 +42,11 @@ struct sl_host_buffer* sl_linux_dmabuf_create_host_buffer( // We are also checking for a single plane format as this container // is currently only defined for single plane format buffers. - if (sl_shm_num_planes_for_shm_format(host_buffer->shm_format) == 1) { + if (sl_shm_format_num_planes(host_buffer->shm_format) == 1) { host_buffer->shm_mmap = sl_drm_prime_mmap_create( ctx->gbm, create_info->dmabuf_fd, - sl_shm_bpp_for_shm_format(host_buffer->shm_format), - sl_shm_num_planes_for_shm_format(host_buffer->shm_format), + sl_shm_format_bpp(host_buffer->shm_format), + sl_shm_format_num_planes(host_buffer->shm_format), create_info->stride, create_info->width, create_info->height, create_info->format); diff --git a/compositor/sommelier-shm.cc b/compositor/sommelier-shm.cc index fd9f492..17633a7 100644 --- a/compositor/sommelier-shm.cc +++ b/compositor/sommelier-shm.cc @@ -5,6 +5,7 @@ #include "../sommelier.h" // NOLINT(build/include_directory) #include "../sommelier-tracing.h" // NOLINT(build/include_directory) #include "../sommelier-util.h" // NOLINT(build/include_directory) +#include "sommelier-formats.h" // NOLINT(build/include_directory) #include #include @@ -28,101 +29,6 @@ struct sl_host_shm { struct zwp_linux_dmabuf_v1* linux_dmabuf_proxy; }; -size_t sl_shm_bpp_for_shm_format(uint32_t format) { - switch (format) { - case WL_SHM_FORMAT_NV12: - return 1; - case WL_SHM_FORMAT_RGB565: - return 2; - case WL_SHM_FORMAT_ARGB8888: - case WL_SHM_FORMAT_ABGR8888: - case WL_SHM_FORMAT_XRGB8888: - case WL_SHM_FORMAT_XBGR8888: - return 4; - } - assert(0); - return 0; -} - -size_t sl_shm_num_planes_for_shm_format(uint32_t format) { - switch (format) { - case WL_SHM_FORMAT_NV12: - return 2; - case WL_SHM_FORMAT_RGB565: - case WL_SHM_FORMAT_ARGB8888: - case WL_SHM_FORMAT_ABGR8888: - case WL_SHM_FORMAT_XRGB8888: - case WL_SHM_FORMAT_XBGR8888: - return 1; - } - assert(0); - return 0; -} - -static size_t sl_y_subsampling_for_shm_format_plane(uint32_t format, - size_t plane) { - switch (format) { - case WL_SHM_FORMAT_NV12: { - const size_t subsampling[] = {1, 2}; - - assert(plane < ARRAY_SIZE(subsampling)); - return subsampling[plane]; - } - case WL_SHM_FORMAT_RGB565: - case WL_SHM_FORMAT_ARGB8888: - case WL_SHM_FORMAT_ABGR8888: - case WL_SHM_FORMAT_XRGB8888: - case WL_SHM_FORMAT_XBGR8888: - return 1; - } - assert(0); - return 0; -} - -static int sl_offset_for_shm_format_plane(uint32_t format, - size_t height, - size_t stride, - size_t plane) { - switch (format) { - case WL_SHM_FORMAT_NV12: { - const size_t offset[] = {0, 1}; - - assert(plane < ARRAY_SIZE(offset)); - return offset[plane] * height * stride; - } - case WL_SHM_FORMAT_RGB565: - case WL_SHM_FORMAT_ARGB8888: - case WL_SHM_FORMAT_ABGR8888: - case WL_SHM_FORMAT_XRGB8888: - case WL_SHM_FORMAT_XBGR8888: - return 0; - } - assert(0); - return 0; -} - -static size_t sl_size_for_shm_format_plane(uint32_t format, - size_t height, - size_t stride, - size_t plane) { - return height / sl_y_subsampling_for_shm_format_plane(format, plane) * stride; -} - -static size_t sl_size_for_shm_format(uint32_t format, - size_t height, - size_t stride) { - size_t i, num_planes = sl_shm_num_planes_for_shm_format(format); - size_t total_size = 0; - - for (i = 0; i < num_planes; ++i) { - size_t size = sl_size_for_shm_format_plane(format, height, stride, i); - size_t offset = sl_offset_for_shm_format_plane(format, height, stride, i); - total_size = MAX(total_size, size + offset); - } - - return total_size; -} - static void sl_host_shm_pool_create_host_buffer(struct wl_client* client, struct wl_resource* resource, uint32_t id, @@ -149,12 +55,11 @@ static void sl_host_shm_pool_create_host_buffer(struct wl_client* client, host_buffer->shm_format = format; host_buffer->shm_mmap = sl_mmap_create( - host->fd, sl_size_for_shm_format(format, height, stride), - sl_shm_bpp_for_shm_format(format), - sl_shm_num_planes_for_shm_format(format), offset, stride, - offset + sl_offset_for_shm_format_plane(format, height, stride, 1), - stride, sl_y_subsampling_for_shm_format_plane(format, 0), - sl_y_subsampling_for_shm_format_plane(format, 1)); + host->fd, sl_shm_format_size(format, height, stride), + sl_shm_format_bpp(format), sl_shm_format_num_planes(format), offset, + stride, offset + sl_shm_format_plane_offset(format, 1, height, stride), + stride, sl_shm_format_plane_y_subsampling(format, 0), + sl_shm_format_plane_y_subsampling(format, 1)); // In the case of mmaps created from the client buffer, we want to be able // to close the FD when the client releases the shm pool (i.e. when it's // done transferring) as opposed to when the pool is freed (i.e. when we're diff --git a/meson.build b/meson.build index 2f71700..aae0a88 100644 --- a/meson.build +++ b/meson.build @@ -190,6 +190,7 @@ libsommelier = static_library('sommelier', 'compositor/sommelier-compositor.cc', 'compositor/sommelier-dmabuf-sync.cc', 'compositor/sommelier-drm.cc', + 'compositor/sommelier-formats.cc', 'compositor/sommelier-linux-dmabuf.cc', 'compositor/sommelier-mmap.cc', 'compositor/sommelier-shm.cc', diff --git a/sommelier-xshape.cc b/sommelier-xshape.cc index 52df4e7..f780318 100644 --- a/sommelier-xshape.cc +++ b/sommelier-xshape.cc @@ -5,9 +5,10 @@ #include #include -#include "sommelier.h" // NOLINT(build/include_directory) -#include "sommelier-tracing.h" // NOLINT(build/include_directory) -#include "sommelier-xshape.h" // NOLINT(build/include_directory) +#include "compositor/sommelier-formats.h" // NOLINT(build/include_directory) +#include "sommelier.h" // NOLINT(build/include_directory) +#include "sommelier-tracing.h" // NOLINT(build/include_directory) +#include "sommelier-xshape.h" // NOLINT(build/include_directory) static void sl_clear_shape_region(sl_window* window) { window->shaped = false; @@ -101,6 +102,7 @@ void sl_shape_query(struct sl_context* ctx, xcb_window_t xwindow) { } pixman_format_code_t sl_pixman_format_for_shm_format(uint32_t shm_format) { + assert(sl_shm_format_is_supported(shm_format)); pixman_format_code_t fmt = PIXMAN_a1; switch (shm_format) { diff --git a/sommelier.cc b/sommelier.cc index b90acac..91580f6 100644 --- a/sommelier.cc +++ b/sommelier.cc @@ -107,44 +107,6 @@ int sl_open_wayland_socket(const char* socket_name, int* lock_fd, int* sock_fd); -int sl_shm_format_for_drm_format(uint32_t drm_format) { - switch (drm_format) { - case WL_DRM_FORMAT_NV12: - return WL_SHM_FORMAT_NV12; - case WL_DRM_FORMAT_RGB565: - return WL_SHM_FORMAT_RGB565; - case WL_DRM_FORMAT_ARGB8888: - return WL_SHM_FORMAT_ARGB8888; - case WL_DRM_FORMAT_ABGR8888: - return WL_SHM_FORMAT_ABGR8888; - case WL_DRM_FORMAT_XRGB8888: - return WL_SHM_FORMAT_XRGB8888; - case WL_DRM_FORMAT_XBGR8888: - return WL_SHM_FORMAT_XBGR8888; - } - assert(0); - return 0; -} - -uint32_t sl_drm_format_for_shm_format(int format) { - switch (format) { - case WL_SHM_FORMAT_NV12: - return WL_DRM_FORMAT_NV12; - case WL_SHM_FORMAT_RGB565: - return WL_DRM_FORMAT_RGB565; - case WL_SHM_FORMAT_ARGB8888: - return WL_DRM_FORMAT_ARGB8888; - case WL_SHM_FORMAT_ABGR8888: - return WL_DRM_FORMAT_ABGR8888; - case WL_SHM_FORMAT_XRGB8888: - return WL_DRM_FORMAT_XRGB8888; - case WL_SHM_FORMAT_XBGR8888: - return WL_DRM_FORMAT_XBGR8888; - } - assert(0); - return 0; -} - const char* net_wm_state_to_string(int i) { switch (i) { case NET_WM_STATE_REMOVE: diff --git a/sommelier.h b/sommelier.h index fb17e30..4b08789 100644 --- a/sommelier.h +++ b/sommelier.h @@ -522,10 +522,6 @@ void sl_compositor_init_context(struct sl_context* ctx, uint32_t id, uint32_t version); -size_t sl_shm_bpp_for_shm_format(uint32_t format); - -size_t sl_shm_num_planes_for_shm_format(uint32_t format); - struct sl_global* sl_shm_global_create(struct sl_context* ctx); struct sl_global* sl_subcompositor_global_create(struct sl_context* ctx); @@ -632,9 +628,6 @@ void sl_handle_client_message(struct sl_context* ctx, xcb_client_message_event_t* event); void sl_handle_focus_in(struct sl_context* ctx, xcb_focus_in_event_t* event); -uint32_t sl_drm_format_for_shm_format(int format); -int sl_shm_format_for_drm_format(uint32_t drm_format); - #ifdef GAMEPAD_SUPPORT void sl_gaming_seat_add_listener(struct sl_context* ctx); #endif