Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit

Permalink
vm_tools: Use viewport to handle window resizing
Browse files Browse the repository at this point in the history
BUG=b:316990641
TEST=left4dead2

Change-Id: I6543c60b5e8dba9242cb4d0854c0d1d29190b642
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/5171466
Commit-Queue: Lucy Qu <[email protected]>
Reviewed-by: Chloe Pelling <[email protected]>
Tested-by: Lucy Qu <[email protected]>
  • Loading branch information
Lucy Qu authored and Chromeos LUCI committed Jan 16, 2024
1 parent 3807b51 commit 8ce185a
Show file tree
Hide file tree
Showing 13 changed files with 383 additions and 33 deletions.
10 changes: 5 additions & 5 deletions compositor/sommelier-compositor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "../sommelier-xshape.h" // NOLINT(build/include_directory)
#include "sommelier-dmabuf-sync.h" // NOLINT(build/include_directory)
#include "sommelier-formats.h" // NOLINT(build/include_directory)

#include "viewporter-shim.h" // NOLINT(build/include_directory)
#include <assert.h>
#include <errno.h>
#include <libdrm/drm_fourcc.h>
Expand Down Expand Up @@ -600,8 +600,8 @@ static void copy_damaged_rect(sl_host_surface* host,
}
}

static void sl_host_surface_commit(struct wl_client* client,
struct wl_resource* resource) {
void sl_host_surface_commit(struct wl_client* client,
struct wl_resource* resource) {
auto resource_id = try_wl_resource_get_id(resource);
TRACE_EVENT(
"surface", "sl_host_surface_commit", "resource_id", resource_id,
Expand Down Expand Up @@ -741,12 +741,12 @@ static void sl_host_surface_commit(struct wl_client* client,

int32_t vp_width = width;
int32_t vp_height = height;

// Consult with the transform function to see if the
// viewport destination set is necessary
if (sl_transform_viewport_scale(host->ctx, host, host->contents_scale,
&vp_width, &vp_height)) {
wp_viewport_set_destination(host->viewport, vp_width, vp_height);
wp_viewport_shim()->set_destination(host->viewport, vp_width,
vp_height);
}
} else {
wl_surface_set_buffer_scale(host->proxy, scale);
Expand Down
1 change: 1 addition & 0 deletions sommelier-ctx.cc
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ void sl_context_init_default(struct sl_context* ctx) {
ctx->stable_scaling = false;
ctx->frame_stats = nullptr;
ctx->stats_timer_delay = 60 * 1000;
ctx->viewport_resize = false;

wl_list_init(&ctx->registries);
wl_list_init(&ctx->globals);
Expand Down
1 change: 1 addition & 0 deletions sommelier-ctx.h
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ struct sl_context {
bool use_explicit_fence;
bool use_virtgpu_channel;
bool use_direct_scale;
bool viewport_resize;

// Experimental feature flags to be cleaned up.
bool enable_x11_move_windows; // TODO(b/247452928): Clean this up.
Expand Down
3 changes: 1 addition & 2 deletions sommelier-seat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ static void sl_pointer_motion(void* data,
wl_fixed_t mx = x;
wl_fixed_t my = y;

sl_transform_host_to_guest_fixed(host->seat->ctx, host->focus_surface, &mx,
&my);
sl_transform_pointer(host->seat->ctx, host->focus_surface, &mx, &my);
wl_pointer_send_motion(host->resource, time, mx, my);
}

Expand Down
42 changes: 36 additions & 6 deletions sommelier-transform-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@

#include "sommelier-ctx.h" // NOLINT(build/include_directory)
#include "sommelier-transform.h" // NOLINT(build/include_directory)
#include "testing/x11-test-base.h"

namespace vm_tools {
namespace sommelier {

using TransformDirectScaleTest = X11DirectScaleTest;

class TransformTest : public ::testing::Test {
public:
void SetUp() override {
Expand Down Expand Up @@ -478,16 +481,43 @@ TEST_F(TransformTest, GuestToHostFixedCoord_UnscaledWithDirectScale) {
EXPECT_EQ(wl_fixed_to_double(coord), 16.0);
}

TEST_F(TransformTest, GuestToHostFixedCoord_ScaledWithDirectScale) {
TEST_F(TransformDirectScaleTest, Pointer_WithViewportOverride) {
ctx.viewport_resize = true;
sl_window* window = CreateToplevelWindow();
window->viewport_override = true;
window->viewport_pointer_scale = 1.1;
sl_host_surface* surface = window->paired_surface;
surface->has_own_scale = true;
surface->xdg_scale_x = 0.9;
surface->xdg_scale_y = 1.6;

wl_fixed_t x = wl_fixed_from_double(16.0);
wl_fixed_t y = wl_fixed_from_double(16.0);

sl_transform_pointer(&ctx, surface, &x, &y);

EXPECT_EQ(x, wl_fixed_from_double(0.9 * 16 * 1.1));
EXPECT_EQ(y, wl_fixed_from_double(1.6 * 16 * 1.1));
}

TEST_F(TransformDirectScaleTest, Pointer_WithoutViewportOverride) {
ctx.viewport_resize = true;
sl_window* window = CreateToplevelWindow();
window->viewport_override = false;
window->viewport_pointer_scale = 0.9;
sl_host_surface* surface = window->paired_surface;
ctx.use_direct_scale = true;
fake_surface.has_own_scale = true;
fake_surface.xdg_scale_y = 1.6;
surface->has_own_scale = true;
surface->xdg_scale_x = 0.9;
surface->xdg_scale_y = 1.6;

wl_fixed_t coord = wl_fixed_from_double(26.0);
wl_fixed_t x = wl_fixed_from_double(16.0);
wl_fixed_t y = wl_fixed_from_double(16.0);

sl_transform_guest_to_host_fixed(&ctx, &fake_surface, &coord, 0u);
sl_transform_pointer(&ctx, surface, &x, &y);

EXPECT_EQ(coord, wl_fixed_from_double(26 / 1.6));
EXPECT_EQ(x, wl_fixed_from_double(0.9 * 16));
EXPECT_EQ(y, wl_fixed_from_double(1.6 * 16));
}
} // namespace sommelier
} // namespace vm_tools
20 changes: 19 additions & 1 deletion sommelier-transform.cc
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,10 @@ bool sl_transform_viewport_scale(struct sl_context* ctx,
// when the virtual and logical space match.
bool do_viewport = true;

if (ctx->use_direct_scale) {
if (surface && surface->window && surface->window->viewport_override) {
*width = surface->window->viewport_width;
*height = surface->window->viewport_height;
} else if (ctx->use_direct_scale) {
sl_transform_direct_to_host(ctx, surface, width, height);

// For very small windows (in pixels), the resulting logical dimensions
Expand Down Expand Up @@ -294,6 +297,21 @@ void sl_transform_host_to_guest_fixed(struct sl_context* ctx,
}
}

void sl_transform_pointer(struct sl_context* ctx,
struct sl_host_surface* surface,
wl_fixed_t* x,
wl_fixed_t* y) {
sl_transform_host_to_guest_fixed(ctx, surface, x, y);
if (surface && surface->window && surface->window->viewport_override) {
double dx = wl_fixed_to_double(*x);
double dy = wl_fixed_to_double(*y);
dx *= surface->window->viewport_pointer_scale;
dy *= surface->window->viewport_pointer_scale;
*x = wl_fixed_from_double(dx);
*y = wl_fixed_from_double(dy);
}
}

void sl_transform_host_to_guest_fixed(struct sl_context* ctx,
struct sl_host_surface* surface,
wl_fixed_t* coord,
Expand Down
6 changes: 6 additions & 0 deletions sommelier-transform.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,10 @@ void sl_transform_output_dimensions(struct sl_context* ctx,
int32_t* width,
int32_t* height);

// Used to transform pointer coordinates from host to guest.
void sl_transform_pointer(struct sl_context* ctx,
struct sl_host_surface* surface,
wl_fixed_t* x,
wl_fixed_t* y);

#endif // VM_TOOLS_SOMMELIER_SOMMELIER_TRANSFORM_H_
215 changes: 215 additions & 0 deletions sommelier-window-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "mock-viewporter-shim.h" // NOLINT(build/include_directory)
#include "testing/x11-test-base.h"

#include <gmock/gmock.h>
Expand All @@ -23,6 +24,220 @@ using ::testing::PrintToString;

using X11Test = X11TestBase;

TEST_F(X11DirectScaleTest, ViewportOverrideStretchedVertically) {
// Arrange
ctx.viewport_resize = true;
AdvertiseOutputs(xwayland.get(),
{{.logical_width = 1536, .logical_height = 864}});
sl_window* window = CreateToplevelWindow();
const int pixel_width = 1920;
const int pixel_height = 1080;
window->managed = true;
window->max_width = pixel_width;
window->min_height = pixel_height;
window->min_width = pixel_width;
window->max_height = pixel_height;
window->width = pixel_width;
window->height = pixel_height;
window->paired_surface->contents_width = pixel_width;
window->paired_surface->contents_height = pixel_height;
wl_array states;
wl_array_init(&states);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, 1393, 784))
.Times(1);

// Act: Configure with height smaller than min_height.
HostEventHandler(window->xdg_toplevel)
->configure(nullptr, window->xdg_toplevel, 1536 /*1920*/, 784 /*980*/,
&states);
HostEventHandler(window->xdg_surface)
->configure(nullptr, window->xdg_surface, 123);
sl_host_surface_commit(nullptr, window->paired_surface->resource);
Pump();

// Assert: viewport size and pointer scale are set, width height are
// unchanged.
EXPECT_TRUE(window->viewport_override);
EXPECT_EQ(window->viewport_width, 1393);
EXPECT_EQ(window->viewport_height, 784);
EXPECT_FLOAT_EQ(window->viewport_pointer_scale, 1.1026561);
EXPECT_EQ(window->width, 1920);
EXPECT_EQ(window->height, 1080);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, -1, -1))
// Act: Configure with the size that is within the window bounds.
.Times(1);
HostEventHandler(window->xdg_toplevel)
->configure(nullptr, window->xdg_toplevel, 1536, 864, &states);
HostEventHandler(window->xdg_surface)
->configure(nullptr, window->xdg_surface, 124);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, 1536, 864))
.Times(1);

// Act
sl_host_surface_commit(nullptr, window->paired_surface->resource);
Pump();

// Assert: viewport override is no longer used.
EXPECT_FALSE(window->viewport_override);
EXPECT_EQ(window->viewport_width, -1);
EXPECT_EQ(window->viewport_height, -1);
EXPECT_EQ(window->width, pixel_width);
EXPECT_EQ(window->height, pixel_height);
}

TEST_F(X11DirectScaleTest, ViewportOverrideStretchedHorizontally) {
// Arrange
ctx.viewport_resize = true;
AdvertiseOutputs(xwayland.get(),
{{.logical_width = 1536, .logical_height = 864}});
sl_window* window = CreateToplevelWindow();
window->managed = true;
window->max_width = 1700;
window->max_height = 900;
window->min_width = 1600;
window->min_height = 800;
window->width = 1650;
window->height = 800;
window->paired_surface->contents_width = 1650;
window->paired_surface->contents_height = 800;
wl_array states;
wl_array_init(&states);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, 1200, 581))
.Times(1);

// Act: Height is set to equal to max height, width smaller than min
// width.
HostEventHandler(window->xdg_toplevel)
->configure(nullptr, window->xdg_toplevel, 1200 /*1500*/, 720 /*900*/,
&states);
HostEventHandler(window->xdg_surface)
->configure(nullptr, window->xdg_surface, 123);
sl_host_surface_commit(nullptr, window->paired_surface->resource);
Pump();

// Assert: viewport size and pointer scale are set, width height are
// unchanged.
EXPECT_TRUE(window->viewport_override);
EXPECT_EQ(window->viewport_width, 1200);
EXPECT_EQ(window->viewport_height, 581);
EXPECT_FLOAT_EQ(window->viewport_pointer_scale, 1.1);
EXPECT_EQ(window->width, 1650);
EXPECT_EQ(window->height, 800);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, -1, -1))
.Times(1);

// Act: Configure with the size that is within the window bounds.
HostEventHandler(window->xdg_toplevel)
->configure(nullptr, window->xdg_toplevel, 1360 /*1700*/, 680 /*850*/,
&states);
HostEventHandler(window->xdg_surface)
->configure(nullptr, window->xdg_surface, 124);
window->paired_surface->contents_width = 1700;
window->paired_surface->contents_height = 850;

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, 1360, 680))
.Times(1);

// Act
sl_host_surface_commit(nullptr, window->paired_surface->resource);
Pump();

// Assert: viewport override is no longer used.
EXPECT_FALSE(window->viewport_override);
EXPECT_EQ(window->viewport_width, -1);
EXPECT_EQ(window->viewport_height, -1);
EXPECT_EQ(window->width, 1700);
EXPECT_EQ(window->height, 850);
}

