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

Commit

Permalink
vm_tools: sommelier: Add DRM mmap code
Browse files Browse the repository at this point in the history
This patch adds support for mapping a DRM prime buffer within Sommelier.

For the XShape support to work within Sommelier, we will need to read
the image coming in from the guest. The guest can supply an image as a
SHM memory buffer or a DRM buffer. To read the DRM buffer we will need
to map it, which is what this patch enables.

BUG=b:223232234
TEST=Ensured no crashes when using both regular and shaped applications

Change-Id: Id4561db7765845e37ead6496410438b665a7afd1
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/3880724
Reviewed-by: Nic Hollingum <[email protected]>
Commit-Queue: Isaac Bosompem <[email protected]>
Tested-by: Isaac Bosompem <[email protected]>
Reviewed-by: Chia-I Wu <[email protected]>
  • Loading branch information
Isaac Bosompem authored and Chromeos LUCI committed Oct 6, 2022
1 parent 836c972 commit 69675a1
Show file tree
Hide file tree
Showing 9 changed files with 248 additions and 40 deletions.
45 changes: 15 additions & 30 deletions sommelier-compositor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,6 @@ static void sl_virtwl_dmabuf_end_write(int fd, struct sl_context* ctx) {
sl_virtwl_dmabuf_sync(fd, DMA_BUF_SYNC_END | DMA_BUF_SYNC_WRITE, ctx);
}

static 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;
}

static void sl_output_buffer_destroy(struct sl_output_buffer* buffer) {
wl_buffer_destroy(buffer->internal);
sl_mmap_unref(buffer->mmap);
Expand Down Expand Up @@ -160,8 +141,11 @@ static void sl_host_surface_attach(struct wl_client* client,
host->contents_width = host_buffer->width;
host->contents_height = host_buffer->height;
buffer_proxy = host_buffer->proxy;
if (host_buffer->shm_mmap)
host->contents_shm_mmap = sl_mmap_ref(host_buffer->shm_mmap);

if (!host_buffer->is_drm) {
if (host_buffer->shm_mmap)
host->contents_shm_mmap = sl_mmap_ref(host_buffer->shm_mmap);
}
}

if (host->contents_shm_mmap) {
Expand Down Expand Up @@ -233,7 +217,7 @@ static void sl_host_surface_attach(struct wl_client* client,
create_output.strides[1], 0, 0);
size = MAX(size, create_output.offsets[1] +
create_output.offsets[1] * height /
host_buffer->shm_mmap->y_ss[1]);
host->contents_shm_mmap->y_ss[1]);
}
host->current_buffer->internal =
zwp_linux_buffer_params_v1_create_immed(
Expand All @@ -243,12 +227,12 @@ static void sl_host_surface_attach(struct wl_client* client,
host->current_buffer->mmap = sl_mmap_create(
create_output.fd, size, bpp, num_planes, create_output.offsets[0],
create_output.strides[0], create_output.offsets[1],
create_output.strides[1], host_buffer->shm_mmap->y_ss[0],
host_buffer->shm_mmap->y_ss[1]);
create_output.strides[1], host->contents_shm_mmap->y_ss[0],
host->contents_shm_mmap->y_ss[1]);
host->current_buffer->mmap->begin_write = sl_virtwl_dmabuf_begin_write;
host->current_buffer->mmap->end_write = sl_virtwl_dmabuf_end_write;
} else {
size_t size = host_buffer->shm_mmap->size;
size_t size = host->contents_shm_mmap->size;
struct WaylandBufferCreateInfo create_info = {0};
struct WaylandBufferCreateOutput create_output = {0};
struct wl_shm_pool* pool;
Expand All @@ -266,16 +250,17 @@ static void sl_host_surface_attach(struct wl_client* client,
create_output.host_size);

host->current_buffer->internal = wl_shm_pool_create_buffer(
pool, 0, width, height, host_buffer->shm_mmap->stride[0],
pool, 0, width, height, host->contents_shm_mmap->stride[0],
shm_format);
wl_shm_pool_destroy(pool);

host->current_buffer->mmap = sl_mmap_create(
create_output.fd, create_output.host_size, bpp, num_planes, 0,
host_buffer->shm_mmap->stride[0],
host_buffer->shm_mmap->offset[1] - host_buffer->shm_mmap->offset[0],
host_buffer->shm_mmap->stride[1], host_buffer->shm_mmap->y_ss[0],
host_buffer->shm_mmap->y_ss[1]);
host->contents_shm_mmap->stride[0],
host->contents_shm_mmap->offset[1] -
host->contents_shm_mmap->offset[0],
host->contents_shm_mmap->stride[1],
host->contents_shm_mmap->y_ss[0], host->contents_shm_mmap->y_ss[1]);
}

