From 9e0e1d5051b7bfd33dffbdd0fdc884cbcee80846 Mon Sep 17 00:00:00 2001 From: Robert Mader Date: Tue, 29 Aug 2023 22:25:18 +0200 Subject: [PATCH] vm_tools: sommelier: Implement fractional scale protocol A simple implementation of the fractional scale protocol, forwarding the value from the parent compositor and adjusting it for the requested scale, similar to sl_output. See https://chromium-review.googlesource.com/c/chromium/src/+/4660423 for the Exo implementation. BUG=b:289488725 TEST=Manual testing with test clients Change-Id: I64bc417248241c0b1b62c4c40c053eaaf2798e60 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/4827206 Commit-Queue: Robert Mader Tested-by: Robert Mader Reviewed-by: Nic Hollingum Reviewed-by: Ryan Neph --- BUILD.gn | 2 + meson.build | 2 + protocol/fractional-scale-v1.xml | 102 +++++++++++++++++++++++ sommelier-ctx.cc | 1 + sommelier-ctx.h | 1 + sommelier-fractional-scale.cc | 136 +++++++++++++++++++++++++++++++ sommelier.cc | 17 ++++ sommelier.h | 15 ++++ 8 files changed, 276 insertions(+) create mode 100644 protocol/fractional-scale-v1.xml create mode 100644 sommelier-fractional-scale.cc diff --git a/BUILD.gn b/BUILD.gn index c6552f9..1727cee 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -40,6 +40,7 @@ if (!defined(dark_frame_color)) { wayland_protocols = [ "protocol/aura-shell.xml", "protocol/drm.xml", + "protocol/fractional-scale-v1.xml", "protocol/gaming-input-unstable-v2.xml", "protocol/gtk-shell.xml", "protocol/keyboard-extension-unstable-v1.xml", @@ -107,6 +108,7 @@ static_library("libsommelier") { "sommelier-ctx.cc", "sommelier-data-device-manager.cc", "sommelier-display.cc", + "sommelier-fractional-scale.cc", "sommelier-global.cc", "sommelier-gtk-shell.cc", "sommelier-inpututils.cc", diff --git a/meson.build b/meson.build index ffd6884..0bd66c3 100644 --- a/meson.build +++ b/meson.build @@ -39,6 +39,7 @@ wl_generators = [ wl_protocols = [ 'protocol/aura-shell.xml', 'protocol/drm.xml', + 'protocol/fractional-scale-v1.xml', 'protocol/gaming-input-unstable-v2.xml', 'protocol/gtk-shell.xml', 'protocol/keyboard-extension-unstable-v1.xml', @@ -155,6 +156,7 @@ libsommelier = static_library('sommelier', 'sommelier-ctx.cc', 'sommelier-data-device-manager.cc', 'sommelier-display.cc', + 'sommelier-fractional-scale.cc', 'sommelier-gtk-shell.cc', 'sommelier-global.cc', 'sommelier-inpututils.cc', diff --git a/protocol/fractional-scale-v1.xml b/protocol/fractional-scale-v1.xml new file mode 100644 index 0000000..350bfc0 --- /dev/null +++ b/protocol/fractional-scale-v1.xml @@ -0,0 +1,102 @@ + + + + Copyright © 2022 Kenny Levinsen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol allows a compositor to suggest for surfaces to render at + fractional scales. + + A client can submit scaled content by utilizing wp_viewport. This is done by + creating a wp_viewport object for the surface and setting the destination + rectangle to the surface size before the scale factor is applied. + + The buffer size is calculated by multiplying the surface size by the + intended scale. + + The wl_surface buffer scale should remain set to 1. + + If a surface has a surface-local size of 100 px by 50 px and wishes to + submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should + be used and the wp_viewport destination rectangle should be 100 px by 50 px. + + For toplevel surfaces, the size is rounded halfway away from zero. The + rounding algorithm for subsurface position and size is not defined. + + + + + A global interface for requesting surfaces to use fractional scales. + + + + + Informs the server that the client will not be using this protocol + object anymore. This does not affect any other objects, + wp_fractional_scale_v1 objects included. + + + + + + + + + + Create an add-on object for the the wl_surface to let the compositor + request fractional scales. If the given wl_surface already has a + wp_fractional_scale_v1 object associated, the fractional_scale_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object which allows the compositor + to inform the client of the preferred scale. + + + + + Destroy the fractional scale object. When this object is destroyed, + preferred_scale events will no longer be sent. + + + + + + Notification of a new preferred scale for this surface that the + compositor suggests that the client should use. + + The sent scale is the numerator of a fraction with a denominator of 120. + + + + + diff --git a/sommelier-ctx.cc b/sommelier-ctx.cc index 0a6c6cc..b763024 100644 --- a/sommelier-ctx.cc +++ b/sommelier-ctx.cc @@ -113,6 +113,7 @@ void sl_context_init_default(struct sl_context* ctx) { ctx->text_input_manager = nullptr; ctx->text_input_extension = nullptr; ctx->xdg_output_manager = nullptr; + ctx->fractional_scale_manager = nullptr; #ifdef GAMEPAD_SUPPORT ctx->gaming_input_manager = nullptr; ctx->gaming_seat = nullptr; diff --git a/sommelier-ctx.h b/sommelier-ctx.h index 41ca57e..3aa97a9 100644 --- a/sommelier-ctx.h +++ b/sommelier-ctx.h @@ -94,6 +94,7 @@ struct sl_context { struct sl_stylus_input_manager* stylus_input_manager; struct sl_relative_pointer_manager* relative_pointer_manager; struct sl_pointer_constraints* pointer_constraints; + struct sl_fractional_scale_manager* fractional_scale_manager; struct wl_list outputs; struct wl_list seats; std::unique_ptr display_event_source; diff --git a/sommelier-fractional-scale.cc b/sommelier-fractional-scale.cc new file mode 100644 index 0000000..bef9440 --- /dev/null +++ b/sommelier-fractional-scale.cc @@ -0,0 +1,136 @@ +// 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-tracing.h" // NOLINT(build/include_directory) + +#include +#include + +#include "fractional-scale-v1-client-protocol.h" // NOLINT(build/include_directory) +#include "fractional-scale-v1-server-protocol.h" // NOLINT(build/include_directory) + +struct sl_host_fractional_scale_manager { + struct sl_fractional_scale_manager* fractional_scale_manager; + struct wl_resource* resource; + struct wp_fractional_scale_manager_v1* proxy; +}; + +struct sl_host_fractional_scale { + struct sl_host_fractional_scale_manager* host_fractional_scale_manager; + struct wl_resource* resource; + struct wp_fractional_scale_v1* proxy; +}; + +static void sl_fractional_scale_destroy(struct wl_client* client, + struct wl_resource* resource) { + wl_resource_destroy(resource); +} + +static void sl_fractional_scale_handle_preferred_scale( + void* data, + struct wp_fractional_scale_v1* fractional_scale, + uint32_t wire_scale) { + struct sl_host_fractional_scale* host_fractional_scale = + static_cast( + wp_fractional_scale_v1_get_user_data(fractional_scale)); + struct sl_fractional_scale_manager* fractional_scale_manager = + host_fractional_scale->host_fractional_scale_manager + ->fractional_scale_manager; + + wp_fractional_scale_v1_send_preferred_scale( + host_fractional_scale->resource, + round(wire_scale / fractional_scale_manager->ctx->scale)); +} + +static const struct wp_fractional_scale_v1_listener fractional_scale_listener = + { + .preferred_scale = sl_fractional_scale_handle_preferred_scale, +}; + +static const struct wp_fractional_scale_v1_interface + sl_fractional_scale_implementation = {sl_fractional_scale_destroy}; + +static void sl_destroy_host_fractional_scale(struct wl_resource* resource) { + struct sl_host_fractional_scale* host = + static_cast( + wl_resource_get_user_data(resource)); + + wl_resource_set_user_data(resource, nullptr); + delete host; +} + +static void sl_fractional_scale_manager_destroy(struct wl_client* client, + struct wl_resource* resource) { + wl_resource_destroy(resource); +} + +static void sl_fractional_scale_manager_get_fractional_scale( + struct wl_client* client, + struct wl_resource* resource, + uint32_t id, + struct wl_resource* surface_resource) { + struct sl_host_fractional_scale_manager* host = + static_cast( + wl_resource_get_user_data(resource)); + struct sl_host_surface* host_surface = static_cast( + wl_resource_get_user_data(surface_resource)); + struct sl_host_fractional_scale* host_fractional_scale = + new sl_host_fractional_scale(); + + host_fractional_scale->host_fractional_scale_manager = host; + host_fractional_scale->resource = + wl_resource_create(client, &wp_fractional_scale_v1_interface, 1, id); + host_fractional_scale->proxy = + wp_fractional_scale_manager_v1_get_fractional_scale( + host->fractional_scale_manager->internal, host_surface->proxy); + wp_fractional_scale_v1_add_listener(host_fractional_scale->proxy, + &fractional_scale_listener, + host_fractional_scale); + wl_resource_set_implementation( + host_fractional_scale->resource, &sl_fractional_scale_implementation, + host_fractional_scale, sl_destroy_host_fractional_scale); +} + +static const struct wp_fractional_scale_manager_v1_interface + sl_wp_fractional_scale_manager_implementation = { + sl_fractional_scale_manager_destroy, + sl_fractional_scale_manager_get_fractional_scale, +}; + +static void sl_destroy_host_fractional_scale_manager( + struct wl_resource* resource) { + struct sl_host_fractional_scale_manager* host = + static_cast( + wl_resource_get_user_data(resource)); + + wp_fractional_scale_manager_v1_destroy(host->proxy); + wl_resource_set_user_data(resource, nullptr); + delete host; +} + +static void sl_bind_host_fractional_scale_manager(struct wl_client* client, + void* data, + uint32_t version, + uint32_t id) { + struct sl_context* ctx = (struct sl_context*)data; + struct sl_host_fractional_scale_manager* host = + new sl_host_fractional_scale_manager(); + host->fractional_scale_manager = ctx->fractional_scale_manager; + host->resource = wl_resource_create( + client, &wp_fractional_scale_manager_v1_interface, 1, id); + wl_resource_set_implementation( + host->resource, &sl_wp_fractional_scale_manager_implementation, host, + sl_destroy_host_fractional_scale_manager); + host->proxy = static_cast(wl_registry_bind( + wl_display_get_registry(ctx->display), ctx->fractional_scale_manager->id, + &wp_fractional_scale_manager_v1_interface, 1)); + wp_fractional_scale_manager_v1_set_user_data(host->proxy, host); +} + +struct sl_global* sl_fractional_scale_manager_global_create( + struct sl_context* ctx) { + return sl_global_create(ctx, &wp_fractional_scale_manager_v1_interface, 1, + ctx, sl_bind_host_fractional_scale_manager); +} diff --git a/sommelier.cc b/sommelier.cc index 5997558..6ffd279 100644 --- a/sommelier.cc +++ b/sommelier.cc @@ -40,6 +40,7 @@ #include "aura-shell-client-protocol.h" // NOLINT(build/include_directory) #include "drm-server-protocol.h" // NOLINT(build/include_directory) +#include "fractional-scale-v1-client-protocol.h" // NOLINT(build/include_directory) #ifdef GAMEPAD_SUPPORT #include "gaming-input-unstable-v2-client-protocol.h" // NOLINT(build/include_directory) #endif @@ -774,6 +775,22 @@ void sl_registry_handler(void* data, static_cast(wl_registry_bind( registry, id, &zxdg_output_manager_v1_interface, MIN(3, version))); ctx->xdg_output_manager = output_manager; + } else if (strcmp(interface, wp_fractional_scale_manager_v1_interface.name) == + 0) { + struct sl_fractional_scale_manager* fractional_scale_manager = + static_cast( + malloc(sizeof(struct sl_fractional_scale_manager))); + assert(fractional_scale_manager); + fractional_scale_manager->ctx = ctx; + fractional_scale_manager->id = id; + fractional_scale_manager->host_fractional_scale_manager_global = nullptr; + fractional_scale_manager->internal = + static_cast(wl_registry_bind( + registry, id, &wp_fractional_scale_manager_v1_interface, 1)); + assert(!ctx->fractional_scale_manager); + ctx->fractional_scale_manager = fractional_scale_manager; + fractional_scale_manager->host_fractional_scale_manager_global = + sl_fractional_scale_manager_global_create(ctx); } } diff --git a/sommelier.h b/sommelier.h index 323fc55..e630c32 100644 --- a/sommelier.h +++ b/sommelier.h @@ -53,6 +53,7 @@ struct sl_pointer_constraints; struct sl_window; struct sl_host_surface; struct sl_host_output; +struct sl_fractional_scale_manager; struct zaura_shell; struct zcr_keyboard_extension_v1; struct zxdg_output_manager_v1; @@ -137,6 +138,10 @@ struct sl_viewport { int32_t dst_height; }; +struct sl_fractional_scale { + struct wl_list link; +}; + struct sl_host_callback { struct wl_resource* resource; struct wl_callback* proxy; @@ -401,6 +406,13 @@ struct sl_linux_explicit_synchronization { struct zwp_linux_explicit_synchronization_v1* internal; }; +struct sl_fractional_scale_manager { + struct sl_context* ctx; + uint32_t id; + struct sl_global* host_fractional_scale_manager_global; + struct wp_fractional_scale_manager_v1* internal; +}; + struct sl_global { struct sl_context* ctx; const struct wl_interface* interface; @@ -518,6 +530,9 @@ struct sl_global* sl_text_input_crostini_manager_global_create( struct sl_global* sl_pointer_constraints_global_create(struct sl_context* ctx); +struct sl_global* sl_fractional_scale_manager_global_create( + struct sl_context* ctx); + void sl_set_display_implementation(struct sl_context* ctx, struct wl_client* client);