TEST_F(X11DirectScaleTest, ViewportOverrideSameAspectRatio) {
// Arrange
ctx.viewport_resize = true;
AdvertiseOutputs(xwayland.get(),
{{.logical_width = 1536, .logical_height = 864}});
sl_window* window = CreateToplevelWindow();
window->managed = true;
const int pixel_width = 1920;
const int pixel_height = 1080;
window->max_width = pixel_width;
window->min_height = pixel_height;
window->min_width = pixel_width;
window->max_height = pixel_height;
window->paired_surface->contents_width = pixel_width;
window->paired_surface->contents_height = pixel_height;
window->width = pixel_width;
window->height = pixel_height;
wl_array states;
wl_array_init(&states);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, 1280, 720))
.Times(1);

// Act: Height and width squished while maintaining aspect ratio.
HostEventHandler(window->xdg_toplevel)
->configure(nullptr, window->xdg_toplevel, 1280 /*1600*/, 720 /*900*/,
&states);
HostEventHandler(window->xdg_surface)
->configure(nullptr, window->xdg_surface, 123);
sl_host_surface_commit(nullptr, window->paired_surface->resource);
Pump();

// Assert: viewport size and pointer scale are set, width height are
// unchanged.
EXPECT_TRUE(window->viewport_override);
EXPECT_EQ(window->viewport_width, 1280);
EXPECT_EQ(window->viewport_height, 720);
EXPECT_FLOAT_EQ(window->viewport_pointer_scale, 1.2);
EXPECT_EQ(window->width, pixel_width);
EXPECT_EQ(window->height, pixel_height);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, -1, -1))
.Times(1);

// Act: Configure with the size that is within the window bounds.
HostEventHandler(window->xdg_toplevel)
->configure(nullptr, window->xdg_toplevel, 1536, 864, &states);
HostEventHandler(window->xdg_surface)
->configure(nullptr, window->xdg_surface, 123);

// Assert
EXPECT_CALL(mock_viewport_shim_,
set_destination(window->paired_surface->viewport, 1536, 864))
.Times(1);

// Act
sl_host_surface_commit(nullptr, window->paired_surface->resource);
Pump();

// Assert: viewport override is no longer used.
EXPECT_FALSE(window->viewport_override);
EXPECT_EQ(window->viewport_width, -1);
EXPECT_EQ(window->viewport_height, -1);
EXPECT_EQ(window->width, 1920);
EXPECT_EQ(window->height, 1080);
}

TEST_F(X11Test, TogglesFullscreenOnWmStateFullscreen) {
// Arrange: Create an xdg_toplevel surface. Initially it's not fullscreen.
AdvertiseOutputs(xwayland.get(), {OutputConfig()});
Expand Down
Loading

0 comments on commit 8ce185a

Please sign in to comment.