2011-02-04 11:39:40 +00:00
|
|
|
|
/*
|
2012-12-14 04:30:45 +00:00
|
|
|
|
* Copyright © 2011-2012 Intel Corporation
|
2015-05-01 10:11:20 +01:00
|
|
|
|
* Copyright © 2012 Collabora, Ltd.
|
2011-02-04 11:39:40 +00:00
|
|
|
|
*
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* Kristian Høgsberg <krh@bitplanet.net>
|
|
|
|
|
* Benjamin Franzke <benjaminfranzke@googlemail.com>
|
|
|
|
|
*/
|
|
|
|
|
|
2015-02-28 17:12:40 +00:00
|
|
|
|
#include <stdint.h>
|
2011-02-04 11:39:40 +00:00
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <unistd.h>
|
2011-04-14 15:42:41 +01:00
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <xf86drm.h>
|
2015-05-01 10:11:20 +01:00
|
|
|
|
#include <sys/mman.h>
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
#include "egl_dri2.h"
|
2014-01-28 20:34:19 +00:00
|
|
|
|
#include "egl_dri2_fallbacks.h"
|
2014-01-11 04:52:48 +00:00
|
|
|
|
#include "loader.h"
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#include <wayland-client.h>
|
|
|
|
|
#include "wayland-drm-client-protocol.h"
|
|
|
|
|
|
2011-08-31 21:45:04 +01:00
|
|
|
|
enum wl_drm_format_flags {
|
2012-01-11 19:23:24 +00:00
|
|
|
|
HAS_ARGB8888 = 1,
|
2013-10-16 02:10:12 +01:00
|
|
|
|
HAS_XRGB8888 = 2,
|
|
|
|
|
HAS_RGB565 = 4,
|
2011-08-31 21:45:04 +01:00
|
|
|
|
};
|
|
|
|
|
|
2014-01-28 00:42:10 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_wl_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
|
|
|
|
|
EGLint interval);
|
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
static int
|
|
|
|
|
roundtrip(struct dri2_egl_display *dri2_dpy)
|
|
|
|
|
{
|
2017-05-05 14:44:20 +01:00
|
|
|
|
return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-05-06 18:13:29 +01:00
|
|
|
|
static void
|
|
|
|
|
wl_buffer_release(void *data, struct wl_buffer *buffer)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = data;
|
|
|
|
|
int i;
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
|
|
|
|
|
if (dri2_surf->color_buffers[i].wl_buffer == buffer)
|
2011-05-06 18:13:29 +01:00
|
|
|
|
break;
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
|
|
|
|
|
wl_buffer_destroy(buffer);
|
2011-05-06 18:13:29 +01:00
|
|
|
|
return;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].locked = 0;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 12:24:11 +01:00
|
|
|
|
static const struct wl_buffer_listener wl_buffer_listener = {
|
|
|
|
|
.release = wl_buffer_release
|
2011-05-06 18:13:29 +01:00
|
|
|
|
};
|
2011-02-11 01:23:14 +00:00
|
|
|
|
|
2012-11-30 15:41:02 +00:00
|
|
|
|
static void
|
|
|
|
|
resize_callback(struct wl_egl_window *wl_win, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = data;
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
|
2015-11-25 05:27:02 +00:00
|
|
|
|
dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
|
2012-11-30 15:41:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-24 09:48:11 +01:00
|
|
|
|
static void
|
|
|
|
|
destroy_window_callback(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = data;
|
|
|
|
|
dri2_surf->wl_win = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
|
|
|
|
|
*/
|
|
|
|
|
static _EGLSurface *
|
2016-11-28 18:25:19 +00:00
|
|
|
|
dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
|
|
|
|
|
_EGLConfig *conf, void *native_window,
|
|
|
|
|
const EGLint *attrib_list)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
2016-11-28 18:25:19 +00:00
|
|
|
|
__DRIcreateNewDrawableFunc createNewDrawable;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
|
egl/main: Stop using EGLNative types internally
Internally, much of the EGL code uses EGLNativeDisplayType,
EGLNativeWindowType, and EGLPixmapType. However, the EGLNative type
often does not match the variable's actual type.
The concept of EGLNative types are a bad match for Linux, as explained
below. And the EGL platform extensions don't use EGLNative types at all.
Those extensions attempt to solve cross-platform issues by moving the
EGL API away from the EGLNative types.
The core of the problem is that eglplatform.h can define each EGLNative
type once only, but Linux supports multiple EGL platforms.
To work around the problem, Mesa's eglplatform.h contains multiple
definitions of each EGLNative type, selected by feature macros. Mesa
expects EGL clients to set the feature macro approrpiately. But the
feature macros don't work when a single codebase must be built with
support for multiple EGL platforms, *such as Mesa itself*.
When building libEGL, autotools chooses the EGLNative typedefs based on
the first element of '--with-egl-platforms'. For example,
'--with-egl-platforms=x11,drm,wayland' defines the following:
typedef Display* EGLNativeDisplayType;
typedef Window EGLNativeWindowType;
typedef Pixmap EGLNativePixmapType;
Clearly, this doesn't work well for Wayland and GBM. Mesa works around
the problem by casting the EGLNative types to different things in
different files.
For sanity's sake, and to prepare for the EGL platform extensions, this
patch removes from egl/main and egl/dri2 all internal use of the
EGLNative types. It replaces them with 'void*' and checks each explicit
cast with a static assertion. Also, the patch touches egl_gallium the
minimal amount to keep it compatible with eglapi.h.
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
2014-01-07 22:54:51 +00:00
|
|
|
|
struct wl_egl_window *window = native_window;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
struct dri2_egl_surface *dri2_surf;
|
2015-06-10 01:49:29 +01:00
|
|
|
|
const __DRIconfig *config;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2014-09-22 05:15:26 +01:00
|
|
|
|
dri2_surf = calloc(1, sizeof *dri2_surf);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (!dri2_surf) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2015-06-13 08:36:27 +01:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list))
|
2011-02-04 11:39:40 +00:00
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
|
2017-02-13 14:06:10 +00:00
|
|
|
|
if (dri2_dpy->dri2) {
|
|
|
|
|
if (conf->RedSize == 5)
|
|
|
|
|
dri2_surf->format = WL_DRM_FORMAT_RGB565;
|
|
|
|
|
else if (conf->AlphaSize == 0)
|
|
|
|
|
dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
|
|
|
|
|
else
|
|
|
|
|
dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
|
|
|
|
|
} else {
|
|
|
|
|
if (conf->RedSize == 5)
|
|
|
|
|
dri2_surf->format = WL_SHM_FORMAT_RGB565;
|
|
|
|
|
else if (conf->AlphaSize == 0)
|
|
|
|
|
dri2_surf->format = WL_SHM_FORMAT_XRGB8888;
|
|
|
|
|
else
|
|
|
|
|
dri2_surf->format = WL_SHM_FORMAT_ARGB8888;
|
|
|
|
|
}
|
2011-08-31 21:45:04 +01:00
|
|
|
|
|
2015-06-18 20:19:32 +01:00
|
|
|
|
if (!window) {
|
|
|
|
|
_eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
|
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_surf->wl_win = window;
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
|
2017-05-22 11:07:53 +01:00
|
|
|
|
if (!dri2_surf->wl_queue) {
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->wl_drm) {
|
|
|
|
|
dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm);
|
|
|
|
|
if (!dri2_surf->wl_drm_wrapper) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
goto cleanup_queue;
|
|
|
|
|
}
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper,
|
|
|
|
|
dri2_surf->wl_queue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
|
|
|
|
|
if (!dri2_surf->wl_dpy_wrapper) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
goto cleanup_drm;
|
|
|
|
|
}
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper,
|
|
|
|
|
dri2_surf->wl_queue);
|
|
|
|
|
|
|
|
|
|
dri2_surf->wl_surface_wrapper = wl_proxy_create_wrapper(window->surface);
|
|
|
|
|
if (!dri2_surf->wl_surface_wrapper) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
goto cleanup_drm;
|
|
|
|
|
}
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,
|
|
|
|
|
dri2_surf->wl_queue);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_surf->wl_win->private = dri2_surf;
|
2016-10-24 09:48:11 +01:00
|
|
|
|
dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
|
2012-11-30 15:41:02 +00:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_surf->base.Width = -1;
|
|
|
|
|
dri2_surf->base.Height = -1;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-06-10 01:49:29 +01:00
|
|
|
|
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
|
|
|
|
|
dri2_surf->base.GLColorspace);
|
|
|
|
|
|
2016-11-28 18:25:19 +00:00
|
|
|
|
if (dri2_dpy->dri2) {
|
|
|
|
|
dri2_surf->wl_win->resize_callback = resize_callback;
|
|
|
|
|
|
|
|
|
|
createNewDrawable = dri2_dpy->dri2->createNewDrawable;
|
|
|
|
|
} else {
|
|
|
|
|
createNewDrawable = dri2_dpy->swrast->createNewDrawable;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-28 18:25:19 +00:00
|
|
|
|
dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen, config,
|
|
|
|
|
dri2_surf);
|
|
|
|
|
if (dri2_surf->dri_drawable == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "createNewDrawable");
|
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_wl_swap_interval(drv, disp, &dri2_surf->base,
|
|
|
|
|
dri2_dpy->default_swap_interval);
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return &dri2_surf->base;
|
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
cleanup_drm:
|
|
|
|
|
if (dri2_surf->wl_drm_wrapper)
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
|
|
|
|
|
cleanup_queue:
|
|
|
|
|
wl_event_queue_destroy(dri2_surf->wl_queue);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
cleanup_surf:
|
|
|
|
|
free(dri2_surf);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-09 17:13:27 +00:00
|
|
|
|
static _EGLSurface *
|
|
|
|
|
dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
|
|
|
|
|
_EGLConfig *conf, void *native_window,
|
|
|
|
|
const EGLint *attrib_list)
|
|
|
|
|
{
|
|
|
|
|
/* From the EGL_EXT_platform_wayland spec, version 3:
|
|
|
|
|
*
|
|
|
|
|
* It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
|
|
|
|
|
* that belongs to Wayland. Any such call fails and generates
|
|
|
|
|
* EGL_BAD_PARAMETER.
|
|
|
|
|
*/
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
|
|
|
|
|
"Wayland");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglDestroySurface(), drv->API.DestroySurface().
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
2015-11-25 05:27:02 +00:00
|
|
|
|
dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (dri2_surf->color_buffers[i].wl_buffer)
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->color_buffers[i].dri_image)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].linear_copy)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].data)
|
|
|
|
|
munmap(dri2_surf->color_buffers[i].data,
|
|
|
|
|
dri2_surf->color_buffers[i].data_size);
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_dpy->dri2) {
|
|
|
|
|
for (i = 0; i < __DRI_BUFFER_COUNT; i++)
|
|
|
|
|
if (dri2_surf->dri_buffers[i] &&
|
|
|
|
|
dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
|
|
|
|
|
dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->dri_buffers[i]);
|
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
if (dri2_surf->throttle_callback)
|
|
|
|
|
wl_callback_destroy(dri2_surf->throttle_callback);
|
2012-10-27 23:50:12 +01:00
|
|
|
|
|
2016-10-24 09:48:11 +01:00
|
|
|
|
if (dri2_surf->wl_win) {
|
|
|
|
|
dri2_surf->wl_win->private = NULL;
|
|
|
|
|
dri2_surf->wl_win->resize_callback = NULL;
|
|
|
|
|
dri2_surf->wl_win->destroy_window_callback = NULL;
|
|
|
|
|
}
|
2012-11-30 15:41:02 +00:00
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
if (dri2_surf->wl_drm_wrapper)
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
|
|
|
|
|
wl_event_queue_destroy(dri2_surf->wl_queue);
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
free(surf);
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2012-12-14 04:30:45 +00:00
|
|
|
|
int i;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (dri2_surf->color_buffers[i].wl_buffer &&
|
|
|
|
|
!dri2_surf->color_buffers[i].locked)
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->color_buffers[i].dri_image)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].linear_copy)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].data)
|
|
|
|
|
munmap(dri2_surf->color_buffers[i].data,
|
|
|
|
|
dri2_surf->color_buffers[i].data_size);
|
2011-02-09 14:30:20 +00:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_surf->color_buffers[i].dri_image = NULL;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_surf->color_buffers[i].linear_copy = NULL;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_surf->color_buffers[i].data = NULL;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].locked = 0;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
}
|
2011-09-01 08:17:04 +01:00
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_dpy->dri2) {
|
|
|
|
|
for (i = 0; i < __DRI_BUFFER_COUNT; i++)
|
|
|
|
|
if (dri2_surf->dri_buffers[i] &&
|
|
|
|
|
dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
|
|
|
|
|
dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->dri_buffers[i]);
|
|
|
|
|
}
|
2011-02-11 01:23:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
static int
|
2013-11-09 06:10:36 +00:00
|
|
|
|
get_back_bo(struct dri2_egl_surface *dri2_surf)
|
2011-02-11 01:23:14 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2015-10-21 11:28:00 +01:00
|
|
|
|
int i, use_flags;
|
2015-02-11 03:15:31 +00:00
|
|
|
|
unsigned int dri_image_format;
|
|
|
|
|
|
|
|
|
|
/* currently supports three WL DRM formats,
|
|
|
|
|
* WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888,
|
|
|
|
|
* and WL_DRM_FORMAT_RGB565
|
|
|
|
|
*/
|
|
|
|
|
switch (dri2_surf->format) {
|
|
|
|
|
case WL_DRM_FORMAT_ARGB8888:
|
|
|
|
|
dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_DRM_FORMAT_XRGB8888:
|
|
|
|
|
dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_DRM_FORMAT_RGB565:
|
|
|
|
|
dri_image_format = __DRI_IMAGE_FORMAT_RGB565;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* format is not supported */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-02-11 01:23:14 +00:00
|
|
|
|
|
Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"
This reverts commit 25cc889004aad6d1cab9edd76db898658e347b97, though
since the code has changed, it was applied manually.
The intent of moving blocking from SwapBuffers to get_back_bo, was to
avoid unnecessary triple-buffering by ensuring that the compositor had
fully processed the previous frame before we started rendering. This
means that the only time we would have to resort to triple-buffering
would be when the buffer is directly scanned out, thus saving an extra
buffer for composition anyway.
The 'repaint window' changes introduced in Weston since then, however,
have narrowed the window of time between the frame event being sent and
the repaint loop needing to conclude, to 7ms by default, in order to
reduce latency. This means however that blocking in get_back_bo gives a
maximum of 7ms for the entire GL submission to begin and complete.
Not only this, but if a client is using buffer_age to avoid full
repaints, the buffer-age request will stall in get_back_bo until the
frame callback completes, meaning that the client cannot even calculate
the repaint area before the 7ms window.
The combination of the two meant that WebKit-GTK+ was failing to
achieve full framerate on a Minnowboard, due to spending a great deal of
its time attempting to query the age of the next buffer before redraw.
Revert to the previous behaviour of allowing rendering to begin but
delaying SwapBuffers, unless and until we can find a more gentle
behaviour.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Derek Foreman <derekf@osg.samsung.com>
Tested-by: Derek Foreman <derekf@osg.samsung.com>
Cc: Kristian Høgsberg <krh@bitplanet.net>
2016-06-01 09:59:06 +01:00
|
|
|
|
/* There might be a buffer release already queued that wasn't processed */
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
egl/wayland: Ensure we get a back buffer
Commit 9ca6711faa03 changed the Wayland winsys to only block for the
frame callback inside SwapBuffers, rather than get_back_bo. get_back_bo
would perform a single non-blocking Wayland event dispatch, to try to
find any release events which we had pulled off the wire but not
actually processed. The blocking dispatch was moved to SwapBuffers.
This removed a guarantee that we would've processed all events inside
get_back_bo(), and introduced a failure whereby the server could've sent
a buffer release event, but we wouldn't have read it. In clients
unconstrained by SwapInterval (rendering ~as fast as possible), which
were being displayed directly without composition (buffer release delayed),
this could lead to get_back_bo() failing because there were no free
buffers available to it.
The drawing rightly failed, but this was papered over because of the
path in eglSwapBuffers() which attempts to guarantee a BO, in order to
support calling SwapBuffers twice in a row with no rendering actually
having been performed.
Since eglSwapBuffers will perform a blocking dispatch of Wayland
events, a buffer release would have arrived by that point, and we
could then choose a buffer to post to the server. The effect was that
frames were displayed out-of-order, since we grabbed a frame with random
past content to display to the compositor.
Ideally get_back_bo() failing should store a failure flag inside the
surface and cause the next SwapBuffers to fail, but for the meantime,
restore the correct behaviour such that get_back_bo() no longer fails.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reported-by: Eero Tamminen <eero.t.tamminen@intel.com>
Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98833
Fixes: 9ca6711faa03 ("Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"")
2017-05-15 22:22:32 +01:00
|
|
|
|
while (dri2_surf->back == NULL) {
|
2012-12-14 04:30:45 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2013-11-15 13:50:50 +00:00
|
|
|
|
/* Get an unlocked buffer, preferrably one with a dri_buffer
|
|
|
|
|
* already allocated. */
|
|
|
|
|
if (dri2_surf->color_buffers[i].locked)
|
2012-12-14 04:30:45 +00:00
|
|
|
|
continue;
|
|
|
|
|
if (dri2_surf->back == NULL)
|
2013-11-15 13:50:50 +00:00
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
2013-02-02 12:40:51 +00:00
|
|
|
|
else if (dri2_surf->back->dri_image == NULL)
|
2013-11-15 13:50:50 +00:00
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
2011-02-11 01:23:14 +00:00
|
|
|
|
}
|
egl/wayland: Ensure we get a back buffer
Commit 9ca6711faa03 changed the Wayland winsys to only block for the
frame callback inside SwapBuffers, rather than get_back_bo. get_back_bo
would perform a single non-blocking Wayland event dispatch, to try to
find any release events which we had pulled off the wire but not
actually processed. The blocking dispatch was moved to SwapBuffers.
This removed a guarantee that we would've processed all events inside
get_back_bo(), and introduced a failure whereby the server could've sent
a buffer release event, but we wouldn't have read it. In clients
unconstrained by SwapInterval (rendering ~as fast as possible), which
were being displayed directly without composition (buffer release delayed),
this could lead to get_back_bo() failing because there were no free
buffers available to it.
The drawing rightly failed, but this was papered over because of the
path in eglSwapBuffers() which attempts to guarantee a BO, in order to
support calling SwapBuffers twice in a row with no rendering actually
having been performed.
Since eglSwapBuffers will perform a blocking dispatch of Wayland
events, a buffer release would have arrived by that point, and we
could then choose a buffer to post to the server. The effect was that
frames were displayed out-of-order, since we grabbed a frame with random
past content to display to the compositor.
Ideally get_back_bo() failing should store a failure flag inside the
surface and cause the next SwapBuffers to fail, but for the meantime,
restore the correct behaviour such that get_back_bo() no longer fails.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reported-by: Eero Tamminen <eero.t.tamminen@intel.com>
Acked-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98833
Fixes: 9ca6711faa03 ("Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"")
2017-05-15 22:22:32 +01:00
|
|
|
|
|
|
|
|
|
if (dri2_surf->back)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* If we don't have a buffer, then block on the server to release one for
|
|
|
|
|
* us, and try again. */
|
|
|
|
|
if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_surf->wl_queue) < 0)
|
|
|
|
|
return -1;
|
2011-02-11 01:23:14 +00:00
|
|
|
|
}
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
if (dri2_surf->back == NULL)
|
|
|
|
|
return -1;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
|
2015-10-21 11:28:00 +01:00
|
|
|
|
use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu &&
|
|
|
|
|
dri2_surf->back->linear_copy == NULL) {
|
|
|
|
|
dri2_surf->back->linear_copy =
|
|
|
|
|
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
dri_image_format,
|
2015-10-21 11:28:00 +01:00
|
|
|
|
use_flags |
|
2015-05-01 00:16:24 +01:00
|
|
|
|
__DRI_IMAGE_USE_LINEAR,
|
|
|
|
|
NULL);
|
|
|
|
|
if (dri2_surf->back->linear_copy == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->back->dri_image == NULL) {
|
2015-06-13 08:36:27 +01:00
|
|
|
|
dri2_surf->back->dri_image =
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
2015-02-11 03:15:31 +00:00
|
|
|
|
dri_image_format,
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->is_different_gpu ?
|
2015-10-21 11:28:00 +01:00
|
|
|
|
0 : use_flags,
|
2013-02-02 12:40:51 +00:00
|
|
|
|
NULL);
|
2012-12-14 04:32:14 +00:00
|
|
|
|
dri2_surf->back->age = 0;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->back->dri_image == NULL)
|
2012-12-14 04:30:45 +00:00
|
|
|
|
return -1;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
dri2_surf->back->locked = 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
__DRIimage *image;
|
|
|
|
|
int name, pitch;
|
|
|
|
|
|
2013-02-02 12:40:51 +00:00
|
|
|
|
image = dri2_surf->back->dri_image;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
|
|
|
|
|
|
|
|
|
|
buffer->attachment = __DRI_BUFFER_BACK_LEFT;
|
|
|
|
|
buffer->name = name;
|
|
|
|
|
buffer->pitch = pitch;
|
|
|
|
|
buffer->cpp = 4;
|
|
|
|
|
buffer->flags = 0;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
static int
|
|
|
|
|
get_aux_bo(struct dri2_egl_surface *dri2_surf,
|
|
|
|
|
unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
|
2011-05-06 18:13:29 +01:00
|
|
|
|
{
|
2012-12-14 04:30:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
__DRIbuffer *b = dri2_surf->dri_buffers[attachment];
|
|
|
|
|
|
|
|
|
|
if (b == NULL) {
|
|
|
|
|
b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
|
|
|
|
|
attachment, format,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height);
|
|
|
|
|
dri2_surf->dri_buffers[attachment] = b;
|
|
|
|
|
}
|
|
|
|
|
if (b == NULL)
|
|
|
|
|
return -1;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
memcpy(buffer, b, sizeof *buffer);
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
return 0;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
static int
|
|
|
|
|
update_buffers(struct dri2_egl_surface *dri2_surf)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2013-11-09 06:10:36 +00:00
|
|
|
|
int i;
|
2012-11-22 13:34:49 +00:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
|
|
|
|
|
dri2_surf->base.Height != dri2_surf->wl_win->height) {
|
2011-02-11 01:23:14 +00:00
|
|
|
|
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_release_buffers(dri2_surf);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
dri2_surf->base.Width = dri2_surf->wl_win->width;
|
|
|
|
|
dri2_surf->base.Height = dri2_surf->wl_win->height;
|
|
|
|
|
dri2_surf->dx = dri2_surf->wl_win->dx;
|
|
|
|
|
dri2_surf->dy = dri2_surf->wl_win->dy;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
if (get_back_bo(dri2_surf) < 0) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
|
|
|
|
|
return -1;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
/* If we have an extra unlocked buffer at this point, we had to do triple
|
|
|
|
|
* buffering for a while, but now can go back to just double buffering.
|
|
|
|
|
* That means we can free any unlocked buffer now. */
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked &&
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer) {
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_surf->color_buffers[i].dri_image = NULL;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_surf->color_buffers[i].linear_copy = NULL;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static __DRIbuffer *
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
|
|
|
|
|
int *width, int *height,
|
|
|
|
|
unsigned int *attachments, int count,
|
|
|
|
|
int *out_count, void *loaderPrivate)
|
2013-11-09 06:10:36 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
if (update_buffers(dri2_surf) < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
|
|
|
|
|
switch (attachments[i]) {
|
|
|
|
|
case __DRI_BUFFER_BACK_LEFT:
|
|
|
|
|
back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
|
|
|
|
|
&dri2_surf->buffers[j]) < 0) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
*out_count = j;
|
|
|
|
|
if (j == 0)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
*width = dri2_surf->base.Width;
|
|
|
|
|
*height = dri2_surf->base.Height;
|
|
|
|
|
|
|
|
|
|
return dri2_surf->buffers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static __DRIbuffer *
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_get_buffers(__DRIdrawable * driDrawable,
|
|
|
|
|
int *width, int *height,
|
|
|
|
|
unsigned int *attachments, int count,
|
|
|
|
|
int *out_count, void *loaderPrivate)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
2015-02-11 03:15:31 +00:00
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
unsigned int *attachments_with_format;
|
|
|
|
|
__DRIbuffer *buffer;
|
2015-02-11 03:15:31 +00:00
|
|
|
|
unsigned int bpp;
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
2015-02-11 03:15:31 +00:00
|
|
|
|
switch (dri2_surf->format) {
|
|
|
|
|
case WL_DRM_FORMAT_ARGB8888:
|
|
|
|
|
case WL_DRM_FORMAT_XRGB8888:
|
|
|
|
|
bpp = 32;
|
|
|
|
|
break;
|
|
|
|
|
case WL_DRM_FORMAT_RGB565:
|
|
|
|
|
bpp = 16;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* format is not supported */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-03 22:33:18 +01:00
|
|
|
|
attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (!attachments_with_format) {
|
|
|
|
|
*out_count = 0;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
|
attachments_with_format[2*i] = attachments[i];
|
2015-02-11 03:15:31 +00:00
|
|
|
|
attachments_with_format[2*i + 1] = bpp;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer =
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_get_buffers_with_format(driDrawable,
|
|
|
|
|
width, height,
|
|
|
|
|
attachments_with_format, count,
|
|
|
|
|
out_count, loaderPrivate);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
free(attachments_with_format);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
static int
|
|
|
|
|
image_get_buffers(__DRIdrawable *driDrawable,
|
|
|
|
|
unsigned int format,
|
|
|
|
|
uint32_t *stamp,
|
|
|
|
|
void *loaderPrivate,
|
|
|
|
|
uint32_t buffer_mask,
|
|
|
|
|
struct __DRIimageList *buffers)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
|
|
|
|
|
if (update_buffers(dri2_surf) < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
|
|
|
|
|
buffers->back = dri2_surf->back->dri_image;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
static void
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
(void) driDrawable;
|
|
|
|
|
(void) loaderPrivate;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 18:21:48 +01:00
|
|
|
|
static const __DRIdri2LoaderExtension dri2_loader_extension = {
|
|
|
|
|
.base = { __DRI_DRI2_LOADER, 3 },
|
|
|
|
|
|
|
|
|
|
.getBuffers = dri2_wl_get_buffers,
|
|
|
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
|
|
|
|
.getBuffersWithFormat = dri2_wl_get_buffers_with_format,
|
|
|
|
|
};
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
static const __DRIimageLoaderExtension image_loader_extension = {
|
2014-02-12 18:32:59 +00:00
|
|
|
|
.base = { __DRI_IMAGE_LOADER, 1 },
|
|
|
|
|
|
|
|
|
|
.getBuffers = image_get_buffers,
|
2014-01-28 20:47:38 +00:00
|
|
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
};
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
static void
|
2013-11-15 13:50:50 +00:00
|
|
|
|
wayland_throttle_callback(void *data,
|
|
|
|
|
struct wl_callback *callback,
|
|
|
|
|
uint32_t time)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = data;
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
dri2_surf->throttle_callback = NULL;
|
2011-08-17 03:38:22 +01:00
|
|
|
|
wl_callback_destroy(callback);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
static const struct wl_callback_listener throttle_listener = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.done = wayland_throttle_callback
|
2011-08-17 03:38:22 +01:00
|
|
|
|
};
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
static void
|
|
|
|
|
create_wl_buffer(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
__DRIimage *image;
|
2013-11-09 06:10:36 +00:00
|
|
|
|
int fd, stride, name;
|
2013-02-02 17:26:12 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_surf->current->wl_buffer != NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu) {
|
|
|
|
|
image = dri2_surf->current->linear_copy;
|
|
|
|
|
} else {
|
|
|
|
|
image = dri2_surf->current->dri_image;
|
|
|
|
|
}
|
2013-02-02 17:26:12 +00:00
|
|
|
|
if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
|
2013-02-02 17:26:12 +00:00
|
|
|
|
|
|
|
|
|
dri2_surf->current->wl_buffer =
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_drm_create_prime_buffer(dri2_surf->wl_drm_wrapper,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
fd,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
dri2_surf->format,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
0, stride,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
0, 0,
|
|
|
|
|
0, 0);
|
|
|
|
|
close(fd);
|
|
|
|
|
} else {
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
|
2013-11-09 06:10:36 +00:00
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
dri2_surf->current->wl_buffer =
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_drm_create_buffer(dri2_surf->wl_drm_wrapper,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
name,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
stride,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
dri2_surf->format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_buffer_add_listener(dri2_surf->current->wl_buffer,
|
|
|
|
|
&wl_buffer_listener, dri2_surf);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 16:34:39 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
try_damage_buffer(struct dri2_egl_surface *dri2_surf,
|
|
|
|
|
const EGLint *rects,
|
|
|
|
|
EGLint n_rects)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper)
|
2016-02-16 16:34:39 +00:00
|
|
|
|
< WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_rects; i++) {
|
|
|
|
|
const int *rect = &rects[i * 4];
|
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper,
|
2016-02-16 16:34:39 +00:00
|
|
|
|
rect[0],
|
|
|
|
|
dri2_surf->base.Height - rect[1] - rect[3],
|
|
|
|
|
rect[2], rect[3]);
|
|
|
|
|
}
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglSwapBuffers(), drv->API.SwapBuffers().
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
|
|
|
|
|
_EGLDisplay *disp,
|
|
|
|
|
_EGLSurface *draw,
|
|
|
|
|
const EGLint *rects,
|
|
|
|
|
EGLint n_rects)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
|
2013-11-15 13:50:49 +00:00
|
|
|
|
int i;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"
This reverts commit 25cc889004aad6d1cab9edd76db898658e347b97, though
since the code has changed, it was applied manually.
The intent of moving blocking from SwapBuffers to get_back_bo, was to
avoid unnecessary triple-buffering by ensuring that the compositor had
fully processed the previous frame before we started rendering. This
means that the only time we would have to resort to triple-buffering
would be when the buffer is directly scanned out, thus saving an extra
buffer for composition anyway.
The 'repaint window' changes introduced in Weston since then, however,
have narrowed the window of time between the frame event being sent and
the repaint loop needing to conclude, to 7ms by default, in order to
reduce latency. This means however that blocking in get_back_bo gives a
maximum of 7ms for the entire GL submission to begin and complete.
Not only this, but if a client is using buffer_age to avoid full
repaints, the buffer-age request will stall in get_back_bo until the
frame callback completes, meaning that the client cannot even calculate
the repaint area before the 7ms window.
The combination of the two meant that WebKit-GTK+ was failing to
achieve full framerate on a Minnowboard, due to spending a great deal of
its time attempting to query the age of the next buffer before redraw.
Revert to the previous behaviour of allowing rendering to begin but
delaying SwapBuffers, unless and until we can find a more gentle
behaviour.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Derek Foreman <derekf@osg.samsung.com>
Tested-by: Derek Foreman <derekf@osg.samsung.com>
Cc: Kristian Høgsberg <krh@bitplanet.net>
2016-06-01 09:59:06 +01:00
|
|
|
|
while (dri2_surf->throttle_callback != NULL)
|
|
|
|
|
if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
dri2_surf->wl_queue) == -1)
|
Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"
This reverts commit 25cc889004aad6d1cab9edd76db898658e347b97, though
since the code has changed, it was applied manually.
The intent of moving blocking from SwapBuffers to get_back_bo, was to
avoid unnecessary triple-buffering by ensuring that the compositor had
fully processed the previous frame before we started rendering. This
means that the only time we would have to resort to triple-buffering
would be when the buffer is directly scanned out, thus saving an extra
buffer for composition anyway.
The 'repaint window' changes introduced in Weston since then, however,
have narrowed the window of time between the frame event being sent and
the repaint loop needing to conclude, to 7ms by default, in order to
reduce latency. This means however that blocking in get_back_bo gives a
maximum of 7ms for the entire GL submission to begin and complete.
Not only this, but if a client is using buffer_age to avoid full
repaints, the buffer-age request will stall in get_back_bo until the
frame callback completes, meaning that the client cannot even calculate
the repaint area before the 7ms window.
The combination of the two meant that WebKit-GTK+ was failing to
achieve full framerate on a Minnowboard, due to spending a great deal of
its time attempting to query the age of the next buffer before redraw.
Revert to the previous behaviour of allowing rendering to begin but
delaying SwapBuffers, unless and until we can find a more gentle
behaviour.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Derek Foreman <derekf@osg.samsung.com>
Tested-by: Derek Foreman <derekf@osg.samsung.com>
Cc: Kristian Høgsberg <krh@bitplanet.net>
2016-06-01 09:59:06 +01:00
|
|
|
|
return -1;
|
|
|
|
|
|
2012-12-14 04:32:14 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
|
|
|
|
|
if (dri2_surf->color_buffers[i].age > 0)
|
|
|
|
|
dri2_surf->color_buffers[i].age++;
|
|
|
|
|
|
2013-02-06 20:41:54 +00:00
|
|
|
|
/* Make sure we have a back buffer in case we're swapping without ever
|
|
|
|
|
* rendering. */
|
2013-11-09 06:10:36 +00:00
|
|
|
|
if (get_back_bo(dri2_surf) < 0) {
|
2013-02-06 20:41:54 +00:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
if (draw->SwapInterval > 0) {
|
|
|
|
|
dri2_surf->throttle_callback =
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_frame(dri2_surf->wl_surface_wrapper);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
}
|
2013-11-15 13:50:49 +00:00
|
|
|
|
|
2012-12-14 04:32:14 +00:00
|
|
|
|
dri2_surf->back->age = 1;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->current = dri2_surf->back;
|
|
|
|
|
dri2_surf->back = NULL;
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
create_wl_buffer(dri2_surf);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_attach(dri2_surf->wl_surface_wrapper,
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->current->wl_buffer,
|
|
|
|
|
dri2_surf->dx, dri2_surf->dy);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
|
|
|
|
|
dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
|
|
|
|
|
/* reset resize growing parameters */
|
|
|
|
|
dri2_surf->dx = 0;
|
|
|
|
|
dri2_surf->dy = 0;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2016-02-16 16:34:39 +00:00
|
|
|
|
/* If the compositor doesn't support damage_buffer, we deliberately
|
|
|
|
|
* ignore the damage region and post maximum damage, due to
|
egl/wayland: Ignore rects from SwapBuffersWithDamage
eglSwapBuffersWithDamage accepts damage-region rectangles to hint the
compositor that it only needs to redraw certain areas, which was passed
through the wl_surface_damage request, as designed.
Wayland also offers a buffer transformation interface, e.g. to allow
users to render pre-rotated buffers. Unfortunately, there is no way to
query buffer transforms, and the damage region was provided in surface,
rather than buffer, co-ordinate space.
Users could in theory account for this themselves, but EGL also requires
co-ordinates to be passed in GL/mathematical co-ordinate space, with an
inversion to Wayland's natural/scanout co-ordinate space, so
transformations other than a 180-degree rotation will fail as EGL
attempts to subtract the region from (its view of the) surface height.
Pending creation and acceptance of a wl_surface.buffer_damage request,
which will accept co-ordinates in buffer co-ordinate space, pessimise to
always sending full-surface damage.
bce64c6c provides the explanation for why we send maximum-range damage,
rather than the full size of the surface: in the presence of buffer
transformations, full-surface damage may not actually cover the entire
surface.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Jason Ekstrand <jason.ekstrand@intel.com>
2015-11-07 18:25:31 +00:00
|
|
|
|
* https://bugs.freedesktop.org/78190 */
|
2016-02-16 16:34:39 +00:00
|
|
|
|
if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_damage(dri2_surf->wl_surface_wrapper,
|
2016-02-16 16:34:39 +00:00
|
|
|
|
0, 0, INT32_MAX, INT32_MAX);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu) {
|
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
dri2_dpy->image->blitImage(dri2_ctx->dri_context,
|
|
|
|
|
dri2_surf->current->linear_copy,
|
|
|
|
|
dri2_surf->current->dri_image,
|
|
|
|
|
0, 0, dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
0, 0, dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height, 0);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-21 19:51:33 +00:00
|
|
|
|
dri2_flush_drawable_for_swapbuffers(disp, draw);
|
2015-11-25 05:27:02 +00:00
|
|
|
|
dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_commit(dri2_surf->wl_surface_wrapper);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
|
|
|
|
|
/* If we're not waiting for a frame callback then we'll at least throttle
|
|
|
|
|
* to a sync callback so that we always give a chance for the compositor to
|
|
|
|
|
* handle the commit and send a release event before checking for a free
|
|
|
|
|
* buffer */
|
|
|
|
|
if (dri2_surf->throttle_callback == NULL) {
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 16:38:09 +00:00
|
|
|
|
wl_display_flush(dri2_dpy->wl_dpy);
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:32:14 +00:00
|
|
|
|
static EGLint
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_query_buffer_age(_EGLDriver *drv,
|
|
|
|
|
_EGLDisplay *disp, _EGLSurface *surface)
|
2012-12-14 04:32:14 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
if (get_back_bo(dri2_surf) < 0) {
|
2012-12-14 04:32:14 +00:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dri2_surf->back->age;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 16:59:31 +00:00
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
|
2012-02-10 16:59:31 +00:00
|
|
|
|
{
|
2014-01-28 20:47:38 +00:00
|
|
|
|
return dri2_wl_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
|
2012-02-10 16:59:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-28 15:07:03 +00:00
|
|
|
|
static struct wl_buffer *
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv,
|
|
|
|
|
_EGLDisplay *disp,
|
|
|
|
|
_EGLImage *img)
|
2013-10-28 15:07:03 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
|
|
|
__DRIimage *image = dri2_img->dri_image;
|
|
|
|
|
struct wl_buffer *buffer;
|
|
|
|
|
int width, height, format, pitch;
|
|
|
|
|
enum wl_drm_format wl_format;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case __DRI_IMAGE_FORMAT_ARGB8888:
|
|
|
|
|
if (!(dri2_dpy->formats & HAS_ARGB8888))
|
|
|
|
|
goto bad_format;
|
|
|
|
|
wl_format = WL_DRM_FORMAT_ARGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case __DRI_IMAGE_FORMAT_XRGB8888:
|
|
|
|
|
if (!(dri2_dpy->formats & HAS_XRGB8888))
|
|
|
|
|
goto bad_format;
|
|
|
|
|
wl_format = WL_DRM_FORMAT_XRGB8888;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
goto bad_format;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
|
|
|
|
|
|
|
|
|
|
buffer =
|
|
|
|
|
wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
|
|
|
|
|
fd,
|
|
|
|
|
width, height,
|
|
|
|
|
wl_format,
|
|
|
|
|
0, pitch,
|
|
|
|
|
0, 0,
|
|
|
|
|
0, 0);
|
|
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
} else {
|
|
|
|
|
int name;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
|
|
|
|
|
|
|
|
|
|
buffer =
|
|
|
|
|
wl_drm_create_buffer(dri2_dpy->wl_drm,
|
|
|
|
|
name,
|
|
|
|
|
width, height,
|
|
|
|
|
pitch,
|
|
|
|
|
wl_format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The buffer object will have been created with our internal event queue
|
|
|
|
|
* because it is using the wl_drm object as a proxy factory. We want the
|
|
|
|
|
* buffer to be used by the application so we'll reset it to the display's
|
|
|
|
|
* default event queue */
|
|
|
|
|
if (buffer)
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
|
|
|
|
|
bad_format:
|
|
|
|
|
_eglError(EGL_BAD_MATCH, "unsupported image format");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
static int
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
|
2011-02-21 15:22:34 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
if (dri2_dpy->is_render_node) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: client asks server to "
|
|
|
|
|
"authenticate for render-nodes");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-05-31 10:45:51 +01:00
|
|
|
|
dri2_dpy->authenticated = 0;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
wl_drm_authenticate(dri2_dpy->wl_drm, id);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
if (roundtrip(dri2_dpy) < 0)
|
|
|
|
|
ret = -1;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
if (!dri2_dpy->authenticated)
|
2011-02-21 15:22:34 +00:00
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
|
|
/* reset authenticated */
|
2011-05-31 10:45:51 +01:00
|
|
|
|
dri2_dpy->authenticated = 1;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_device(void *data, struct wl_drm *drm, const char *device)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
drm_magic_t magic;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->device_name = strdup(device);
|
|
|
|
|
if (!dri2_dpy->device_name)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-06-17 17:28:51 +01:00
|
|
|
|
dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);
|
2011-04-14 15:42:41 +01:00
|
|
|
|
if (dri2_dpy->fd == -1) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
|
|
|
|
|
dri2_dpy->device_name, strerror(errno));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 12:27:06 +01:00
|
|
|
|
if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
|
2015-05-01 00:30:10 +01:00
|
|
|
|
dri2_dpy->authenticated = 1;
|
|
|
|
|
} else {
|
|
|
|
|
drmGetMagic(dri2_dpy->fd, &magic);
|
|
|
|
|
wl_drm_authenticate(dri2_dpy->wl_drm, magic);
|
|
|
|
|
}
|
2011-04-14 15:42:41 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-31 21:45:04 +01:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
2012-01-11 19:23:24 +00:00
|
|
|
|
case WL_DRM_FORMAT_ARGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_ARGB8888;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
break;
|
2012-01-11 19:23:24 +00:00
|
|
|
|
case WL_DRM_FORMAT_XRGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_XRGB8888;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
break;
|
2013-10-16 02:10:12 +01:00
|
|
|
|
case WL_DRM_FORMAT_RGB565:
|
|
|
|
|
dri2_dpy->formats |= HAS_RGB565;
|
|
|
|
|
break;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->capabilities = value;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_authenticated(void *data, struct wl_drm *drm)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
2011-05-31 10:45:51 +01:00
|
|
|
|
dri2_dpy->authenticated = 1;
|
2011-04-14 15:42:41 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_drm_listener drm_listener = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.device = drm_handle_device,
|
|
|
|
|
.format = drm_handle_format,
|
|
|
|
|
.authenticated = drm_handle_authenticated,
|
|
|
|
|
.capabilities = drm_handle_capabilities
|
2011-04-14 15:42:41 +01:00
|
|
|
|
};
|
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
static void
|
2015-05-01 10:11:20 +01:00
|
|
|
|
registry_handle_global_drm(void *data, struct wl_registry *registry, uint32_t name,
|
2012-10-11 03:10:42 +01:00
|
|
|
|
const char *interface, uint32_t version)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
if (version > 1)
|
|
|
|
|
version = 2;
|
2012-10-11 03:10:42 +01:00
|
|
|
|
if (strcmp(interface, "wl_drm") == 0) {
|
|
|
|
|
dri2_dpy->wl_drm =
|
2013-02-02 17:26:12 +00:00
|
|
|
|
wl_registry_bind(registry, name, &wl_drm_interface, version);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-18 21:53:46 +01:00
|
|
|
|
static void
|
|
|
|
|
registry_handle_global_remove(void *data, struct wl_registry *registry,
|
|
|
|
|
uint32_t name)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static const struct wl_registry_listener registry_listener_drm = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.global = registry_handle_global_drm,
|
|
|
|
|
.global_remove = registry_handle_global_remove
|
2012-10-11 03:10:42 +01:00
|
|
|
|
};
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_swap_interval(_EGLDriver *drv,
|
2013-11-15 13:50:50 +00:00
|
|
|
|
_EGLDisplay *disp,
|
|
|
|
|
_EGLSurface *surf,
|
|
|
|
|
EGLint interval)
|
|
|
|
|
{
|
|
|
|
|
if (interval > surf->Config->MaxSwapInterval)
|
|
|
|
|
interval = surf->Config->MaxSwapInterval;
|
|
|
|
|
else if (interval < surf->Config->MinSwapInterval)
|
|
|
|
|
interval = surf->Config->MinSwapInterval;
|
|
|
|
|
|
|
|
|
|
surf->SwapInterval = interval;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
|
2013-11-15 13:50:50 +00:00
|
|
|
|
{
|
|
|
|
|
GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
|
|
|
|
|
|
|
|
|
|
/* We can't use values greater than 1 on Wayland because we are using the
|
|
|
|
|
* frame callback to synchronise the frame and the only way we be sure to
|
|
|
|
|
* get a frame callback is to attach a new buffer. Therefore we can't just
|
|
|
|
|
* sit drawing nothing to wait until the next ‘n’ frame callbacks */
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->config)
|
|
|
|
|
dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
|
|
|
|
|
"vblank_mode", &vblank_mode);
|
|
|
|
|
switch (vblank_mode) {
|
|
|
|
|
case DRI_CONF_VBLANK_NEVER:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = 0;
|
|
|
|
|
dri2_dpy->default_swap_interval = 0;
|
|
|
|
|
break;
|
|
|
|
|
case DRI_CONF_VBLANK_ALWAYS_SYNC:
|
|
|
|
|
dri2_dpy->min_swap_interval = 1;
|
|
|
|
|
dri2_dpy->max_swap_interval = 1;
|
|
|
|
|
dri2_dpy->default_swap_interval = 1;
|
|
|
|
|
break;
|
|
|
|
|
case DRI_CONF_VBLANK_DEF_INTERVAL_0:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = 1;
|
|
|
|
|
dri2_dpy->default_swap_interval = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
case DRI_CONF_VBLANK_DEF_INTERVAL_1:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = 1;
|
|
|
|
|
dri2_dpy->default_swap_interval = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-15 16:14:17 +01:00
|
|
|
|
static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
|
2014-01-28 20:47:38 +00:00
|
|
|
|
.authenticate = dri2_wl_authenticate,
|
2014-01-29 00:39:09 +00:00
|
|
|
|
.create_window_surface = dri2_wl_create_window_surface,
|
2014-02-09 17:13:27 +00:00
|
|
|
|
.create_pixmap_surface = dri2_wl_create_pixmap_surface,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.destroy_surface = dri2_wl_destroy_surface,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.create_image = dri2_create_image_khr,
|
2014-01-28 20:34:19 +00:00
|
|
|
|
.swap_interval = dri2_wl_swap_interval,
|
2014-01-29 00:21:21 +00:00
|
|
|
|
.swap_buffers = dri2_wl_swap_buffers,
|
2014-01-29 00:26:44 +00:00
|
|
|
|
.swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.swap_buffers_region = dri2_fallback_swap_buffers_region,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.post_sub_buffer = dri2_fallback_post_sub_buffer,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.copy_buffers = dri2_fallback_copy_buffers,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.query_buffer_age = dri2_wl_query_buffer_age,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
|
2014-05-06 20:10:57 +01:00
|
|
|
|
.get_sync_values = dri2_fallback_get_sync_values,
|
2015-07-21 16:43:59 +01:00
|
|
|
|
.get_dri_drawable = dri2_surface_get_dri_drawable,
|
2014-01-28 19:41:46 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-24 23:32:27 +01:00
|
|
|
|
static const __DRIextension *dri2_loader_extensions[] = {
|
|
|
|
|
&dri2_loader_extension.base,
|
2017-01-10 21:21:47 +00:00
|
|
|
|
&image_loader_extension.base,
|
2016-08-24 23:32:27 +01:00
|
|
|
|
&image_lookup_extension.base,
|
|
|
|
|
&use_invalidate.base,
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const __DRIextension *image_loader_extensions[] = {
|
|
|
|
|
&image_loader_extension.base,
|
|
|
|
|
&image_lookup_extension.base,
|
|
|
|
|
&use_invalidate.base,
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-25 14:55:06 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_wl_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
static const struct {
|
|
|
|
|
const char *format_name;
|
|
|
|
|
int has_format;
|
|
|
|
|
unsigned int rgba_masks[4];
|
|
|
|
|
} visuals[] = {
|
|
|
|
|
{ "XRGB8888", HAS_XRGB8888, { 0xff0000, 0xff00, 0x00ff, 0xff000000 } },
|
|
|
|
|
{ "ARGB8888", HAS_ARGB8888, { 0xff0000, 0xff00, 0x00ff, 0 } },
|
|
|
|
|
{ "RGB565", HAS_RGB565, { 0x00f800, 0x07e0, 0x001f, 0 } },
|
|
|
|
|
};
|
|
|
|
|
unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 };
|
|
|
|
|
unsigned int count, i, j;
|
|
|
|
|
|
|
|
|
|
count = 0;
|
|
|
|
|
for (i = 0; dri2_dpy->driver_configs[i]; i++) {
|
|
|
|
|
for (j = 0; j < ARRAY_SIZE(visuals); j++) {
|
|
|
|
|
struct dri2_egl_config *dri2_conf;
|
|
|
|
|
|
|
|
|
|
if (!(dri2_dpy->formats & visuals[j].has_format))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
|
|
|
|
|
count + 1, EGL_WINDOW_BIT, NULL, visuals[j].rgba_masks);
|
|
|
|
|
if (dri2_conf) {
|
|
|
|
|
count++;
|
|
|
|
|
format_count[j]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(format_count); i++) {
|
|
|
|
|
if (!format_count[i]) {
|
|
|
|
|
_eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
|
|
|
|
|
visuals[i].format_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (count != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy;
|
|
|
|
|
|
2014-01-11 04:52:48 +00:00
|
|
|
|
loader_set_logger(_eglLog);
|
|
|
|
|
|
2012-09-05 07:09:22 +01:00
|
|
|
|
dri2_dpy = calloc(1, sizeof *dri2_dpy);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (!dri2_dpy)
|
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
|
|
2017-05-11 17:26:48 +01:00
|
|
|
|
dri2_dpy->fd = -1;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
disp->DriverData = (void *) dri2_dpy;
|
2011-06-11 21:07:02 +01:00
|
|
|
|
if (disp->PlatformDisplay == NULL) {
|
|
|
|
|
dri2_dpy->wl_dpy = wl_display_connect(NULL);
|
|
|
|
|
if (dri2_dpy->wl_dpy == NULL)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2011-12-13 13:43:48 +00:00
|
|
|
|
dri2_dpy->own_device = 1;
|
2011-06-11 21:07:02 +01:00
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->wl_dpy = disp->PlatformDisplay;
|
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
|
2013-02-26 17:49:40 +00:00
|
|
|
|
|
2017-01-13 15:05:10 +00:00
|
|
|
|
dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
|
|
|
|
|
if (dri2_dpy->wl_dpy_wrapper == NULL)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2017-01-13 15:05:10 +00:00
|
|
|
|
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
|
2013-02-26 17:49:40 +00:00
|
|
|
|
if (dri2_dpy->own_device)
|
|
|
|
|
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
|
|
|
|
|
|
2017-01-13 15:05:10 +00:00
|
|
|
|
dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
wl_registry_add_listener(dri2_dpy->wl_registry,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
®istry_listener_drm, dri2_dpy);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2012-10-11 03:10:42 +01:00
|
|
|
|
|
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2011-02-04 20:37:51 +00:00
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
|
|
|
|
|
&dri2_dpy->is_different_gpu);
|
|
|
|
|
if (dri2_dpy->is_different_gpu) {
|
|
|
|
|
free(dri2_dpy->device_name);
|
|
|
|
|
dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
|
|
|
|
|
if (!dri2_dpy->device_name) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "
|
|
|
|
|
"for requested GPU");
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we have to do the check now, because loader_get_user_preferred_fd
|
|
|
|
|
* will return a render-node when the requested gpu is different
|
|
|
|
|
* to the server, but also if the client asks for the same gpu than
|
|
|
|
|
* the server by requesting its pci-id */
|
2015-07-10 12:27:06 +01:00
|
|
|
|
dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
|
2016-09-12 17:48:18 +01:00
|
|
|
|
dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (dri2_dpy->driver_name == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
if (!dri2_load_driver(disp))
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
/* render nodes cannot use Gem names, and thus do not support
|
|
|
|
|
* the __DRI_DRI2_LOADER extension */
|
2016-08-24 23:32:27 +01:00
|
|
|
|
if (!dri2_dpy->is_render_node)
|
|
|
|
|
dri2_dpy->loader_extensions = dri2_loader_extensions;
|
|
|
|
|
else
|
|
|
|
|
dri2_dpy->loader_extensions = image_loader_extensions;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
if (!dri2_create_screen(disp))
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2017-05-11 16:20:04 +01:00
|
|
|
|
if (!dri2_setup_extensions(disp))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
dri2_setup_screen(disp);
|
|
|
|
|
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_setup_swap_interval(dri2_dpy);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
/* To use Prime, we must have _DRI_IMAGE v7 at least.
|
|
|
|
|
* createImageFromFds support indicates that Prime export/import
|
|
|
|
|
* is supported by the driver. Fall back to
|
|
|
|
|
* gem names if we don't have Prime support. */
|
2013-03-19 17:20:36 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->image->base.version < 7 ||
|
|
|
|
|
dri2_dpy->image->createImageFromFds == NULL)
|
2014-04-08 21:28:40 +01:00
|
|
|
|
dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
|
2013-03-19 17:20:36 +00:00
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
/* We cannot use Gem names with render-nodes, only prime fds (dma-buf).
|
|
|
|
|
* The server needs to accept them */
|
|
|
|
|
if (dri2_dpy->is_render_node &&
|
|
|
|
|
!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 00:30:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu &&
|
|
|
|
|
(dri2_dpy->image->base.version < 9 ||
|
|
|
|
|
dri2_dpy->image->blitImage == NULL)) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the "
|
|
|
|
|
"Image extension in the driver is not "
|
|
|
|
|
"compatible. Version 9 or later and blitImage() "
|
|
|
|
|
"are required");
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-25 14:55:06 +01:00
|
|
|
|
if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
|
|
|
|
|
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2016-08-25 13:15:43 +01:00
|
|
|
|
dri2_set_WL_bind_wayland_display(drv, disp);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
/* When cannot convert EGLImage to wl_buffer when on a different gpu,
|
|
|
|
|
* because the buffer of the EGLImage has likely a tiling mode the server
|
|
|
|
|
* gpu won't support. These is no way to check for now. Thus do not support the
|
|
|
|
|
* extension */
|
2017-05-15 16:14:16 +01:00
|
|
|
|
if (!dri2_dpy->is_different_gpu)
|
2015-05-01 00:16:24 +01:00
|
|
|
|
disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
|
2017-05-15 16:14:16 +01:00
|
|
|
|
|
2012-12-14 04:32:14 +00:00
|
|
|
|
disp->Extensions.EXT_buffer_age = EGL_TRUE;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2012-02-10 16:59:31 +00:00
|
|
|
|
disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
|
|
|
|
|
|
2014-01-28 19:41:46 +00:00
|
|
|
|
/* Fill vtbl last to prevent accidentally calling virtual function during
|
|
|
|
|
* initialization.
|
|
|
|
|
*/
|
|
|
|
|
dri2_dpy->vtbl = &dri2_wl_display_vtbl;
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
|
2017-05-11 17:26:48 +01:00
|
|
|
|
cleanup:
|
|
|
|
|
dri2_display_destroy(disp);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
dri2_wl_swrast_get_stride_for_format(int format, int w)
|
|
|
|
|
{
|
|
|
|
|
if (format == WL_SHM_FORMAT_RGB565)
|
|
|
|
|
return 2 * w;
|
|
|
|
|
else /* ARGB8888 || XRGB8888 */
|
|
|
|
|
return 4 * w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Taken from weston shared/os-compatibility.c
|
|
|
|
|
*/
|
|
|
|
|
|
2015-08-21 14:44:36 +01:00
|
|
|
|
#ifndef HAVE_MKOSTEMP
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static int
|
|
|
|
|
set_cloexec_or_close(int fd)
|
|
|
|
|
{
|
|
|
|
|
long flags;
|
|
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
flags = fcntl(fd, F_GETFD);
|
|
|
|
|
if (flags == -1)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
close(fd);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-21 14:44:36 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
/*
|
|
|
|
|
* Taken from weston shared/os-compatibility.c
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
create_tmpfile_cloexec(char *tmpname)
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_MKOSTEMP
|
|
|
|
|
fd = mkostemp(tmpname, O_CLOEXEC);
|
|
|
|
|
if (fd >= 0)
|
|
|
|
|
unlink(tmpname);
|
|
|
|
|
#else
|
|
|
|
|
fd = mkstemp(tmpname);
|
|
|
|
|
if (fd >= 0) {
|
|
|
|
|
fd = set_cloexec_or_close(fd);
|
|
|
|
|
unlink(tmpname);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Taken from weston shared/os-compatibility.c
|
|
|
|
|
*
|
|
|
|
|
* Create a new, unique, anonymous file of the given size, and
|
|
|
|
|
* return the file descriptor for it. The file descriptor is set
|
|
|
|
|
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
|
|
|
|
* the given size at offset zero.
|
|
|
|
|
*
|
|
|
|
|
* The file should not have a permanent backing store like a disk,
|
|
|
|
|
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
|
|
|
|
*
|
|
|
|
|
* The file name is deleted from the file system.
|
|
|
|
|
*
|
|
|
|
|
* The file is suitable for buffer sharing between processes by
|
|
|
|
|
* transmitting the file descriptor over Unix sockets using the
|
|
|
|
|
* SCM_RIGHTS methods.
|
|
|
|
|
*
|
|
|
|
|
* If the C library implements posix_fallocate(), it is used to
|
|
|
|
|
* guarantee that disk space is available for the file at the
|
|
|
|
|
* given size. If disk space is insufficent, errno is set to ENOSPC.
|
|
|
|
|
* If posix_fallocate() is not supported, program may receive
|
|
|
|
|
* SIGBUS on accessing mmap()'ed file contents instead.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
os_create_anonymous_file(off_t size)
|
|
|
|
|
{
|
|
|
|
|
static const char template[] = "/mesa-shared-XXXXXX";
|
|
|
|
|
const char *path;
|
|
|
|
|
char *name;
|
|
|
|
|
int fd;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
path = getenv("XDG_RUNTIME_DIR");
|
|
|
|
|
if (!path) {
|
|
|
|
|
errno = ENOENT;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = malloc(strlen(path) + sizeof(template));
|
|
|
|
|
if (!name)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
strcpy(name, path);
|
|
|
|
|
strcat(name, template);
|
|
|
|
|
|
|
|
|
|
fd = create_tmpfile_cloexec(name);
|
|
|
|
|
|
|
|
|
|
free(name);
|
|
|
|
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
ret = ftruncate(fd, size);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
close(fd);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
int format, int w, int h,
|
|
|
|
|
void **data, int *size,
|
|
|
|
|
struct wl_buffer **buffer)
|
|
|
|
|
{
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
struct wl_shm_pool *pool;
|
|
|
|
|
int fd, stride, size_map;
|
|
|
|
|
void *data_map;
|
|
|
|
|
|
|
|
|
|
stride = dri2_wl_swrast_get_stride_for_format(format, w);
|
|
|
|
|
size_map = h * stride;
|
|
|
|
|
|
|
|
|
|
/* Create a sharable buffer */
|
|
|
|
|
fd = os_create_anonymous_file(size_map);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
|
|
|
if (data_map == MAP_FAILED) {
|
|
|
|
|
close(fd);
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Share it in a wl_buffer */
|
|
|
|
|
pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *)pool, dri2_surf->wl_queue);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
*buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
|
|
|
|
|
wl_shm_pool_destroy(pool);
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
|
|
*data = data_map;
|
|
|
|
|
*size = size_map;
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* we need to do the following operations only once per frame */
|
|
|
|
|
if (dri2_surf->back)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
|
|
|
|
|
dri2_surf->base.Height != dri2_surf->wl_win->height) {
|
|
|
|
|
|
|
|
|
|
dri2_wl_release_buffers(dri2_surf);
|
|
|
|
|
|
|
|
|
|
dri2_surf->base.Width = dri2_surf->wl_win->width;
|
|
|
|
|
dri2_surf->base.Height = dri2_surf->wl_win->height;
|
|
|
|
|
dri2_surf->dx = dri2_surf->wl_win->dx;
|
|
|
|
|
dri2_surf->dy = dri2_surf->wl_win->dy;
|
|
|
|
|
dri2_surf->current = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find back buffer */
|
|
|
|
|
|
Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"
This reverts commit 25cc889004aad6d1cab9edd76db898658e347b97, though
since the code has changed, it was applied manually.
The intent of moving blocking from SwapBuffers to get_back_bo, was to
avoid unnecessary triple-buffering by ensuring that the compositor had
fully processed the previous frame before we started rendering. This
means that the only time we would have to resort to triple-buffering
would be when the buffer is directly scanned out, thus saving an extra
buffer for composition anyway.
The 'repaint window' changes introduced in Weston since then, however,
have narrowed the window of time between the frame event being sent and
the repaint loop needing to conclude, to 7ms by default, in order to
reduce latency. This means however that blocking in get_back_bo gives a
maximum of 7ms for the entire GL submission to begin and complete.
Not only this, but if a client is using buffer_age to avoid full
repaints, the buffer-age request will stall in get_back_bo until the
frame callback completes, meaning that the client cannot even calculate
the repaint area before the 7ms window.
The combination of the two meant that WebKit-GTK+ was failing to
achieve full framerate on a Minnowboard, due to spending a great deal of
its time attempting to query the age of the next buffer before redraw.
Revert to the previous behaviour of allowing rendering to begin but
delaying SwapBuffers, unless and until we can find a more gentle
behaviour.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Derek Foreman <derekf@osg.samsung.com>
Tested-by: Derek Foreman <derekf@osg.samsung.com>
Cc: Kristian Høgsberg <krh@bitplanet.net>
2016-06-01 09:59:06 +01:00
|
|
|
|
/* There might be a buffer release already queued that wasn't processed */
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
/* try get free buffer already created */
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked &&
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer) {
|
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* else choose any another free location */
|
|
|
|
|
if (!dri2_surf->back) {
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked) {
|
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
if (!dri2_wl_swrast_allocate_buffer(dri2_surf,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_surf->format,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
&dri2_surf->back->data,
|
|
|
|
|
&dri2_surf->back->data_size,
|
|
|
|
|
&dri2_surf->back->wl_buffer)) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
wl_buffer_add_listener(dri2_surf->back->wl_buffer,
|
|
|
|
|
&wl_buffer_listener, dri2_surf);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!dri2_surf->back) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to find free buffer");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_surf->back->locked = 1;
|
|
|
|
|
|
|
|
|
|
/* If we have an extra unlocked buffer at this point, we had to do triple
|
|
|
|
|
* buffering for a while, but now can go back to just double buffering.
|
|
|
|
|
* That means we can free any unlocked buffer now. */
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked &&
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer) {
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
|
|
|
|
munmap(dri2_surf->color_buffers[i].data,
|
|
|
|
|
dri2_surf->color_buffers[i].data_size);
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
|
|
|
|
dri2_surf->color_buffers[i].data = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void*
|
|
|
|
|
dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
/* if there has been a resize: */
|
|
|
|
|
if (!dri2_surf->current)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return dri2_surf->current->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void*
|
|
|
|
|
dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
assert(dri2_surf->back);
|
|
|
|
|
return dri2_surf->back->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
|
Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"
This reverts commit 25cc889004aad6d1cab9edd76db898658e347b97, though
since the code has changed, it was applied manually.
The intent of moving blocking from SwapBuffers to get_back_bo, was to
avoid unnecessary triple-buffering by ensuring that the compositor had
fully processed the previous frame before we started rendering. This
means that the only time we would have to resort to triple-buffering
would be when the buffer is directly scanned out, thus saving an extra
buffer for composition anyway.
The 'repaint window' changes introduced in Weston since then, however,
have narrowed the window of time between the frame event being sent and
the repaint loop needing to conclude, to 7ms by default, in order to
reduce latency. This means however that blocking in get_back_bo gives a
maximum of 7ms for the entire GL submission to begin and complete.
Not only this, but if a client is using buffer_age to avoid full
repaints, the buffer-age request will stall in get_back_bo until the
frame callback completes, meaning that the client cannot even calculate
the repaint area before the 7ms window.
The combination of the two meant that WebKit-GTK+ was failing to
achieve full framerate on a Minnowboard, due to spending a great deal of
its time attempting to query the age of the next buffer before redraw.
Revert to the previous behaviour of allowing rendering to begin but
delaying SwapBuffers, unless and until we can find a more gentle
behaviour.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Derek Foreman <derekf@osg.samsung.com>
Tested-by: Derek Foreman <derekf@osg.samsung.com>
Cc: Kristian Høgsberg <krh@bitplanet.net>
2016-06-01 09:59:06 +01:00
|
|
|
|
while (dri2_surf->throttle_callback != NULL)
|
|
|
|
|
if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
dri2_surf->wl_queue) == -1)
|
2016-11-11 16:27:59 +00:00
|
|
|
|
return;
|
Revert "wayland: Block for the frame callback in get_back_bo not dri2_swap_buffers"
This reverts commit 25cc889004aad6d1cab9edd76db898658e347b97, though
since the code has changed, it was applied manually.
The intent of moving blocking from SwapBuffers to get_back_bo, was to
avoid unnecessary triple-buffering by ensuring that the compositor had
fully processed the previous frame before we started rendering. This
means that the only time we would have to resort to triple-buffering
would be when the buffer is directly scanned out, thus saving an extra
buffer for composition anyway.
The 'repaint window' changes introduced in Weston since then, however,
have narrowed the window of time between the frame event being sent and
the repaint loop needing to conclude, to 7ms by default, in order to
reduce latency. This means however that blocking in get_back_bo gives a
maximum of 7ms for the entire GL submission to begin and complete.
Not only this, but if a client is using buffer_age to avoid full
repaints, the buffer-age request will stall in get_back_bo until the
frame callback completes, meaning that the client cannot even calculate
the repaint area before the 7ms window.
The combination of the two meant that WebKit-GTK+ was failing to
achieve full framerate on a Minnowboard, due to spending a great deal of
its time attempting to query the age of the next buffer before redraw.
Revert to the previous behaviour of allowing rendering to begin but
delaying SwapBuffers, unless and until we can find a more gentle
behaviour.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Jonas Ådahl <jadahl@gmail.com>
Reviewed-by: Derek Foreman <derekf@osg.samsung.com>
Tested-by: Derek Foreman <derekf@osg.samsung.com>
Cc: Kristian Høgsberg <krh@bitplanet.net>
2016-06-01 09:59:06 +01:00
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_surf->base.SwapInterval > 0) {
|
|
|
|
|
dri2_surf->throttle_callback =
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_frame(dri2_surf->wl_surface_wrapper);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_surf->current = dri2_surf->back;
|
|
|
|
|
dri2_surf->back = NULL;
|
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_attach(dri2_surf->wl_surface_wrapper,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_surf->current->wl_buffer,
|
|
|
|
|
dri2_surf->dx, dri2_surf->dy);
|
|
|
|
|
|
|
|
|
|
dri2_surf->wl_win->attached_width = dri2_surf->base.Width;
|
|
|
|
|
dri2_surf->wl_win->attached_height = dri2_surf->base.Height;
|
|
|
|
|
/* reset resize growing parameters */
|
|
|
|
|
dri2_surf->dx = 0;
|
|
|
|
|
dri2_surf->dy = 0;
|
|
|
|
|
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_damage(dri2_surf->wl_surface_wrapper,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
0, 0, INT32_MAX, INT32_MAX);
|
egl/wayland: Use per-surface event queues
During display initialisation, we need a separate event queue to handle
the registry events, which is correctly handled. But we also need
separate per-surface event queues to handle swapchain-related events,
such as surface frame events and buffer release events. This avoids two
surfaces from the same EGLDisplay, both current on separate threads,
dispatching each other's events.
Create separate per-surface event queues, create wl_surface and wl_drm
proxy wrapper objects per surface, so we eliminate the race around
sending events to the wrong queue. swrast buffers do not need a
dedicated proxy wrapper, as the wl_shm_pool used to create the
wl_buffers, being transient, can itself be assigned to a queue.
Signed-off-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 36b9976e1f99 ("egl/wayland: Avoid race conditions when on non-main thread")
Cc: mesa-stable@lists.freedesktop.org
2017-05-05 14:49:09 +01:00
|
|
|
|
wl_surface_commit(dri2_surf->wl_surface_wrapper);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
/* If we're not waiting for a frame callback then we'll at least throttle
|
|
|
|
|
* to a sync callback so that we always give a chance for the compositor to
|
|
|
|
|
* handle the commit and send a release event before checking for a free
|
|
|
|
|
* buffer */
|
|
|
|
|
if (dri2_surf->throttle_callback == NULL) {
|
2017-01-13 15:05:10 +00:00
|
|
|
|
dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy_wrapper);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_display_flush(dri2_dpy->wl_dpy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,
|
|
|
|
|
int *x, int *y, int *w, int *h,
|
|
|
|
|
void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
|
|
|
|
|
(void) swrast_update_buffers(dri2_surf);
|
|
|
|
|
*x = 0;
|
|
|
|
|
*y = 0;
|
|
|
|
|
*w = dri2_surf->base.Width;
|
|
|
|
|
*h = dri2_surf->base.Height;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_wl_swrast_get_image(__DRIdrawable * read,
|
|
|
|
|
int x, int y, int w, int h,
|
|
|
|
|
char *data, void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
|
|
|
|
|
int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
|
|
|
|
|
int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
|
|
|
|
|
int dst_stride = copy_width;
|
|
|
|
|
char *src, *dst;
|
|
|
|
|
|
|
|
|
|
src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf);
|
|
|
|
|
if (!src) {
|
|
|
|
|
memset(data, 0, copy_width * h);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(data != src);
|
|
|
|
|
assert(copy_width <= src_stride);
|
|
|
|
|
|
|
|
|
|
src += x_offset;
|
|
|
|
|
src += y * src_stride;
|
|
|
|
|
dst = data;
|
|
|
|
|
|
|
|
|
|
if (copy_width > src_stride-x_offset)
|
|
|
|
|
copy_width = src_stride-x_offset;
|
|
|
|
|
if (h > dri2_surf->base.Height-y)
|
|
|
|
|
h = dri2_surf->base.Height-y;
|
|
|
|
|
|
|
|
|
|
for (; h>0; h--) {
|
|
|
|
|
memcpy(dst, src, copy_width);
|
|
|
|
|
src += src_stride;
|
|
|
|
|
dst += dst_stride;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op,
|
|
|
|
|
int x, int y, int w, int h, int stride,
|
|
|
|
|
char *data, void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
|
|
|
|
|
int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);
|
|
|
|
|
int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);
|
|
|
|
|
char *src, *dst;
|
|
|
|
|
|
|
|
|
|
assert(copy_width <= stride);
|
|
|
|
|
|
|
|
|
|
(void) swrast_update_buffers(dri2_surf);
|
|
|
|
|
dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);
|
|
|
|
|
|
|
|
|
|
/* partial copy, copy old content */
|
|
|
|
|
if (copy_width < dst_stride)
|
|
|
|
|
dri2_wl_swrast_get_image(draw, 0, 0,
|
|
|
|
|
dri2_surf->base.Width, dri2_surf->base.Height,
|
|
|
|
|
dst, loaderPrivate);
|
|
|
|
|
|
|
|
|
|
dst += x_offset;
|
|
|
|
|
dst += y * dst_stride;
|
|
|
|
|
|
|
|
|
|
src = data;
|
|
|
|
|
|
|
|
|
|
/* drivers expect we do these checks (and some rely on it) */
|
|
|
|
|
if (copy_width > dst_stride-x_offset)
|
|
|
|
|
copy_width = dst_stride-x_offset;
|
|
|
|
|
if (h > dri2_surf->base.Height-y)
|
|
|
|
|
h = dri2_surf->base.Height-y;
|
|
|
|
|
|
|
|
|
|
for (; h>0; h--) {
|
|
|
|
|
memcpy(dst, src, copy_width);
|
|
|
|
|
src += stride;
|
|
|
|
|
dst += dst_stride;
|
|
|
|
|
}
|
|
|
|
|
dri2_wl_swrast_commit_backbuffer(dri2_surf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_wl_swrast_put_image(__DRIdrawable * draw, int op,
|
|
|
|
|
int x, int y, int w, int h,
|
|
|
|
|
char *data, void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
int stride;
|
|
|
|
|
|
|
|
|
|
stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);
|
|
|
|
|
dri2_wl_swrast_put_image2(draw, op, x, y, w, h,
|
|
|
|
|
stride, data, loaderPrivate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
|
|
|
|
|
|
|
|
|
|
dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case WL_SHM_FORMAT_ARGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_ARGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_SHM_FORMAT_XRGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_XRGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_SHM_FORMAT_RGB565:
|
|
|
|
|
dri2_dpy->formats |= HAS_RGB565;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_shm_listener shm_listener = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.format = shm_handle_format
|
2015-05-01 10:11:20 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
registry_handle_global_swrast(void *data, struct wl_registry *registry, uint32_t name,
|
|
|
|
|
const char *interface, uint32_t version)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
if (strcmp(interface, "wl_shm") == 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_registry_listener registry_listener_swrast = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.global = registry_handle_global_swrast,
|
|
|
|
|
.global_remove = registry_handle_global_remove
|
2015-05-01 10:11:20 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-15 16:14:17 +01:00
|
|
|
|
static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
|
2015-05-01 10:11:20 +01:00
|
|
|
|
.authenticate = NULL,
|
2016-11-28 18:25:19 +00:00
|
|
|
|
.create_window_surface = dri2_wl_create_window_surface,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
.create_pixmap_surface = dri2_wl_create_pixmap_surface,
|
|
|
|
|
.create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
|
|
|
|
|
.destroy_surface = dri2_wl_destroy_surface,
|
|
|
|
|
.create_image = dri2_fallback_create_image_khr,
|
|
|
|
|
.swap_interval = dri2_wl_swap_interval,
|
|
|
|
|
.swap_buffers = dri2_wl_swrast_swap_buffers,
|
|
|
|
|
.swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
|
|
|
|
|
.swap_buffers_region = dri2_fallback_swap_buffers_region,
|
|
|
|
|
.post_sub_buffer = dri2_fallback_post_sub_buffer,
|
|
|
|
|
.copy_buffers = dri2_fallback_copy_buffers,
|
|
|
|
|
.query_buffer_age = dri2_fallback_query_buffer_age,
|
|
|
|
|
.create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
|
|
|
|
|
.get_sync_values = dri2_fallback_get_sync_values,
|
2015-07-21 16:43:59 +01:00
|
|
|
|
.get_dri_drawable = dri2_surface_get_dri_drawable,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-16 18:39:14 +01:00
|
|
|
|
static const __DRIswrastLoaderExtension swrast_loader_extension = {
|
|
|
|
|
.base = { __DRI_SWRAST_LOADER, 2 },
|
|
|
|
|
|
|
|
|
|
.getDrawableInfo = dri2_wl_swrast_get_drawable_info,
|
|
|
|
|
.putImage = dri2_wl_swrast_put_image,
|
|
|
|
|
.getImage = dri2_wl_swrast_get_image,
|
|
|
|
|
.putImage2 = dri2_wl_swrast_put_image2,
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-24 23:32:27 +01:00
|
|
|
|
static const __DRIextension *swrast_loader_extensions[] = {
|
|
|
|
|
&swrast_loader_extension.base,
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy;
|
|
|
|
|
|
|
|
|
|
loader_set_logger(_eglLog);
|
|
|
|
|
|
|
|
|
|
dri2_dpy = calloc(1, sizeof *dri2_dpy);
|
|
|
|
|
if (!dri2_dpy)
|
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
|
|
2017-05-11 17:26:48 +01:00
|
|
|
|
dri2_dpy->fd = -1;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
disp->DriverData = (void *) dri2_dpy;
|
|
|
|
|
if (disp->PlatformDisplay == NULL) {
|
|
|
|
|
dri2_dpy->wl_dpy = wl_display_connect(NULL);
|
|
|
|
|
if (dri2_dpy->wl_dpy == NULL)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_dpy->own_device = 1;
|
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->wl_dpy = disp->PlatformDisplay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
|
|
|
|
|
|
2017-01-13 15:05:10 +00:00
|
|
|
|
dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);
|
|
|
|
|
if (dri2_dpy->wl_dpy_wrapper == NULL)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2017-01-13 15:05:10 +00:00
|
|
|
|
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_dpy->own_device)
|
|
|
|
|
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
|
|
|
|
|
|
2017-01-13 15:05:10 +00:00
|
|
|
|
dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
wl_registry_add_listener(dri2_dpy->wl_registry,
|
|
|
|
|
®istry_listener_swrast, dri2_dpy);
|
|
|
|
|
|
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0)
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
dri2_dpy->driver_name = strdup("swrast");
|
|
|
|
|
if (!dri2_load_driver_swrast(disp))
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->loader_extensions = swrast_loader_extensions;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
if (!dri2_create_screen(disp))
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
2017-05-11 16:20:04 +01:00
|
|
|
|
if (!dri2_setup_extensions(disp))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
dri2_setup_screen(disp);
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_wl_setup_swap_interval(dri2_dpy);
|
|
|
|
|
|
2016-08-25 14:55:06 +01:00
|
|
|
|
if (!dri2_wl_add_configs_for_visuals(drv, disp)) {
|
|
|
|
|
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");
|
2017-05-11 17:26:48 +01:00
|
|
|
|
goto cleanup;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fill vtbl last to prevent accidentally calling virtual function during
|
|
|
|
|
* initialization.
|
|
|
|
|
*/
|
|
|
|
|
dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
|
2017-05-11 17:26:48 +01:00
|
|
|
|
cleanup:
|
|
|
|
|
dri2_display_destroy(disp);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
EGLBoolean initialized = EGL_TRUE;
|
|
|
|
|
|
|
|
|
|
int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
|
|
|
|
|
|
|
|
|
|
if (hw_accel) {
|
|
|
|
|
if (!dri2_initialize_wayland_drm(drv, disp)) {
|
|
|
|
|
initialized = dri2_initialize_wayland_swrast(drv, disp);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
initialized = dri2_initialize_wayland_swrast(drv, disp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return initialized;
|
|
|
|
|
|
|
|
|
|
}
|