From dfcd969d3ec88a539bfc0e24b61afe44d5e451e5 Mon Sep 17 00:00:00 2001 From: oldosfan Date: Fri, 30 Sep 2022 01:00:09 +0000 Subject: [PATCH] Add files for viewporter support * transform.c: * viewporter.xml: * wp_viewporter.c: New files. --- transform.c | 177 ++++++++++++++++++++++++++++++++ viewporter.xml | 180 ++++++++++++++++++++++++++++++++ wp_viewporter.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 623 insertions(+) create mode 100644 transform.c create mode 100644 viewporter.xml create mode 100644 wp_viewporter.c diff --git a/transform.c b/transform.c new file mode 100644 index 0000000..621d7ab --- /dev/null +++ b/transform.c @@ -0,0 +1,177 @@ +/* Wayland compositor running on top of an X server. + +Copyright (C) 2022 to various contributors. + +This file is part of 12to11. + +12to11 is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +12to11 is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with 12to11. If not, see . */ + +/* Generic 3x3 matrix transform code. */ + +#include +#include + +#include "compositor.h" + +#include + +/* These macros make column major order easier to reason about for C + folks. */ +#define Index(matrix, row, column) \ + ((matrix)[(column) * 3 + (row)]) + +#define MultiplySub(a, b, a_row, a_column, b_row, b_column) \ + (Index (a, a_row, a_column) * Index (b, b_row, b_column)) + +#if 0 + +static void +MatrixPrint (Matrix *matrix) +{ + fprintf (stderr, + "%4f %4f %4f\n" + "%4f %4f %4f\n" + "%4f %4f %4f\n\n", + (double) Index (*matrix, 0, 0), + (double) Index (*matrix, 0, 1), + (double) Index (*matrix, 0, 2), + (double) Index (*matrix, 1, 0), + (double) Index (*matrix, 1, 1), + (double) Index (*matrix, 1, 2), + (double) Index (*matrix, 2, 0), + (double) Index (*matrix, 2, 1), + (double) Index (*matrix, 2, 2)); +} + +#endif + +void +MatrixMultiply (Matrix a, Matrix b, Matrix *product) +{ + Index (*product, 0, 0) = (MultiplySub (a, b, 0, 0, 0, 0) + + MultiplySub (a, b, 0, 1, 1, 0) + + MultiplySub (a, b, 0, 2, 2, 0)); + Index (*product, 0, 1) = (MultiplySub (a, b, 0, 0, 0, 1) + + MultiplySub (a, b, 0, 1, 1, 1) + + MultiplySub (a, b, 0, 2, 2, 1)); + Index (*product, 0, 2) = (MultiplySub (a, b, 0, 0, 0, 2) + + MultiplySub (a, b, 0, 1, 1, 2) + + MultiplySub (a, b, 0, 2, 2, 2)); + + Index (*product, 1, 0) = (MultiplySub (a, b, 1, 0, 0, 0) + + MultiplySub (a, b, 1, 1, 1, 0) + + MultiplySub (a, b, 1, 2, 2, 0)); + Index (*product, 1, 1) = (MultiplySub (a, b, 1, 0, 0, 1) + + MultiplySub (a, b, 1, 1, 1, 1) + + MultiplySub (a, b, 1, 2, 2, 1)); + Index (*product, 1, 2) = (MultiplySub (a, b, 1, 0, 0, 2) + + MultiplySub (a, b, 1, 1, 1, 2) + + MultiplySub (a, b, 1, 2, 2, 2)); + + Index (*product, 2, 0) = (MultiplySub (a, b, 2, 0, 0, 0) + + MultiplySub (a, b, 2, 1, 1, 0) + + MultiplySub (a, b, 2, 2, 2, 0)); + Index (*product, 2, 1) = (MultiplySub (a, b, 2, 0, 0, 1) + + MultiplySub (a, b, 2, 1, 1, 1) + + MultiplySub (a, b, 2, 2, 2, 1)); + Index (*product, 2, 2) = (MultiplySub (a, b, 2, 0, 0, 2) + + MultiplySub (a, b, 2, 1, 1, 2) + + MultiplySub (a, b, 2, 2, 2, 2)); +} + +void +MatrixIdentity (Matrix *matrix) +{ + memset (matrix, 0, sizeof *matrix); + + Index (*matrix, 0, 0) = 1.0f; + Index (*matrix, 1, 1) = 1.0f; + Index (*matrix, 2, 2) = 1.0f; +} + +void +MatrixTranslate (Matrix *transform, float tx, float ty) +{ + Matrix temp, copy; + + MatrixIdentity (&temp); + memcpy (copy, transform, sizeof copy); + + /* Set the tx and ty. */ + Index (temp, 0, 2) = tx; + Index (temp, 1, 2) = ty; + + /* Multiply it with the transform. */ + MatrixMultiply (copy, temp, transform); +} + +void +MatrixScale (Matrix *transform, float sx, float sy) +{ + Matrix temp, copy; + + MatrixIdentity (&temp); + memcpy (copy, transform, sizeof copy); + + /* Set the scale factors. */ + Index (temp, 0, 0) = sx; + Index (temp, 1, 1) = sy; + + /* Multiply it with the transform. */ + MatrixMultiply (copy, temp, transform); +} + +void +MatrixExport (Matrix *transform, XTransform *xtransform) +{ + /* M1 M2 M3 X + M4 M5 M6 * Y + M7 M8 M9 Z + + = + + M1*X + M2*Y + M3*1 = X1 + M4*X + M5*Y + M6*1 = Y1 + M7*X + M8*Y + M9*1 = Z1 (Only on some drivers) + + where + + M1 = matrix[0][0] + M2 = matrix[0][1] + M3 = matrix[0][2] + M4 = matrix[1][0] + M5 = matrix[1][1] + M6 = matrix[1][2] + M7 = matrix[2][0] + M8 = matrix[2][1] + M9 = matrix[2][2] */ + +#define Export(row, column) \ + xtransform->matrix[row][column] \ + = XDoubleToFixed (Index (*transform, row, column)) + + Export (0, 0); + Export (0, 1); + Export (0, 2); + + Export (1, 0); + Export (1, 1); + Export (1, 2); + + Export (2, 0); + Export (2, 1); + Export (2, 2); + +#undef Export +} diff --git a/viewporter.xml b/viewporter.xml new file mode 100644 index 0000000..d1048d1 --- /dev/null +++ b/viewporter.xml @@ -0,0 +1,180 @@ + + + + + Copyright © 2013-2016 Collabora, Ltd. + + 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. + + + + + The global interface exposing surface cropping and scaling + capabilities is used to instantiate an interface extension for a + wl_surface object. This extended interface will then allow + cropping and scaling the surface contents, effectively + disconnecting the direct relationship between the buffer and the + surface size. + + + + + Informs the server that the client will not be using this + protocol object anymore. This does not affect any other objects, + wp_viewport objects included. + + + + + + + + + + Instantiate an interface extension for the given wl_surface to + crop and scale its content. If the given wl_surface already has + a wp_viewport object associated, the viewport_exists + protocol error is raised. + + + + + + + + + An additional interface to a wl_surface object, which allows the + client to specify the cropping and scaling of the surface + contents. + + This interface works with two concepts: the source rectangle (src_x, + src_y, src_width, src_height), and the destination size (dst_width, + dst_height). The contents of the source rectangle are scaled to the + destination size, and content outside the source rectangle is ignored. + This state is double-buffered, and is applied on the next + wl_surface.commit. + + The two parts of crop and scale state are independent: the source + rectangle, and the destination size. Initially both are unset, that + is, no scaling is applied. The whole of the current wl_buffer is + used as the source, and the surface size is as defined in + wl_surface.attach. + + If the destination size is set, it causes the surface size to become + dst_width, dst_height. The source (rectangle) is scaled to exactly + this size. This overrides whatever the attached wl_buffer size is, + unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface + has no content and therefore no size. Otherwise, the size is always + at least 1x1 in surface local coordinates. + + If the source rectangle is set, it defines what area of the wl_buffer is + taken as the source. If the source rectangle is set and the destination + size is not set, then src_width and src_height must be integers, and the + surface size becomes the source rectangle size. This results in cropping + without scaling. If src_width or src_height are not integers and + destination size is not set, the bad_size protocol error is raised when + the surface state is applied. + + The coordinate transformations from buffer pixel coordinates up to + the surface-local coordinates happen in the following order: + 1. buffer_transform (wl_surface.set_buffer_transform) + 2. buffer_scale (wl_surface.set_buffer_scale) + 3. crop and scale (wp_viewport.set*) + This means, that the source rectangle coordinates of crop and scale + are given in the coordinates after the buffer transform and scale, + i.e. in the coordinates that would be the surface-local coordinates + if the crop and scale was not applied. + + If src_x or src_y are negative, the bad_value protocol error is raised. + Otherwise, if the source rectangle is partially or completely outside of + the non-NULL wl_buffer, then the out_of_buffer protocol error is raised + when the surface state is applied. A NULL wl_buffer does not raise the + out_of_buffer error. + + If the wl_surface associated with the wp_viewport is destroyed, + all wp_viewport requests except 'destroy' raise the protocol error + no_surface. + + If the wp_viewport object is destroyed, the crop and scale + state is removed from the wl_surface. The change will be applied + on the next wl_surface.commit. + + + + + The associated wl_surface's crop and scale state is removed. + The change is applied on the next wl_surface.commit. + + + + + + + + + + + + + Set the source rectangle of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If all of x, y, width and height are -1.0, the source rectangle is + unset instead. Any other set of values where width or height are zero + or negative, or x or y are negative, raise the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + + + + Set the destination size of the associated wl_surface. See + wp_viewport for the description, and relation to the wl_buffer + size. + + If width is -1 and height is -1, the destination size is unset + instead. Any other pair of values for width and height that + contains zero or negative values raises the bad_value protocol + error. + + The crop and scale state is double-buffered state, and will be + applied on the next wl_surface.commit. + + + + + + + diff --git a/wp_viewporter.c b/wp_viewporter.c new file mode 100644 index 0000000..f9af8b8 --- /dev/null +++ b/wp_viewporter.c @@ -0,0 +1,266 @@ +/* Wayland compositor running on top of an X server. + +Copyright (C) 2022 to various contributors. + +This file is part of 12to11. + +12to11 is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation, either version 3 of the License, or (at your +option) any later version. + +12to11 is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with 12to11. If not, see . */ + +#include + +#include "compositor.h" +#include "viewporter.h" + +typedef struct _ViewportExt ViewportExt; + +struct _ViewportExt +{ + /* The attached surface. */ + Surface *surface; + + /* The attached callback. */ + DestroyCallback *destroy_callback; + + /* The associated wl_resource. */ + struct wl_resource *resource; +}; + +/* The wp_viewporter global. */ +static struct wl_global *viewporter_global; + +static void +HandleResourceDestroy (struct wl_resource *resource) +{ + ViewportExt *ext; + + ext = wl_resource_get_user_data (resource); + + /* Free the user data and detach the surface destroy callback. */ + + if (ext->surface) + { + XLSurfaceCancelRunOnFree (ext->destroy_callback); + ext->surface->viewport = NULL; + + /* Clear viewport data. */ + ext->surface->pending_state.pending |= PendingViewportSrc; + ext->surface->pending_state.pending |= PendingViewportDest; + ext->surface->pending_state.src_x = -1.0; + ext->surface->pending_state.src_y = -1.0; + ext->surface->pending_state.src_width = -1.0; + ext->surface->pending_state.src_height = -1.0; + ext->surface->pending_state.dest_width = -1; + ext->surface->pending_state.dest_height = -1; + } + + XLFree (ext); +} + +static void +HandleSurfaceDestroy (void *data) +{ + ViewportExt *ext; + + ext = data; + + /* Clear callbacks and surface, as they are now gone. */ + ext->surface = NULL; + ext->destroy_callback = NULL; +} + +static void +DestroyViewport (struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +SetSource (struct wl_client *client, struct wl_resource *resource, + wl_fixed_t x, wl_fixed_t y, wl_fixed_t width, wl_fixed_t height) +{ + ViewportExt *ext; + double src_x, src_y, src_width, src_height; + + ext = wl_resource_get_user_data (resource); + + /* Check that the surface is still attached. */ + if (!ext->surface) + { + wl_resource_post_error (resource, WP_VIEWPORT_ERROR_NO_SURFACE, + "the surface has been detached"); + return; + } + + src_x = wl_fixed_to_double (x); + src_y = wl_fixed_to_double (y); + src_width = wl_fixed_to_double (width); + src_height = wl_fixed_to_double (height); + + /* Now, verify that the values are correct. They can either all be + -1, or the origin must be positive, and width and height must be + more than 0. */ + if (!(src_x == -1.0 && src_y == -1.0 && src_width == -1.0 + && src_height == -1.0) + && (src_x < 0 || src_y < 0 + || src_width < 1.0 || src_height < 1.0)) + wl_resource_post_error (resource, WP_VIEWPORT_ERROR_BAD_VALUE, + "invalid source rectangle specified"); + + ext->surface->pending_state.pending |= PendingViewportSrc; + ext->surface->pending_state.src_x = src_x; + ext->surface->pending_state.src_y = src_y; + ext->surface->pending_state.src_width = src_width; + ext->surface->pending_state.src_height = src_height; +} + +static void +SetDestination (struct wl_client *client, struct wl_resource *resource, + int32_t width, int32_t height) +{ + ViewportExt *ext; + + ext = wl_resource_get_user_data (resource); + + /* Check that the surface is still attached. */ + if (!ext->surface) + { + wl_resource_post_error (resource, WP_VIEWPORT_ERROR_NO_SURFACE, + "the surface has been detached"); + return; + } + + if ((width <= 0 || height <= 0) + && !(width == -1 && height == -1)) + { + wl_resource_post_error (resource, WP_VIEWPORT_ERROR_BAD_VALUE, + "invalid destination size specified"); + return; + } + + ext->surface->pending_state.pending |= PendingViewportDest; + ext->surface->pending_state.dest_width = width; + ext->surface->pending_state.dest_height = height; +} + +static const struct wp_viewport_interface wp_viewport_impl = + { + .destroy = DestroyViewport, + .set_source = SetSource, + .set_destination = SetDestination, + }; + + + +static void +Destroy (struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy (resource); +} + +static void +GetViewport (struct wl_client *client, struct wl_resource *resource, + uint32_t id, struct wl_resource *surface_resource) +{ + ViewportExt *ext; + Surface *surface; + + surface = wl_resource_get_user_data (surface_resource); + + /* If the surface already has a viewport resource attached, post an + error. */ + if (surface->viewport) + { + wl_resource_post_error (resource, WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS, + "viewport already exists"); + return; + } + + ext = XLSafeMalloc (sizeof *ext); + + if (!ext) + { + wl_resource_post_no_memory (resource); + return; + } + + memset (ext, 0, sizeof *ext); + ext->resource + = wl_resource_create (client, &wp_viewport_interface, + wl_resource_get_version (resource), id); + + if (!ext->resource) + { + XLFree (ext); + wl_resource_post_no_memory (resource); + return; + } + + /* Attach the surface. */ + ext->surface = wl_resource_get_user_data (surface_resource); + ext->destroy_callback + = XLSurfaceRunOnFree (ext->surface, HandleSurfaceDestroy, + ext); + surface->viewport = ext; + + wl_resource_set_implementation (ext->resource, &wp_viewport_impl, + ext, HandleResourceDestroy); +} + +static const struct wp_viewporter_interface wp_viewporter_impl = + { + .destroy = Destroy, + .get_viewport = GetViewport, + }; + + + +static void +HandleBind (struct wl_client *client, void *data, uint32_t version, + uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create (client, &wp_viewporter_interface, + version, id); + if (!resource) + { + wl_client_post_no_memory (client); + return; + } + + wl_resource_set_implementation (resource, &wp_viewporter_impl, NULL, + NULL); +} + +void +XLInitWpViewporter (void) +{ + viewporter_global = wl_global_create (compositor.wl_display, + &wp_viewporter_interface, + 1, NULL, HandleBind); +} + +void +XLWpViewportReportBadSize (ViewportExt *ext) +{ + wl_resource_post_error (ext->resource, WP_VIEWPORT_ERROR_BAD_SIZE, + "invalid non-integer size specified"); +} + +void +XLWpViewportReportOutOfBuffer (ViewportExt *ext) +{ + wl_resource_post_error (ext->resource, WP_VIEWPORT_ERROR_OUT_OF_BUFFER, + "viewport source rectangle out of buffer"); +}