assert(host->current_buffer->internal);
Expand Down
15 changes: 15 additions & 0 deletions sommelier-ctx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,18 @@ bool sl_context_init_wayland_channel(struct sl_context* ctx,
}
return true;
}

sl_window* sl_context_lookup_window_for_surface(struct sl_context* ctx,
wl_resource* resource) {
sl_window* surface_window = NULL;
sl_window* window;

wl_list_for_each(window, &ctx->windows, link) {
if (window->host_surface_id == wl_resource_get_id(resource)) {
surface_window = window;
break;
}
}

return surface_window;
}
3 changes: 3 additions & 0 deletions sommelier-ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,7 @@ bool sl_context_init_wayland_channel(struct sl_context* ctx,
struct wl_event_loop* event_loop,
bool display);

sl_window* sl_context_lookup_window_for_surface(struct sl_context* ctx,
wl_resource* resource);

#endif // VM_TOOLS_SOMMELIER_SOMMELIER_CTX_H_
24 changes: 23 additions & 1 deletion sommelier-drm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,32 @@ static void sl_drm_create_prime_buffer(struct wl_client* client,
sl_create_host_buffer(host->ctx, client, id,
zwp_linux_buffer_params_v1_create_immed(
buffer_params, width, height, format, 0),
width, height);
width, height, /*is_drm=*/true);
if (is_gpu_buffer) {
host_buffer->sync_point = sl_sync_point_create(name);
host_buffer->sync_point->sync = sl_drm_sync;
host_buffer->shm_format = sl_shm_format_for_drm_format(format);

// Create our DRM PRIME mmap container
// This is simply a container that records necessary information
// to map the DRM buffer through the GBM API's.
// The GBM API's may need to perform a rather heavy copy of the
// buffer into memory accessible by the CPU to perform the mapping
// operation.
// For this reason, the GBM mapping API's will not be used until we
// are absolutely certain that the buffers contents need to be
// accessed. This will be done through a call to sl_mmap_begin_access.
//
// 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) {
host_buffer->shm_mmap = sl_drm_prime_mmap_create(
host->ctx->gbm, name,
sl_shm_bpp_for_shm_format(host_buffer->shm_format),
sl_shm_num_planes_for_shm_format(host_buffer->shm_format), stride0,
width, height, format);
}
} else {
close(name);
}
Expand Down
122 changes: 118 additions & 4 deletions sommelier-mmap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ struct sl_mmap* sl_mmap_create(int fd,
map->refcount = 1;
map->fd = fd;
map->size = size;
map->map_type = SL_MMAP_SHM;
map->gbm_map_data = NULL;
map->gbmbo = NULL;
map->num_planes = num_planes;
map->bpp = bpp;
map->offset[0] = offset0;
Expand All @@ -44,18 +47,129 @@ struct sl_mmap* sl_mmap_create(int fd,
return map;
}

struct sl_mmap* sl_drm_prime_mmap_create(gbm_device* device,
int fd,
size_t bpp,
size_t num_planes,
size_t stride,
int32_t width,
int32_t height,
uint32_t drm_format) {
TRACE_EVENT("drm", "sl_drm_mmap_create");
struct sl_mmap* map = static_cast<sl_mmap*>(malloc(sizeof(*map)));
assert(map);
assert(num_planes == 1);

map->refcount = 1;
map->fd = fd;
map->num_planes = num_planes;
map->bpp = bpp;
map->offset[0] = 0;
map->stride[0] = stride;
map->offset[1] = 0;
map->stride[1] = 0;
map->y_ss[0] = 1;
map->y_ss[1] = 1;
map->begin_write = NULL;
map->end_write = NULL;
map->buffer_resource = NULL;
map->map_type = SL_MMAP_DRM_PRIME;
map->gbm_map_data = NULL;
map->addr = NULL;
map->gbmbo = NULL;

// Prefill in the gbm_import_data structure
map->gbm_import_data.fd = fd;
map->gbm_import_data.width = width;
map->gbm_import_data.height = height;
map->gbm_import_data.stride = stride;
map->gbm_import_data.format = drm_format;

// Save the device as we will need it later
map->gbm_device_object = device;
return map;
}

struct sl_mmap* sl_mmap_ref(struct sl_mmap* map) {
TRACE_EVENT("shm", "sl_mmap_ref");
map->refcount++;
return map;
}

bool sl_mmap_begin_access(struct sl_mmap* map) {
uint32_t ret_stride;

// This function is to be used on the DRM PRIME mmap path.
// It is used to ensure we can actually access the resource
// when its contents are needed.
// If we have any other mmap type, we should simply return true
// under the assumption that they do not need to perform this extra
// check
if (map->map_type != SL_MMAP_DRM_PRIME)
return true;

// Attempt to import (and map) the GBM BO
// If we cannot do so, return false so the upper layers
// can respond appropriately.
map->gbmbo = gbm_bo_import(map->gbm_device_object, GBM_BO_IMPORT_FD,
reinterpret_cast<void*>(&map->gbm_import_data),
GBM_BO_USE_LINEAR);
if (!map->gbmbo) {
return false;
}

map->gbm_map_data = NULL;
map->addr = gbm_bo_map(map->gbmbo, 0, 0, map->gbm_import_data.width,
map->gbm_import_data.height, GBM_BO_TRANSFER_READ,
&ret_stride, &map->gbm_map_data);
if (!map->addr) {
gbm_bo_destroy(map->gbmbo);
return false;
}

map->stride[0] = ret_stride;
map->size = ret_stride * map->gbm_import_data.height;

return true;
}

void sl_mmap_end_access(struct sl_mmap* map) {
if (map->map_type != SL_MMAP_DRM_PRIME)
return;

if (map->addr && map->gbm_map_data) {
gbm_bo_unmap(map->gbmbo, map->gbm_map_data);
map->addr = NULL;
map->gbm_map_data = NULL;
}

if (map->gbmbo) {
gbm_bo_destroy(map->gbmbo);
map->gbmbo = NULL;
}
}

void sl_mmap_unref(struct sl_mmap* map) {
TRACE_EVENT("shm", "sl_mmap_unref");
if (map->refcount-- == 1) {
munmap(map->addr, map->size + map->offset[0]);
if (map->fd != -1)
close(map->fd);
free(map);
switch (map->map_type) {
case SL_MMAP_SHM:
munmap(map->addr, map->size + map->offset[0]);
if (map->fd != -1)
close(map->fd);
free(map);
break;

case SL_MMAP_DRM_PRIME:
// Invoke end_access just in case
sl_mmap_end_access(map);
if (map->fd != -1)
close(map->fd);
free(map);
break;

default:
break;
}
}
}
25 changes: 25 additions & 0 deletions sommelier-mmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,24 @@
#ifndef VM_TOOLS_SOMMELIER_SOMMELIER_MMAP_H_
#define VM_TOOLS_SOMMELIER_SOMMELIER_MMAP_H_

#include <gbm.h>
#include <sys/types.h>

typedef void (*sl_begin_end_access_func_t)(int fd, struct sl_context* ctx);

enum slMmapType {
SL_MMAP_NONE, // None
SL_MMAP_SHM, // SHM mmap type
SL_MMAP_DRM_PRIME // DRM PRIME mmap type
};

struct sl_mmap {
int refcount;
int fd;
void* addr;
struct gbm_bo* gbmbo;
void* gbm_map_data;
gbm_device* gbm_device_object;
size_t size;
size_t bpp;
size_t num_planes;
Expand All @@ -21,9 +31,20 @@ struct sl_mmap {
size_t y_ss[2];
sl_begin_end_access_func_t begin_write;
sl_begin_end_access_func_t end_write;
slMmapType map_type;
struct gbm_import_fd_data gbm_import_data;
struct wl_resource* buffer_resource;
};

struct sl_mmap* sl_drm_prime_mmap_create(gbm_device* device,
int fd,
size_t bpp,
size_t num_planes,
size_t stride,
int32_t width,
int32_t height,
uint32_t drm_format);

struct sl_mmap* sl_mmap_create(int fd,
size_t size,
size_t bpp,
Expand All @@ -34,6 +55,10 @@ struct sl_mmap* sl_mmap_create(int fd,
size_t stride1,
size_t y_ss0,
size_t y_ss1);

bool sl_mmap_begin_access(struct sl_mmap* map);
void sl_mmap_end_access(struct sl_mmap* map);

struct sl_mmap* sl_mmap_ref(struct sl_mmap* map);
void sl_mmap_unref(struct sl_mmap* map);

Expand Down
4 changes: 2 additions & 2 deletions sommelier-shm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ static void sl_host_shm_pool_create_host_buffer(struct wl_client* client,
struct sl_host_shm_pool* host =
static_cast<sl_host_shm_pool*>(wl_resource_get_user_data(resource));

struct sl_host_buffer* host_buffer =
sl_create_host_buffer(host->shm->ctx, client, id, NULL, width, height);
struct sl_host_buffer* host_buffer = sl_create_host_buffer(
host->shm->ctx, client, id, NULL, width, height, /*is_drm=*/false);

host_buffer->shm_format = format;
host_buffer->shm_mmap = sl_mmap_create(
Expand Down
Loading

0 comments on commit 69675a1

Please sign in to comment.