| // Copyright 2019 The Chromium Authors |
| // 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 <wayland-server-protocol-core.h> |
| |
| #include <algorithm> |
| |
| #include "base/functional/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" |
| #include "components/viz/common/resources/shared_image_format.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; |
| viz::SharedImageFormat si_format; |
| } shm_supported_formats[] = { |
| {WL_SHM_FORMAT_XBGR8888, viz::SinglePlaneFormat::kRGBX_8888}, |
| {WL_SHM_FORMAT_ABGR8888, viz::SinglePlaneFormat::kRGBA_8888}, |
| {WL_SHM_FORMAT_XRGB8888, viz::SinglePlaneFormat::kBGRX_8888}, |
| {WL_SHM_FORMAT_ARGB8888, viz::SinglePlaneFormat::kBGRA_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::ranges::find( |
| shm_supported_formats, format, &shm_supported_format::shm_format); |
| if (supported_format == std::end(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> buffer = |
| GetUserDataAs<SharedMemory>(resource)->CreateBuffer( |
| gfx::Size(width, height), supported_format->si_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<SharedMemory>(resource); |
| if (size < 0 || static_cast<size_t>(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<SharedMemory> shared_memory = |
| GetUserDataAs<Display>(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 |