Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit

Permalink
vm_tools: sommelier: refactor format metadata helpers
Browse files Browse the repository at this point in the history
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 <[email protected]>
Commit-Queue: Ryan Neph <[email protected]>
Reviewed-by: Chloe Pelling <[email protected]>
  • Loading branch information
Ryan Neph authored and Chromeos LUCI committed Nov 14, 2023
1 parent 9833ea0 commit dd22cc0
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 156 deletions.
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
8 changes: 5 additions & 3 deletions compositor/sommelier-compositor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <assert.h>
#include <errno.h>
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
156 changes: 156 additions & 0 deletions compositor/sommelier-formats.cc
Original file line number Diff line number Diff line change
@@ -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 <assert.h>
#include <libdrm/drm_fourcc.h>
#include <wayland-client.h>

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;
}
32 changes: 32 additions & 0 deletions compositor/sommelier-formats.h
Original file line number Diff line number Diff line change
@@ -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 <stddef.h>
#include <stdint.h>

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_
10 changes: 6 additions & 4 deletions compositor/sommelier-linux-dmabuf.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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);

Expand Down
107 changes: 6 additions & 101 deletions compositor/sommelier-shm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 <assert.h>
#include <stdlib.h>
Expand All @@ -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,
Expand All @@ -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
Expand Down
Loading

0 comments on commit dd22cc0

Please sign in to comment.