mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-02 03:38:06 +02:00
Add a thin wrapper around the wayland dispatch code for no reason other than to add MESA_TRACE_FUNC so we can see where wayland dispatch delays are. Move this to loader so we can use it in the wayland egl code later. Signed-off-by: Derek Foreman <derek.foreman@collabora.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28634>
165 lines
5 KiB
C
165 lines
5 KiB
C
/*
|
|
* Copyright © 2022 Red Hat, Inc.
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting documentation, and
|
|
* that the name of the copyright holders not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. The copyright holders make no representations
|
|
* about the suitability of this software for any purpose. It is provided "as
|
|
* is" without express or implied warranty.
|
|
*
|
|
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
* OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <poll.h>
|
|
#include <errno.h>
|
|
|
|
#include "util/perf/cpu_trace.h"
|
|
|
|
#include "loader_wayland_helper.h"
|
|
|
|
#ifndef HAVE_WL_DISPATCH_QUEUE_TIMEOUT
|
|
static int
|
|
wl_display_poll(struct wl_display *display,
|
|
short int events,
|
|
const struct timespec *timeout)
|
|
{
|
|
int ret;
|
|
struct pollfd pfd[1];
|
|
struct timespec now;
|
|
struct timespec deadline = {0};
|
|
struct timespec result;
|
|
struct timespec *remaining_timeout = NULL;
|
|
|
|
if (timeout) {
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
timespec_add(&deadline, &now, timeout);
|
|
}
|
|
|
|
pfd[0].fd = wl_display_get_fd(display);
|
|
pfd[0].events = events;
|
|
do {
|
|
if (timeout) {
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
timespec_sub_saturate(&result, &deadline, &now);
|
|
remaining_timeout = &result;
|
|
}
|
|
ret = ppoll(pfd, 1, remaining_timeout, NULL);
|
|
} while (ret == -1 && errno == EINTR);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
wl_display_dispatch_queue_timeout(struct wl_display *display,
|
|
struct wl_event_queue *queue,
|
|
const struct timespec *timeout)
|
|
{
|
|
int ret;
|
|
struct timespec now;
|
|
struct timespec deadline = {0};
|
|
struct timespec result;
|
|
struct timespec *remaining_timeout = NULL;
|
|
|
|
if (timeout) {
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
timespec_add(&deadline, &now, timeout);
|
|
}
|
|
|
|
if (wl_display_prepare_read_queue(display, queue) == -1)
|
|
return wl_display_dispatch_queue_pending(display, queue);
|
|
|
|
while (true) {
|
|
ret = wl_display_flush(display);
|
|
|
|
if (ret != -1 || errno != EAGAIN)
|
|
break;
|
|
|
|
if (timeout) {
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
timespec_sub_saturate(&result, &deadline, &now);
|
|
remaining_timeout = &result;
|
|
}
|
|
ret = wl_display_poll(display, POLLOUT, remaining_timeout);
|
|
|
|
if (ret <= 0) {
|
|
wl_display_cancel_read(display);
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* Don't stop if flushing hits an EPIPE; continue so we can read any
|
|
* protocol error that may have triggered it. */
|
|
if (ret < 0 && errno != EPIPE) {
|
|
wl_display_cancel_read(display);
|
|
return -1;
|
|
}
|
|
|
|
while (true) {
|
|
if (timeout) {
|
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
timespec_sub_saturate(&result, &deadline, &now);
|
|
remaining_timeout = &result;
|
|
}
|
|
|
|
ret = wl_display_poll(display, POLLIN, remaining_timeout);
|
|
if (ret <= 0) {
|
|
wl_display_cancel_read(display);
|
|
break;
|
|
}
|
|
|
|
ret = wl_display_read_events(display);
|
|
if (ret == -1)
|
|
break;
|
|
|
|
ret = wl_display_dispatch_queue_pending(display, queue);
|
|
if (ret != 0)
|
|
break;
|
|
|
|
/* wl_display_dispatch_queue_pending can return 0 if we ended up reading
|
|
* from WL fd, but there was no complete event to dispatch yet.
|
|
* Try reading again. */
|
|
if (wl_display_prepare_read_queue(display, queue) == -1)
|
|
return wl_display_dispatch_queue_pending(display, queue);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
#ifndef HAVE_WL_CREATE_QUEUE_WITH_NAME
|
|
struct wl_event_queue *
|
|
wl_display_create_queue_with_name(struct wl_display *display, const char *name)
|
|
{
|
|
return wl_display_create_queue(display);
|
|
}
|
|
#endif
|
|
|
|
int
|
|
loader_wayland_dispatch(struct wl_display *wl_display,
|
|
struct wl_event_queue *queue,
|
|
struct timespec *end_time)
|
|
{
|
|
struct timespec current_time;
|
|
struct timespec remaining_timeout;
|
|
|
|
MESA_TRACE_FUNC();
|
|
|
|
if (!end_time)
|
|
return wl_display_dispatch_queue(wl_display, queue);
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, ¤t_time);
|
|
timespec_sub_saturate(&remaining_timeout, end_time, ¤t_time);
|
|
return wl_display_dispatch_queue_timeout(wl_display,
|
|
queue,
|
|
&remaining_timeout);
|
|
}
|