diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 20dfb3e1dde..94a5a3a4bd4 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -282,6 +282,7 @@ struct dri2_egl_display { struct wl_shm *wl_shm; struct wl_event_queue *wl_queue; struct zwp_linux_dmabuf_v1 *wl_dmabuf; + struct wp_presentation *wp_presentation; struct dri2_wl_formats formats; struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; struct dmabuf_feedback_format_table format_table; @@ -289,6 +290,7 @@ struct dri2_egl_display { uint32_t capabilities; char *device_name; bool is_render_node; + clockid_t presentation_clock_id; #endif #ifdef HAVE_ANDROID_PLATFORM @@ -331,6 +333,7 @@ struct dri2_egl_surface { struct wl_callback *throttle_callback; struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback; + struct loader_wayland_presentation wayland_presentation; bool compositor_using_another_device; int format; bool resized; diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index aa2f61ab122..47fd8bcd692 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -42,6 +42,7 @@ #include #include "util/anon_file.h" +#include "util/perf/cpu_trace.h" #include "util/u_vector.h" #include "util/format/u_formats.h" #include "main/glconfig.h" @@ -762,6 +763,15 @@ dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, goto cleanup_dpy_wrapper; } + if (dri2_dpy->wp_presentation) { + loader_wayland_wrap_presentation(&dri2_surf->wayland_presentation, + dri2_dpy->wp_presentation, + dri2_surf->wl_queue, + dri2_dpy->presentation_clock_id, + &dri2_surf->wayland_surface, + NULL, NULL, NULL); + } + if (dri2_dpy->wl_dmabuf && zwp_linux_dmabuf_v1_get_version(dri2_dpy->wl_dmabuf) >= ZWP_LINUX_DMABUF_V1_GET_SURFACE_FEEDBACK_SINCE_VERSION) { @@ -874,6 +884,8 @@ dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) dri2_surf->wl_win->destroy_window_callback = NULL; } + loader_wayland_presentation_destroy(&dri2_surf->wayland_presentation); + loader_wayland_surface_destroy(&dri2_surf->wayland_surface); wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper); if (dri2_surf->wl_drm_wrapper) @@ -1182,7 +1194,8 @@ wait_for_free_buffer(struct dri2_egl_display *dri2_dpy, } static int -get_back_bo(struct dri2_egl_surface *dri2_surf) +get_back_bo(struct dri2_egl_surface *dri2_surf, + struct mesa_trace_flow *flow) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); @@ -1191,6 +1204,8 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) unsigned int pipe_format; unsigned int linear_pipe_format; + MESA_TRACE_FUNC_FLOW(flow); + visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); assert(visual_idx != -1); pipe_format = dri2_wl_visuals[visual_idx].pipe_format; @@ -1355,6 +1370,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) if (dri2_surf->back->dri_image == NULL) return -1; + loader_wayland_buffer_set_flow(&dri2_surf->back->wayland_buffer, flow); dri2_surf->back->locked = true; return 0; @@ -1385,11 +1401,14 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) #define BUFFER_TRIM_AGE_HYSTERESIS 20 static int -update_buffers(struct dri2_egl_surface *dri2_surf) +update_buffers(struct dri2_egl_surface *dri2_surf, + struct mesa_trace_flow *flow) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); + MESA_TRACE_FUNC_FLOW(flow); + if (dri2_surf->wl_win && (dri2_surf->base.Width != dri2_surf->wl_win->width || dri2_surf->base.Height != dri2_surf->wl_win->height)) { @@ -1406,7 +1425,7 @@ update_buffers(struct dri2_egl_surface *dri2_surf) dri2_surf->received_dmabuf_feedback = false; } - if (get_back_bo(dri2_surf) < 0) { + if (get_back_bo(dri2_surf, flow) < 0) { _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); return -1; } @@ -1436,12 +1455,15 @@ update_buffers(struct dri2_egl_surface *dri2_surf) } static int -update_buffers_if_needed(struct dri2_egl_surface *dri2_surf) +update_buffers_if_needed(struct dri2_egl_surface *dri2_surf, + struct mesa_trace_flow *flow) { + MESA_TRACE_FUNC_FLOW(flow); + if (dri2_surf->back != NULL) return 0; - return update_buffers(dri2_surf); + return update_buffers(dri2_surf, flow); } static int @@ -1450,8 +1472,11 @@ image_get_buffers(struct dri_drawable *driDrawable, unsigned int format, struct __DRIimageList *buffers) { struct dri2_egl_surface *dri2_surf = loaderPrivate; + struct mesa_trace_flow flow = {0}; - if (update_buffers_if_needed(dri2_surf) < 0) + MESA_TRACE_FUNC_FLOW(&flow); + + if (update_buffers_if_needed(dri2_surf, &flow) < 0) return 0; buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; @@ -1683,10 +1708,16 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw, { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + struct mesa_trace_flow flow = { 0 }; if (!dri2_surf->wl_win) return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers"); + if (dri2_surf->back) + flow = dri2_surf->back->wayland_buffer.flow; + + MESA_TRACE_FUNC_FLOW(&flow); + /* Flush (and finish glthread) before: * - update_buffers_if_needed because the unmarshalling thread * may be running currently, and we would concurrently alloc/free @@ -1709,7 +1740,7 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw, /* Make sure we have a back buffer in case we're swapping without ever * rendering. */ - if (update_buffers_if_needed(dri2_surf) < 0) + if (update_buffers_if_needed(dri2_surf, &flow) < 0) return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); if (draw->SwapInterval > 0) { @@ -1742,6 +1773,8 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw, wl_buffer_add_listener(dri2_surf->current->wayland_buffer.buffer, &wl_buffer_listener, dri2_surf); + + loader_wayland_buffer_set_flow(&dri2_surf->current->wayland_buffer, &flow); } wl_surface_attach(dri2_surf->wayland_surface.wrapper, @@ -1774,6 +1807,10 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw, dri_flush_drawable(dri_drawable); } + loader_wayland_presentation_feedback(&dri2_surf->wayland_presentation, + &dri2_surf->current->wayland_buffer, + NULL); + wl_surface_commit(dri2_surf->wayland_surface.wrapper); /* If we're not waiting for a frame callback then we'll at least throttle @@ -1795,8 +1832,11 @@ static EGLint dri2_wl_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface) { struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); + struct mesa_trace_flow flow = { 0 }; - if (update_buffers_if_needed(dri2_surf) < 0) { + MESA_TRACE_FUNC_FLOW(&flow); + + if (update_buffers_if_needed(dri2_surf, &flow) < 0) { _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); return -1; } @@ -2106,6 +2146,18 @@ static const struct zwp_linux_dmabuf_feedback_v1_listener .done = default_dmabuf_feedback_done, }; +static void +presentation_handle_clock_id(void* data, struct wp_presentation *wp_presentation, uint32_t clk_id) +{ + struct dri2_egl_display *dri2_dpy = data; + + dri2_dpy->presentation_clock_id = clk_id; +} + +static const struct wp_presentation_listener presentation_listener = { + presentation_handle_clock_id, +}; + static void registry_handle_global_drm(void *data, struct wl_registry *registry, uint32_t name, const char *interface, @@ -2123,6 +2175,11 @@ registry_handle_global_drm(void *data, struct wl_registry *registry, MIN2(version, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION)); zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener, dri2_dpy); + } else if (strcmp(interface, wp_presentation_interface.name) == 0) { + dri2_dpy->wp_presentation = + wl_registry_bind(registry, name, &wp_presentation_interface, 1); + wp_presentation_add_listener(dri2_dpy->wp_presentation, + &presentation_listener, dri2_dpy); } } @@ -2867,7 +2924,13 @@ registry_handle_global_kopper(void *data, struct wl_registry *registry, ZWP_LINUX_DMABUF_V1_GET_DEFAULT_FEEDBACK_SINCE_VERSION)); zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener, dri2_dpy); + } else if (strcmp(interface, wp_presentation_interface.name) == 0) { + dri2_dpy->wp_presentation = + wl_registry_bind(registry, name, &wp_presentation_interface, 1); + wp_presentation_add_listener(dri2_dpy->wp_presentation, + &presentation_listener, dri2_dpy); } + } static const struct wl_registry_listener registry_listener_kopper = { @@ -2885,7 +2948,13 @@ registry_handle_global_swrast(void *data, struct wl_registry *registry, if (strcmp(interface, wl_shm_interface.name) == 0) { dri2_dpy->wl_shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy); + } else if (strcmp(interface, wp_presentation_interface.name) == 0) { + dri2_dpy->wp_presentation = + wl_registry_bind(registry, name, &wp_presentation_interface, 1); + wp_presentation_add_listener(dri2_dpy->wp_presentation, + &presentation_listener, dri2_dpy); } + } static const struct wl_registry_listener registry_listener_swrast = { @@ -3132,6 +3201,8 @@ void dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy) { dri2_wl_formats_fini(&dri2_dpy->formats); + if (dri2_dpy->wp_presentation) + wp_presentation_destroy(dri2_dpy->wp_presentation); if (dri2_dpy->wl_drm) wl_drm_destroy(dri2_dpy->wl_drm); if (dri2_dpy->wl_dmabuf)