/* * Copyright © 2025 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. */ #include "config.h" #include "pixel-formats.h" #include "shared/weston-drm-fourcc.h" #include "shared/xalloc.h" #include "weston-test-client-helper.h" #include "weston-test-assert.h" #include "xdg-client-helper.h" struct setup_args { struct fixture_metadata meta; enum weston_renderer_type renderer; }; static const struct setup_args my_setup_args[] = { { .meta.name = "GL", .renderer = WESTON_RENDERER_GL, }, { .meta.name = "Vulkan", .renderer = WESTON_RENDERER_VULKAN, }, }; static enum test_result_code fixture_setup(struct weston_test_harness *harness, const struct setup_args *arg) { struct compositor_setup setup; compositor_setup_defaults(&setup); setup.backend = WESTON_BACKEND_DRM; setup.renderer = arg->renderer; setup.logging_scopes = "log,drm-backend"; setup.width = 1024; setup.height = 768; return weston_test_harness_execute_as_client(harness, &setup); } DECLARE_FIXTURE_SETUP_WITH_ARG(fixture_setup, my_setup_args, meta); static void buffer_release(void *data, struct wl_buffer *wl_buffer) { struct client_buffer *buffer = data; client_buffer_util_destroy_buffer(buffer); } static const struct wl_buffer_listener buffer_listener = { buffer_release }; enum feedback_result { FB_PENDING = 0, FB_PRESENTED, FB_PRESENTED_ZERO_COPY, FB_DISCARDED }; static void presentation_feedback_handle_sync_output(void *data, struct wp_presentation_feedback *feedback, struct wl_output *output) { } static void presentation_feedback_handle_presented(void *data, struct wp_presentation_feedback *feedback, uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec, uint32_t refresh, uint32_t seq_hi, uint32_t seq_lo, uint32_t flags) { enum feedback_result *result = data; bool zero_copy = flags & WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY; if (zero_copy) *result = FB_PRESENTED_ZERO_COPY; else *result = FB_PRESENTED; wp_presentation_feedback_destroy(feedback); } static void presentation_feedback_handle_discarded(void *data, struct wp_presentation_feedback *feedback) { enum feedback_result *result = data; *result = FB_DISCARDED; wp_presentation_feedback_destroy(feedback); } static const struct wp_presentation_feedback_listener presentation_feedback_listener = { .sync_output = presentation_feedback_handle_sync_output, .presented = presentation_feedback_handle_presented, .discarded = presentation_feedback_handle_discarded, }; static void presentation_wait_nofail(struct client *client, enum feedback_result *result) { while (*result == FB_PENDING) { if (wl_display_dispatch(client->wl_display) < 0) test_assert_not_reached("Connection error"); } } static void overlay_buffer_release(void *data, struct wl_buffer *buffer) { wl_buffer_destroy(buffer); } static const struct wl_buffer_listener overlay_buffer_listener = { overlay_buffer_release }; /* * All following tests assume the vkms default configuration of a single * 1024x768 pixel output with a primary plane and one cursor plane (limited to * 512x512 pixels). */ /* * Test that a fullscreen client with fullscreen-sized buffer is presented via * direct-scanout. */ TEST(drm_offload_fullscreen) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct client_buffer *buffer; struct wl_surface *surface; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, xdg_surface->configure.width, xdg_surface->configure.height); wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(surface, buffer->wl_buffer, 0, 0); wl_surface_damage(surface, 0, 0, INT32_MAX, INT32_MAX); xdg_surface_maybe_ack_configure(xdg_surface); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED_ZERO_COPY); client_buffer_util_destroy_buffer(buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a fullscreen client with fullscreen-sized buffer and a fully * transparent overlay surface is presented via direct-scanout. */ TEST(drm_offload_fullscreen_transparent_overlay) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct client_buffer *buffer; struct wl_surface *surface; struct wl_surface *overlay_surface; struct wl_subsurface *overlay_subsurface; struct wl_buffer *overlay_buffer; struct wp_viewport *overlay_viewport; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, xdg_surface->configure.width, xdg_surface->configure.height); wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(surface, buffer->wl_buffer, 0, 0); wl_surface_damage(surface, 0, 0, INT32_MAX, INT32_MAX); xdg_surface_maybe_ack_configure(xdg_surface); overlay_surface = wl_compositor_create_surface(client->wl_compositor); overlay_subsurface = wl_subcompositor_get_subsurface(client->wl_subcompositor, overlay_surface, surface); overlay_viewport = wp_viewporter_get_viewport(client->viewporter, overlay_surface); wp_viewport_set_destination(overlay_viewport, 100, 100); overlay_buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager, 0x0, 0x0, 0x0, 0x0); wl_surface_attach(overlay_surface, overlay_buffer, 0, 0); wl_buffer_add_listener(overlay_buffer, &overlay_buffer_listener, NULL); wl_surface_damage_buffer(overlay_surface, 0, 0, 1, 1); wl_surface_commit(overlay_surface); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED_ZERO_COPY); wp_viewport_destroy(overlay_viewport); wl_subsurface_destroy(overlay_subsurface); wl_surface_destroy(overlay_surface); client_buffer_util_destroy_buffer(buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a fullscreen client with smaller-than-fullscreen-sized buffer is * presented via direct-scanout. */ TEST(drm_offload_fullscreen_black_background) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct client_buffer *buffer; struct wl_surface *surface; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, xdg_surface->configure.width - 100, xdg_surface->configure.height - 100); wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(surface, buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX); xdg_surface_maybe_ack_configure(xdg_surface); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED_ZERO_COPY); client_buffer_util_destroy_buffer(buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a fullscreen client with opaque-black single-pixel-buffer with a * smaller-than-fullscreen-sized dmabuf subsurface above is presented via * direct-scanout. */ TEST(drm_offload_fullscreen_semi_transparent_black_background) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct wl_buffer *buffer; struct wl_surface *surface; struct wl_surface *overlay_surface; struct wl_subsurface *overlay_subsurface; struct client_buffer *overlay_buffer; struct wp_viewport *viewport; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_ARGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); viewport = wp_viewporter_get_viewport(client->viewporter, surface); wp_viewport_set_destination(viewport, xdg_surface->configure.width, xdg_surface->configure.height); buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager, 0x0, 0x0, 0x0, 0xffffffff); wl_surface_attach(surface, buffer, 0, 0); wl_buffer_add_listener(buffer, &overlay_buffer_listener, NULL); wl_surface_damage_buffer(surface, 0, 0, 1, 1); xdg_surface_maybe_ack_configure(xdg_surface); overlay_surface = wl_compositor_create_surface(client->wl_compositor); overlay_subsurface = wl_subcompositor_get_subsurface(client->wl_subcompositor, overlay_surface, surface); overlay_buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, 100, 100); wl_buffer_add_listener(overlay_buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(overlay_surface, overlay_buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(overlay_surface, 0, 0, INT32_MAX, INT32_MAX); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, overlay_surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(overlay_surface); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED_ZERO_COPY); wp_viewport_destroy(viewport); wl_subsurface_destroy(overlay_subsurface); wl_surface_destroy(overlay_surface); client_buffer_util_destroy_buffer(overlay_buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a fullscreen client with opaque-white single-pixel-buffer with a * smaller-than-fullscreen-sized dmabuf subsurface above is *not* presented via * direct-scanout. * * This should be optimized in the future. */ TEST(drm_offload_fullscreen_semi_transparent_white_background) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct wl_buffer *buffer; struct wl_surface *surface; struct wl_surface *overlay_surface; struct wl_subsurface *overlay_subsurface; struct client_buffer *overlay_buffer; struct wp_viewport *viewport; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_ARGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); viewport = wp_viewporter_get_viewport(client->viewporter, surface); wp_viewport_set_destination(viewport, xdg_surface->configure.width, xdg_surface->configure.height); buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff); wl_surface_attach(surface, buffer, 0, 0); wl_buffer_add_listener(buffer, &overlay_buffer_listener, NULL); wl_surface_damage_buffer(surface, 0, 0, 1, 1); xdg_surface_maybe_ack_configure(xdg_surface); overlay_surface = wl_compositor_create_surface(client->wl_compositor); overlay_subsurface = wl_subcompositor_get_subsurface(client->wl_subcompositor, overlay_surface, surface); overlay_buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, 100, 100); wl_buffer_add_listener(overlay_buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(overlay_surface, overlay_buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(overlay_surface, 0, 0, INT32_MAX, INT32_MAX); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, overlay_surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(overlay_surface); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED); wp_viewport_destroy(viewport); wl_subsurface_destroy(overlay_subsurface); wl_surface_destroy(overlay_surface); client_buffer_util_destroy_buffer(overlay_buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a fullscreen client with smaller-than-fullscreen-sized opaque-black * single-pixel-buffer with an even smaller dmabuf subsurface above is presented * via direct-scanout. */ TEST(drm_offload_fullscreen_black_background_black_subsurface_underlay) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct wl_buffer *buffer; struct wl_surface *surface; struct wl_surface *overlay_surface; struct wl_subsurface *overlay_subsurface; struct client_buffer *overlay_buffer; struct wp_viewport *viewport; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); viewport = wp_viewporter_get_viewport(client->viewporter, surface); wp_viewport_set_destination(viewport, xdg_surface->configure.width - 100, xdg_surface->configure.height - 100); buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager, 0x0, 0x0, 0x0, 0xffffffff); wl_surface_attach(surface, buffer, 0, 0); wl_buffer_add_listener(buffer, &overlay_buffer_listener, NULL); wl_surface_damage_buffer(surface, 0, 0, 1, 1); xdg_surface_maybe_ack_configure(xdg_surface); overlay_surface = wl_compositor_create_surface(client->wl_compositor); overlay_subsurface = wl_subcompositor_get_subsurface(client->wl_subcompositor, overlay_surface, surface); overlay_buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, 100, 100); wl_buffer_add_listener(overlay_buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(overlay_surface, overlay_buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(overlay_surface, 0, 0, INT32_MAX, INT32_MAX); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, overlay_surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(overlay_surface); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED_ZERO_COPY); //TODO: check the spb surface for FB_PRESENTED_ZERO_COPY, too (does not yet work). wp_viewport_destroy(viewport); wl_subsurface_destroy(overlay_subsurface); wl_surface_destroy(overlay_surface); client_buffer_util_destroy_buffer(overlay_buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a fullscreen client with smaller-than-fullscreen-sized buffer * with an overlapping opaque-black single-pixel-buffer subsurface above is * *not* presented via direct-scanout. This test is meant to ensure that future * optimizations for the above tests don't overreach. */ TEST(drm_offload_fullscreen_black_background_black_subsurface_overlay) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct client_buffer *buffer; struct wl_surface *surface; struct wl_surface *overlay_surface; struct wl_subsurface *overlay_subsurface; struct wl_buffer *overlay_buffer; struct wp_viewport *overlay_viewport; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, xdg_surface->configure.width - 100, xdg_surface->configure.height - 100); wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(surface, buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX); xdg_surface_maybe_ack_configure(xdg_surface); overlay_surface = wl_compositor_create_surface(client->wl_compositor); overlay_subsurface = wl_subcompositor_get_subsurface(client->wl_subcompositor, overlay_surface, surface); overlay_viewport = wp_viewporter_get_viewport(client->viewporter, overlay_surface); wp_viewport_set_destination(overlay_viewport, 100, 100); overlay_buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager, 0x0, 0x0, 0x0, 0xffffffff); wl_surface_attach(overlay_surface, overlay_buffer, 0, 0); wl_buffer_add_listener(overlay_buffer, &overlay_buffer_listener, NULL); wl_surface_damage_buffer(overlay_surface, 0, 0, 1, 1); wl_surface_commit(overlay_surface); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED); wp_viewport_destroy(overlay_viewport); wl_subsurface_destroy(overlay_subsurface); wl_surface_destroy(overlay_surface); client_buffer_util_destroy_buffer(buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a fullscreen client with smaller-than-fullscreen-sized opaque-red * single-pixel-buffer with an even smaller dmabuf subsurface above is *not* * presented via direct-scanout. * * This *might* be possible to get optimized in the future once the backend can * support multiple solid color planes, see * https://lore.kernel.org/dri-devel/20231027-solid-fill-v7-0-780188bfa7b2@quicinc.com/ */ TEST(drm_offload_fullscreen_black_background_red_subsurface_underlay) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct wl_buffer *buffer; struct wl_surface *surface; struct wl_surface *overlay_surface; struct wl_subsurface *overlay_subsurface; struct client_buffer *overlay_buffer; struct wp_viewport *viewport; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_toplevel_set_fullscreen(xdg_surface->xdg_toplevel, NULL); xdg_surface_wait_configure(xdg_surface); test_assert_true(xdg_surface->configure.fullscreen); test_assert_int_gt(xdg_surface->configure.width, 0); test_assert_int_gt(xdg_surface->configure.height, 0); viewport = wp_viewporter_get_viewport(client->viewporter, surface); wp_viewport_set_destination(viewport, xdg_surface->configure.width - 100, xdg_surface->configure.height - 100); buffer = wp_single_pixel_buffer_manager_v1_create_u32_rgba_buffer(client->single_pixel_manager, 0xffffffff, 0x0, 0x0, 0xffffffff); wl_surface_attach(surface, buffer, 0, 0); wl_buffer_add_listener(buffer, &overlay_buffer_listener, NULL); wl_surface_damage_buffer(surface, 0, 0, 1, 1); xdg_surface_maybe_ack_configure(xdg_surface); overlay_surface = wl_compositor_create_surface(client->wl_compositor); overlay_subsurface = wl_subcompositor_get_subsurface(client->wl_subcompositor, overlay_surface, surface); overlay_buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, 100, 100); wl_buffer_add_listener(overlay_buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(overlay_surface, overlay_buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(overlay_surface, 0, 0, INT32_MAX, INT32_MAX); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, overlay_surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(overlay_surface); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED); wp_viewport_destroy(viewport); wl_subsurface_destroy(overlay_subsurface); wl_surface_destroy(overlay_surface); client_buffer_util_destroy_buffer(overlay_buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a windowed / not-fullscreen client on top of a solid background is * *not* presented via direct-scanout. * * This should be optimized in the future. */ TEST(drm_offload_windowed) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct client_buffer *buffer; struct wl_surface *surface; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_surface_wait_configure(xdg_surface); test_assert_false(xdg_surface->configure.fullscreen); test_assert_int_eq(xdg_surface->configure.width, 0); test_assert_int_eq(xdg_surface->configure.height, 0); buffer = client_buffer_util_create_dmabuf_buffer(client->wl_display, client->dmabuf, fmt_info, 100, 100); wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(surface, buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX); xdg_surface_maybe_ack_configure(xdg_surface); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED); client_buffer_util_destroy_buffer(buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; } /* * Test that a windowed / not-fullscreen client with a wl_shm buffer is *not* * presented via direct-scanout. This is mainly a sanity check for the tests * above. */ TEST(drm_offload_windowed_shm) { struct xdg_client *xdg_client; struct xdg_surface_data *xdg_surface; struct client *client; struct client_buffer *buffer; struct wl_surface *surface; const struct pixel_format_info *fmt_info; struct wp_presentation_feedback *presentation_feedback; enum feedback_result result; fmt_info = pixel_format_get_info(DRM_FORMAT_XRGB8888); xdg_client = create_xdg_client(); client = xdg_client->client; xdg_surface = create_xdg_surface(xdg_client); surface = xdg_surface->surface->wl_surface; xdg_surface_make_toplevel(xdg_surface, "weston.test.drm-offload", "one"); xdg_surface_wait_configure(xdg_surface); test_assert_false(xdg_surface->configure.fullscreen); test_assert_int_eq(xdg_surface->configure.width, 0); test_assert_int_eq(xdg_surface->configure.height, 0); buffer = client_buffer_util_create_shm_buffer(client->wl_shm, fmt_info, 100, 100); wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer); wl_surface_attach(surface, buffer->wl_buffer, 0, 0); wl_surface_damage_buffer(surface, 0, 0, INT32_MAX, INT32_MAX); xdg_surface_maybe_ack_configure(xdg_surface); result = FB_PENDING; presentation_feedback = wp_presentation_feedback(client->presentation, surface); wp_presentation_feedback_add_listener(presentation_feedback, &presentation_feedback_listener, &result); wl_surface_commit(surface); presentation_wait_nofail(client, &result); test_assert_enum(result, FB_PRESENTED); client_buffer_util_destroy_buffer(buffer); destroy_xdg_surface(xdg_surface); xdg_client_destroy(xdg_client); return RESULT_OK; }