// Copyright 2019 The Chromium 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 "components/exo/wayland/wl_shm.h" #include #include "base/bind.h" #include "components/exo/buffer.h" #include "components/exo/display.h" #include "components/exo/shared_memory.h" #include "components/exo/wayland/server_util.h" namespace exo { namespace wayland { namespace { void buffer_destroy(wl_client* client, wl_resource* resource) { wl_resource_destroy(resource); } const struct wl_buffer_interface buffer_implementation = {buffer_destroy}; void HandleBufferReleaseCallback(wl_resource* resource) { wl_buffer_send_release(resource); wl_client_flush(wl_resource_get_client(resource)); } const struct shm_supported_format { uint32_t shm_format; gfx::BufferFormat buffer_format; } shm_supported_formats[] = { {WL_SHM_FORMAT_XBGR8888, gfx::BufferFormat::RGBX_8888}, {WL_SHM_FORMAT_ABGR8888, gfx::BufferFormat::RGBA_8888}, {WL_SHM_FORMAT_XRGB8888, gfx::BufferFormat::BGRX_8888}, {WL_SHM_FORMAT_ARGB8888, gfx::BufferFormat::BGRA_8888}}; void shm_pool_create_buffer(wl_client* client, wl_resource* resource, uint32_t id, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format) { const auto* supported_format = std::find_if(shm_supported_formats, shm_supported_formats + base::size(shm_supported_formats), [format](const shm_supported_format& supported_format) { return supported_format.shm_format == format; }); if (supported_format == (shm_supported_formats + base::size(shm_supported_formats))) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FORMAT, "invalid format 0x%x", format); return; } if (offset < 0) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FORMAT, "invalid offset %d", offset); return; } std::unique_ptr buffer = GetUserDataAs(resource)->CreateBuffer( gfx::Size(width, height), supported_format->buffer_format, offset, stride); if (!buffer) { wl_resource_post_no_memory(resource); return; } wl_resource* buffer_resource = wl_resource_create(client, &wl_buffer_interface, 1, id); buffer->set_release_callback(base::BindRepeating( &HandleBufferReleaseCallback, base::Unretained(buffer_resource))); SetImplementation(buffer_resource, &buffer_implementation, std::move(buffer)); } void shm_pool_destroy(wl_client* client, wl_resource* resource) { wl_resource_destroy(resource); } void shm_pool_resize(wl_client* client, wl_resource* resource, int32_t size) { auto* shm = GetUserDataAs(resource); if (size < 0 || static_cast(size) < shm->GetSize()) { wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD, "Can't shrink a shm pool."); } if (!shm->Resize(size)) wl_resource_post_no_memory(resource); } const struct wl_shm_pool_interface shm_pool_implementation = { shm_pool_create_buffer, shm_pool_destroy, shm_pool_resize}; void shm_create_pool(wl_client* client, wl_resource* resource, uint32_t id, int fd, int32_t size) { static const auto kMode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe; auto fd_pair = base::subtle::ScopedFDPair(base::ScopedFD(fd), base::ScopedFD() /* readonly_fd */); auto guid = base::UnguessableToken::Create(); auto platform_shared_memory = base::subtle::PlatformSharedMemoryRegion::Take( std::move(fd_pair), kMode, size, guid); std::unique_ptr shared_memory = GetUserDataAs(resource)->CreateSharedMemory( base::UnsafeSharedMemoryRegion::Deserialize( std::move(platform_shared_memory))); if (!shared_memory) { wl_resource_post_no_memory(resource); return; } wl_resource* shm_pool_resource = wl_resource_create(client, &wl_shm_pool_interface, 1, id); SetImplementation(shm_pool_resource, &shm_pool_implementation, std::move(shared_memory)); } const struct wl_shm_interface shm_implementation = {shm_create_pool}; } // namespace void bind_shm(wl_client* client, void* data, uint32_t version, uint32_t id) { wl_resource* resource = wl_resource_create(client, &wl_shm_interface, 1, id); wl_resource_set_implementation(resource, &shm_implementation, data, nullptr); for (const auto& supported_format : shm_supported_formats) wl_shm_send_format(resource, supported_format.shm_format); } } // namespace wayland } // namespace exo