Commit 3fa9628b authored by Paulo Warren's avatar Paulo Warren Committed by Commit Bot

exo: add a memfd path to wayland base client

This CL incorporates new behavior into the wayland base client for testing udmabuf_create on the server side. If memfd_create succeeds, the client
allocates a memory region using memfd_create instead of the chrome
SharedMemoryRegion class. The returned buffer is page aligned, and sealed
with F_SEAL_SHRINK due to the requirements of udmabuf_create on the server
side.


TEST=autoninja -C out_atlas/Release/ wayland_simple_client then scp the
client to an atlas chromebook. To run add --use-dmabuf flag.
BUG=None

Change-Id: I27f6f04c1d577e172bbb68bd09718e6f0d6d65f6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2003267Reviewed-by: default avatarDaniele Castagna <dcastagna@chromium.org>
Reviewed-by: default avatarAndres Calderon Jaramillo <andrescj@chromium.org>
Commit-Queue: Paulo Warren <pwarren@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738575}
parent 3ece94e3
// Copyright 2017 The Chromium Authors. All rights reserved. // Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
//
#define _GNU_SOURCE
#include "components/exo/wayland/clients/client_base.h" #include "components/exo/wayland/clients/client_base.h"
...@@ -11,6 +14,8 @@ ...@@ -11,6 +14,8 @@
#include <linux-dmabuf-unstable-v1-client-protocol.h> #include <linux-dmabuf-unstable-v1-client-protocol.h>
#include <linux-explicit-synchronization-unstable-v1-client-protocol.h> #include <linux-explicit-synchronization-unstable-v1-client-protocol.h>
#include <presentation-time-client-protocol.h> #include <presentation-time-client-protocol.h>
#include <sys/mman.h>
#include <unistd.h>
#include <wayland-client-core.h> #include <wayland-client-core.h>
#include <wayland-client-protocol.h> #include <wayland-client-protocol.h>
...@@ -18,12 +23,15 @@ ...@@ -18,12 +23,15 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "base/bits.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/platform_shared_memory_region.h" #include "base/memory/platform_shared_memory_region.h"
#include "base/memory/unsafe_shared_memory_region.h" #include "base/memory/unsafe_shared_memory_region.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/unguessable_token.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRefCnt.h" #include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkSurface.h" #include "third_party/skia/include/core/SkSurface.h"
...@@ -69,6 +77,9 @@ const char kTransparentBackground[] = "transparent-background"; ...@@ -69,6 +77,9 @@ const char kTransparentBackground[] = "transparent-background";
// Use drm buffer instead of shared memory. // Use drm buffer instead of shared memory.
const char kUseDrm[] = "use-drm"; const char kUseDrm[] = "use-drm";
// Use memfd backed buffer instead of shared memory.
const char kUseMemfd[] = "use-memfd";
// Specifies if client should be fullscreen. // Specifies if client should be fullscreen.
const char kFullscreen[] = "fullscreen"; const char kFullscreen[] = "fullscreen";
...@@ -96,6 +107,15 @@ ClientBase* CastToClientBase(void* data) { ...@@ -96,6 +107,15 @@ ClientBase* CastToClientBase(void* data) {
return static_cast<ClientBase*>(data); return static_cast<ClientBase*>(data);
} }
class MemfdMemoryMapping : public base::SharedMemoryMapping {
public:
MemfdMemoryMapping(void* memory, size_t size)
: base::SharedMemoryMapping(memory,
size,
size /* mapped_size */,
base::UnguessableToken::Create()) {}
};
void RegistryHandler(void* data, void RegistryHandler(void* data,
wl_registry* registry, wl_registry* registry,
uint32_t id, uint32_t id,
...@@ -360,6 +380,8 @@ bool ClientBase::InitParams::FromCommandLine( ...@@ -360,6 +380,8 @@ bool ClientBase::InitParams::FromCommandLine(
if (use_drm) if (use_drm)
use_drm_value = command_line.GetSwitchValueASCII(switches::kUseDrm); use_drm_value = command_line.GetSwitchValueASCII(switches::kUseDrm);
use_memfd = command_line.HasSwitch(switches::kUseMemfd);
fullscreen = command_line.HasSwitch(switches::kFullscreen); fullscreen = command_line.HasSwitch(switches::kFullscreen);
transparent_background = transparent_background =
command_line.HasSwitch(switches::kTransparentBackground); command_line.HasSwitch(switches::kTransparentBackground);
...@@ -544,6 +566,8 @@ bool ClientBase::Init(const InitParams& params) { ...@@ -544,6 +566,8 @@ bool ClientBase::Init(const InitParams& params) {
wl_surface_set_opaque_region(surface_.get(), opaque_region.get()); wl_surface_set_opaque_region(surface_.get(), opaque_region.get());
} }
use_memfd_ = params.use_memfd;
if (params.allocate_buffers_with_output_mode) { if (params.allocate_buffers_with_output_mode) {
static wl_output_listener kOutputListener = { static wl_output_listener kOutputListener = {
[](void* data, struct wl_output* wl_output, int32_t x, int32_t y, [](void* data, struct wl_output* wl_output, int32_t x, int32_t y,
...@@ -756,18 +780,75 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer( ...@@ -756,18 +780,75 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
if (!buffer) { if (!buffer) {
buffer = std::make_unique<Buffer>(); buffer = std::make_unique<Buffer>();
size_t stride = size.width() * kBytesPerPixel; size_t stride = size.width() * kBytesPerPixel;
base::UnsafeSharedMemoryRegion shared_memory_region = size_t length = size.height() * stride;
base::UnsafeSharedMemoryRegion::Create(stride * size.height()); uint8_t* mapped_data;
buffer->shared_memory_mapping = shared_memory_region.Map();
base::subtle::PlatformSharedMemoryRegion platform_shared_memory = if (use_memfd_) {
base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( // udmabuf_create requires a page aligned buffer.
std::move(shared_memory_region)); length = base::bits::Align(length, getpagesize());
int memfd = memfd_create("memfd", MFD_ALLOW_SEALING);
if (memfd < 0) {
PLOG(ERROR) << "memfd_create failed";
return nullptr;
}
// Truncate the chunk of memory to be page aligned so that the server
// has the option of using the shared memory region as a dma-buf through
// udmabuf_create.
int res = HANDLE_EINTR(ftruncate(memfd, length));
if (res < 0) {
PLOG(ERROR) << "ftruncate failed";
return nullptr;
}
// Seal the fd with F_SEAL_SHRINK so that the server has the option of
// using the shared memory region as a dma-buf through udmabuf_create.
if (fcntl(memfd, F_ADD_SEALS, F_SEAL_SHRINK) < 0) {
PLOG(ERROR) << "Failed to seal memfd";
return nullptr;
}
mapped_data = static_cast<uint8_t*>(
mmap(nullptr, length, PROT_WRITE | PROT_READ, MAP_SHARED, memfd, 0));
if (mapped_data == MAP_FAILED) {
PLOG(ERROR) << "Failed to mmap";
return nullptr;
}
buffer->shm_pool.reset(wl_shm_create_pool( buffer->shared_memory_mapping = MemfdMemoryMapping(mapped_data, length);
globals_.shm.get(), platform_shared_memory.GetPlatformHandle().fd, buffer->shm_pool.reset(
buffer->shared_memory_mapping.size())); wl_shm_create_pool(globals_.shm.get(), memfd, length));
close(memfd);
} else {
base::UnsafeSharedMemoryRegion shared_memory_region =
base::UnsafeSharedMemoryRegion::Create(length);
if (!shared_memory_region.IsValid()) {
LOG(ERROR) << "Shared Memory Region is not valid";
return nullptr;
}
base::WritableSharedMemoryMapping map = shared_memory_region.Map();
if (!map.IsValid()) {
LOG(ERROR) << "WritableSharedMemoryMapping is not valid";
return nullptr;
}
mapped_data = map.GetMemoryAs<uint8_t>();
buffer->shared_memory_mapping = std::move(map);
base::subtle::PlatformSharedMemoryRegion platform_shared_memory =
base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
std::move(shared_memory_region));
buffer->shm_pool.reset(wl_shm_create_pool(
globals_.shm.get(), platform_shared_memory.GetPlatformHandle().fd,
buffer->shared_memory_mapping.size()));
}
buffer->buffer.reset(static_cast<wl_buffer*>( buffer->buffer.reset(static_cast<wl_buffer*>(
wl_shm_pool_create_buffer(buffer->shm_pool.get(), 0, size.width(), wl_shm_pool_create_buffer(buffer->shm_pool.get(), 0, size.width(),
...@@ -780,7 +861,7 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer( ...@@ -780,7 +861,7 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateBuffer(
buffer->sk_surface = SkSurface::MakeRasterDirect( buffer->sk_surface = SkSurface::MakeRasterDirect(
SkImageInfo::Make(size.width(), size.height(), kColorType, SkImageInfo::Make(size.width(), size.height(), kColorType,
kOpaque_SkAlphaType), kOpaque_SkAlphaType),
buffer->shared_memory_mapping.GetMemoryAs<uint8_t>(), stride); mapped_data, stride);
DCHECK(buffer->sk_surface); DCHECK(buffer->sk_surface);
} }
...@@ -808,7 +889,9 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateDrmBuffer( ...@@ -808,7 +889,9 @@ std::unique_ptr<ClientBase::Buffer> ClientBase::CreateDrmBuffer(
buffer->params.reset( buffer->params.reset(
zwp_linux_dmabuf_v1_create_params(globals_.linux_dmabuf.get())); zwp_linux_dmabuf_v1_create_params(globals_.linux_dmabuf.get()));
for (size_t i = 0; i < gbm_bo_get_plane_count(buffer->bo.get()); ++i) { for (size_t i = 0;
i < static_cast<size_t>(gbm_bo_get_plane_count(buffer->bo.get()));
++i) {
base::ScopedFD fd(gbm_bo_get_plane_fd(buffer->bo.get(), i)); base::ScopedFD fd(gbm_bo_get_plane_fd(buffer->bo.get(), i));
uint32_t stride = gbm_bo_get_stride_for_plane(buffer->bo.get(), i); uint32_t stride = gbm_bo_get_stride_for_plane(buffer->bo.get(), i);
uint32_t offset = gbm_bo_get_offset(buffer->bo.get(), i); uint32_t offset = gbm_bo_get_offset(buffer->bo.get(), i);
......
...@@ -57,6 +57,7 @@ class ClientBase { ...@@ -57,6 +57,7 @@ class ClientBase {
bool y_invert = false; bool y_invert = false;
bool allocate_buffers_with_output_mode = false; bool allocate_buffers_with_output_mode = false;
bool use_fullscreen_shell = false; bool use_fullscreen_shell = false;
bool use_memfd = false;
bool use_touch = false; bool use_touch = false;
bool use_vulkan = false; bool use_vulkan = false;
}; };
...@@ -103,7 +104,7 @@ class ClientBase { ...@@ -103,7 +104,7 @@ class ClientBase {
#endif // defined(USE_GBM) #endif // defined(USE_GBM)
std::unique_ptr<zwp_linux_buffer_params_v1> params; std::unique_ptr<zwp_linux_buffer_params_v1> params;
std::unique_ptr<wl_shm_pool> shm_pool; std::unique_ptr<wl_shm_pool> shm_pool;
base::WritableSharedMemoryMapping shared_memory_mapping; base::SharedMemoryMapping shared_memory_mapping;
sk_sp<SkSurface> sk_surface; sk_sp<SkSurface> sk_surface;
}; };
...@@ -180,6 +181,7 @@ class ClientBase { ...@@ -180,6 +181,7 @@ class ClientBase {
int transform_ = WL_OUTPUT_TRANSFORM_NORMAL; int transform_ = WL_OUTPUT_TRANSFORM_NORMAL;
gfx::Size surface_size_ = gfx::Size(256, 256); gfx::Size surface_size_ = gfx::Size(256, 256);
bool fullscreen_ = false; bool fullscreen_ = false;
bool use_memfd_ = false;
bool transparent_background_ = false; bool transparent_background_ = false;
bool y_invert_ = false; bool y_invert_ = false;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment