// Copyright 2022 The ChromiumOS Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef VM_TOOLS_SOMMELIER_SOMMELIER_TRANSFORM_H_ #define VM_TOOLS_SOMMELIER_SOMMELIER_TRANSFORM_H_ #include "sommelier.h" // NOLINT(build/include_directory) #include "sommelier-ctx.h" // NOLINT(build/include_directory) // Direct Scaling Mode Explained: // // It will be helpful to define the 3 coordinate spaces that we need to // manage: // // 1. Physical Coordinate Space: This refers to the actual physical dimensions // of the devices display. Typical sizes would be 3840x2160, 1920x1080, etc. // // 2. Virtual Coordinate Space: This refers to the coordinate space that is // formed by multiplying the scale factor with the physical dimensions. // (Example: scale = 1.0, physical = 3840x2160, virtual = 3840x2160) // (Example: scale = 0.5, physical = 3840x2160, virtual = 1920x1080) // The scale factor will come from the "--scale" command line parameter or // from the associated environment variable. // // 3. Host Logical Space: The dimensions of this space are defined // entirely by the host. The exact dimensions are retrieved through // the xdg_output interface. It is assumed that there is a direct, linear // relationship between the logical space and the physical space on the // host. As an example: // a) A 1600x900 logical space // b) A 3840x2160 physical space // // If we place a 1600x900 dimensioned object at the origin of the logical // space, it should appear as a 3840x2160 object within the physical space // (also at the origin). // // The product of the desired scale factor and the physical dimensions may // result in non-integer values. In these cases, the result // is rounded down towards zero (truncate). This slight modification // will require recomputation of the scale factors to maintain consistency // between the two coordinate spaces. For this reason, the (single) scale // factor provided as input from the user is used to generate the virtual // coordinates. Then once those have been computed (and rounded), the scale // factors for each axis will then be recalculated using the virtual and // logical dimensions. Each axis is given its own scale factor because // it is possible for only one axis to require rounding. // // The logical coordinates come to us from the host. This is the // coordinate space that the host is operating in. This can change // based on the users scale settings. // // The physical coordinate space is no longer necessary once the virtual // coordinate space has been formed, so no scaling factors are needed to // convert to that space. // // Xwayland operates within the virtual coordinate space and the // host is operating within its logical space. Sommelier only needs to // facilitate translations between these two coordinate spaces. // // The virtual to logical scale factors are derived from the ratios between // the virtual coordinate spaces dimensions and the logical coordinate spaces // dimensions. // // In this mode, a buffer that is full screen sized within Xwayland (virtual) // will also be full screen sized in the logical coordinate space. The same // pattern holds with a quarter resolution sized image. With a scale factor // of 1.0, it is expected that there will be no scaling done to present the // image onto the screen. // Coordinate transform functions // // In general, the transformation functions fall under one of these // two classes: // // 1. Transformations which follow the basic rules: // A straight multiply for host->guest and straight divide for the opposite // 2. Transformations which perform their transformations in a slightly // different manner. // // The functions immediately following this block fall under the latter // They are separate functions so these cases can be easily identified // throughout the rest of the code. // // The functions that fall under the latter case work in the // guest->host direction and do not have variants which work in the // opposite direction. // This particular function will return true if setting a destination // viewport size is necessary. It can be false if the host/guest spaces // matches. // This is a potential optimization as it removes one step // from the guest->host surface_attach cycle. bool sl_transform_viewport_scale(struct sl_context* ctx, struct sl_host_surface* surface, double contents_scale, int32_t* width, int32_t* height); void sl_transform_damage_coord(struct sl_context* ctx, const struct sl_host_surface* surface, double buffer_scalex, double buffer_scaley, int64_t* x1, int64_t* y1, int64_t* x2, int64_t* y2); // Basic Transformations // The following transformations fall under the basic type // 1D transformation functions have an axis specifier // to indicate along which axis the transformation is to // take place. // // The axis specifier will follow the wl_pointer::axis definitions // 0 = vertical axis (Y) // 1 = horizontal axis (X) void sl_transform_host_to_guest(struct sl_context* ctx, struct sl_host_surface* surface, int32_t* x, int32_t* y); void sl_transform_host_to_guest_fixed(struct sl_context* ctx, struct sl_host_surface* surface, wl_fixed_t* x, wl_fixed_t* y); void sl_transform_host_to_guest_fixed(struct sl_context* ctx, struct sl_host_surface* surface, wl_fixed_t* coord, uint32_t axis); // Opposite Direction void sl_transform_guest_to_host(struct sl_context* ctx, struct sl_host_surface* surface, int32_t* x, int32_t* y); void sl_transform_guest_to_host_fixed(struct sl_context* ctx, struct sl_host_surface* surface, wl_fixed_t* x, wl_fixed_t* y); void sl_transform_guest_to_host_fixed(struct sl_context* ctx, struct sl_host_surface* surface, wl_fixed_t* coord, uint32_t axis); // Given the desired window size in virtual pixels, this function // will see if it can be cleanly converted to logical coordinates and back. // // If the desired dimensions can be met with the default scaling factors, // no intervention will take place. // // If the desired dimensions CANNOT be met with the default scaling factors, // a set of scaling factors will be chosen to match the nearest logical // coordinates to the desired virtual pixel dimensions. These scaling factors // will then be used for all transformations being performed on this surface. // // This function is a no-op when not in direct scale mode. void sl_transform_try_window_scale(struct sl_context* ctx, struct sl_host_surface* surface, int32_t width_in_pixels, int32_t height_in_pixels); // Removes any custom scaling factors that have been set on the surface // by try_window_scale void sl_transform_reset_surface_scale(struct sl_context* ctx, struct sl_host_surface* surface); // This function performs the physical to virtual transformation // based on the scale factor provided by the command line/env. // This function is called in response to the physical dimensions being sent // by the host. The virtual dimensions are calculated by this function and // then relayed to the guest. void sl_transform_output_dimensions(struct sl_context* ctx, int32_t* width, int32_t* height); #endif // VM_TOOLS_SOMMELIER_SOMMELIER_TRANSFORM_H_