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>
|
2019-02-12 18:18:03 +00:00
|
|
|
|
#include "drm-uapi/drm_fourcc.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"
|
2020-12-15 13:39:32 +00:00
|
|
|
|
#include "loader_dri_helper.h"
|
2014-01-11 04:52:48 +00:00
|
|
|
|
#include "loader.h"
|
2017-06-16 18:01:23 +01:00
|
|
|
|
#include "util/u_vector.h"
|
2018-01-18 20:29:14 +00:00
|
|
|
|
#include "util/anon_file.h"
|
2017-07-20 01:27:12 +01:00
|
|
|
|
#include "eglglobals.h"
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2018-05-29 15:41:28 +01:00
|
|
|
|
#include <wayland-egl-backend.h>
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#include <wayland-client.h>
|
|
|
|
|
#include "wayland-drm-client-protocol.h"
|
2017-06-16 18:01:23 +01:00
|
|
|
|
#include "linux-dmabuf-unstable-v1-client-protocol.h"
|
|
|
|
|
|
2018-02-06 11:14:32 +00:00
|
|
|
|
/*
|
|
|
|
|
* The index of entries in this table is used as a bitmask in
|
|
|
|
|
* dri2_dpy->formats, which tracks the formats supported by our server.
|
|
|
|
|
*/
|
2018-02-06 10:07:23 +00:00
|
|
|
|
static const struct dri2_wl_visual {
|
2018-02-06 09:32:22 +00:00
|
|
|
|
const char *format_name;
|
2018-02-06 09:42:27 +00:00
|
|
|
|
uint32_t wl_drm_format;
|
|
|
|
|
uint32_t wl_shm_format;
|
|
|
|
|
int dri_image_format;
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
/* alt_dri_image_format is a substitute wl_buffer format to use for a
|
|
|
|
|
* wl-server unsupported dri_image_format, ie. some other dri_image_format in
|
|
|
|
|
* the table, of the same precision but with different channel ordering, or
|
|
|
|
|
* __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported.
|
|
|
|
|
* The code checks if alt_dri_image_format can be used as a fallback for a
|
|
|
|
|
* dri_image_format for a given wl-server implementation.
|
|
|
|
|
*/
|
|
|
|
|
int alt_dri_image_format;
|
2018-02-06 11:58:45 +00:00
|
|
|
|
int bpp;
|
2019-01-25 00:32:48 +00:00
|
|
|
|
int rgba_shifts[4];
|
|
|
|
|
unsigned int rgba_sizes[4];
|
2018-02-06 09:32:22 +00:00
|
|
|
|
} dri2_wl_visuals[] = {
|
2019-08-30 20:35:22 +01:00
|
|
|
|
{
|
|
|
|
|
"ABGR16F",
|
|
|
|
|
WL_DRM_FORMAT_ABGR16F, WL_SHM_FORMAT_ABGR16161616F,
|
|
|
|
|
__DRI_IMAGE_FORMAT_ABGR16161616F, 0, 64,
|
|
|
|
|
{ 0, 16, 32, 48 },
|
|
|
|
|
{ 16, 16, 16, 16 },
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"XBGR16F",
|
|
|
|
|
WL_DRM_FORMAT_XBGR16F, WL_SHM_FORMAT_XBGR16161616F,
|
|
|
|
|
__DRI_IMAGE_FORMAT_XBGR16161616F, 0, 64,
|
|
|
|
|
{ 0, 16, 32, -1 },
|
|
|
|
|
{ 16, 16, 16, 0 },
|
|
|
|
|
},
|
2018-02-06 18:06:52 +00:00
|
|
|
|
{
|
2019-08-30 20:27:23 +01:00
|
|
|
|
"XRGB2101010",
|
|
|
|
|
WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010,
|
|
|
|
|
__DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32,
|
|
|
|
|
{ 20, 10, 0, -1 },
|
|
|
|
|
{ 10, 10, 10, 0 },
|
2018-02-06 18:06:52 +00:00
|
|
|
|
},
|
|
|
|
|
{
|
2019-08-30 20:27:23 +01:00
|
|
|
|
"ARGB2101010",
|
|
|
|
|
WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010,
|
|
|
|
|
__DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32,
|
|
|
|
|
{ 20, 10, 0, 30 },
|
|
|
|
|
{ 10, 10, 10, 2 },
|
2018-02-06 18:06:52 +00:00
|
|
|
|
},
|
2018-06-13 05:04:11 +01:00
|
|
|
|
{
|
2019-08-30 20:27:23 +01:00
|
|
|
|
"XBGR2101010",
|
|
|
|
|
WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010,
|
|
|
|
|
__DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32,
|
|
|
|
|
{ 0, 10, 20, -1 },
|
|
|
|
|
{ 10, 10, 10, 0 },
|
2018-06-13 05:04:11 +01:00
|
|
|
|
},
|
|
|
|
|
{
|
2019-08-30 20:27:23 +01:00
|
|
|
|
"ABGR2101010",
|
|
|
|
|
WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010,
|
|
|
|
|
__DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32,
|
|
|
|
|
{ 0, 10, 20, 30 },
|
|
|
|
|
{ 10, 10, 10, 2 },
|
2018-06-13 05:04:11 +01:00
|
|
|
|
},
|
2018-02-06 18:06:52 +00:00
|
|
|
|
{
|
2019-08-30 20:27:23 +01:00
|
|
|
|
"XRGB8888",
|
|
|
|
|
WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888,
|
|
|
|
|
__DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
|
|
|
|
|
{ 16, 8, 0, -1 },
|
|
|
|
|
{ 8, 8, 8, 0 },
|
2018-02-06 18:06:52 +00:00
|
|
|
|
},
|
|
|
|
|
{
|
2019-08-30 20:27:23 +01:00
|
|
|
|
"ARGB8888",
|
|
|
|
|
WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888,
|
|
|
|
|
__DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32,
|
|
|
|
|
{ 16, 8, 0, 24 },
|
|
|
|
|
{ 8, 8, 8, 8 },
|
2018-02-06 18:06:52 +00:00
|
|
|
|
},
|
2021-09-23 20:37:19 +01:00
|
|
|
|
{
|
|
|
|
|
"ABGR8888",
|
|
|
|
|
WL_DRM_FORMAT_ABGR8888, WL_SHM_FORMAT_ABGR8888,
|
|
|
|
|
__DRI_IMAGE_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_NONE, 32,
|
|
|
|
|
{ 0, 8, 16, 24 },
|
|
|
|
|
{ 8, 8, 8, 8 },
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"XBGR8888",
|
|
|
|
|
WL_DRM_FORMAT_XBGR8888, WL_SHM_FORMAT_XBGR8888,
|
|
|
|
|
__DRI_IMAGE_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_NONE, 32,
|
|
|
|
|
{ 0, 8, 16, -1 },
|
|
|
|
|
{ 8, 8, 8, 0 },
|
|
|
|
|
},
|
2018-02-06 18:06:52 +00:00
|
|
|
|
{
|
2019-08-30 20:27:23 +01:00
|
|
|
|
"RGB565",
|
|
|
|
|
WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565,
|
|
|
|
|
__DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16,
|
|
|
|
|
{ 11, 5, 0, -1 },
|
|
|
|
|
{ 5, 6, 5, 0 },
|
2018-02-06 18:06:52 +00:00
|
|
|
|
},
|
2018-02-06 09:32:22 +00:00
|
|
|
|
};
|
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
static_assert(ARRAY_SIZE(dri2_wl_visuals) <= EGL_DRI2_MAX_FORMATS,
|
|
|
|
|
"dri2_egl_display::formats is not large enough for "
|
|
|
|
|
"the formats in dri2_wl_visuals");
|
|
|
|
|
|
2018-02-06 10:07:23 +00:00
|
|
|
|
static int
|
|
|
|
|
dri2_wl_visual_idx_from_config(struct dri2_egl_display *dri2_dpy,
|
2021-08-02 21:16:34 +01:00
|
|
|
|
const __DRIconfig *config,
|
|
|
|
|
bool force_opaque)
|
2018-02-06 10:07:23 +00:00
|
|
|
|
{
|
2019-01-25 00:32:48 +00:00
|
|
|
|
int shifts[4];
|
|
|
|
|
unsigned int sizes[4];
|
2018-02-06 10:07:23 +00:00
|
|
|
|
|
2019-01-25 00:32:48 +00:00
|
|
|
|
dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
|
2018-02-06 10:07:23 +00:00
|
|
|
|
|
2018-02-06 10:15:32 +00:00
|
|
|
|
for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
|
2018-02-06 10:07:23 +00:00
|
|
|
|
const struct dri2_wl_visual *wl_visual = &dri2_wl_visuals[i];
|
|
|
|
|
|
2021-08-02 21:16:34 +01:00
|
|
|
|
int cmp_rgb_shifts = memcmp(shifts, wl_visual->rgba_shifts,
|
|
|
|
|
3 * sizeof(shifts[0]));
|
|
|
|
|
int cmp_rgb_sizes = memcmp(sizes, wl_visual->rgba_sizes,
|
|
|
|
|
3 * sizeof(sizes[0]));
|
|
|
|
|
|
|
|
|
|
if (cmp_rgb_shifts == 0 && cmp_rgb_sizes == 0 &&
|
|
|
|
|
wl_visual->rgba_shifts[3] == (force_opaque ? -1 : shifts[3]) &&
|
|
|
|
|
wl_visual->rgba_sizes[3] == (force_opaque ? 0 : sizes[3])) {
|
2018-02-06 10:07:23 +00:00
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 10:20:39 +00:00
|
|
|
|
static int
|
|
|
|
|
dri2_wl_visual_idx_from_fourcc(uint32_t fourcc)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
|
|
|
|
|
/* wl_drm format codes overlap with DRIImage FourCC codes for all formats
|
|
|
|
|
* we support. */
|
|
|
|
|
if (dri2_wl_visuals[i].wl_drm_format == fourcc)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 10:15:32 +00:00
|
|
|
|
static int
|
|
|
|
|
dri2_wl_visual_idx_from_dri_image_format(uint32_t dri_image_format)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
|
|
|
|
|
if (dri2_wl_visuals[i].dri_image_format == dri_image_format)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 10:20:39 +00:00
|
|
|
|
static int
|
|
|
|
|
dri2_wl_visual_idx_from_shm_format(uint32_t shm_format)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
|
|
|
|
|
if (dri2_wl_visuals[i].wl_shm_format == shm_format)
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-13 05:04:15 +01:00
|
|
|
|
bool
|
|
|
|
|
dri2_wl_is_format_supported(void* user_data, uint32_t format)
|
|
|
|
|
{
|
|
|
|
|
_EGLDisplay *disp = (_EGLDisplay *) user_data;
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
int j = dri2_wl_visual_idx_from_fourcc(format);
|
|
|
|
|
|
|
|
|
|
if (j == -1)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; dri2_dpy->driver_configs[i]; i++)
|
|
|
|
|
if (j == dri2_wl_visual_idx_from_config(dri2_dpy,
|
2021-08-02 21:16:34 +01:00
|
|
|
|
dri2_dpy->driver_configs[i],
|
|
|
|
|
false))
|
2018-06-13 05:04:15 +01:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
2018-08-30 09:14:49 +01:00
|
|
|
|
assert (i < ARRAY_SIZE(dri2_surf->color_buffers));
|
|
|
|
|
|
|
|
|
|
if (dri2_surf->color_buffers[i].wl_release) {
|
2012-12-14 04:30:45 +00:00
|
|
|
|
wl_buffer_destroy(buffer);
|
2018-08-30 09:14:49 +01:00
|
|
|
|
dri2_surf->color_buffers[i].wl_release = false;
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_surf->color_buffers[i].locked = false;
|
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);
|
|
|
|
|
|
2020-03-03 10:52:32 +00:00
|
|
|
|
if (dri2_surf->base.Width == wl_win->width &&
|
|
|
|
|
dri2_surf->base.Height == wl_win->height)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-10-08 14:55:44 +01:00
|
|
|
|
dri2_surf->resized = true;
|
|
|
|
|
|
2018-06-06 11:13:05 +01:00
|
|
|
|
/* Update the surface size as soon as native window is resized; from user
|
2018-08-10 12:37:17 +01:00
|
|
|
|
* pov, this makes the effect that resize is done immediately after native
|
2018-06-06 11:13:05 +01:00
|
|
|
|
* window resize, without requiring to wait until the first draw.
|
|
|
|
|
*
|
|
|
|
|
* A more detailed and lengthy explanation can be found at
|
|
|
|
|
* https://lists.freedesktop.org/archives/mesa-dev/2018-June/196474.html
|
|
|
|
|
*/
|
|
|
|
|
if (!dri2_surf->back) {
|
|
|
|
|
dri2_surf->base.Width = wl_win->width;
|
|
|
|
|
dri2_surf->base.Height = wl_win->height;
|
|
|
|
|
}
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-20 01:27:12 +01:00
|
|
|
|
static struct wl_surface *
|
|
|
|
|
get_wl_surface_proxy(struct wl_egl_window *window)
|
|
|
|
|
{
|
|
|
|
|
/* Version 3 of wl_egl_window introduced a version field at the same
|
|
|
|
|
* location where a pointer to wl_surface was stored. Thus, if
|
2018-08-10 12:37:17 +01:00
|
|
|
|
* window->version is dereferenceable, we've been given an older version of
|
2017-07-20 01:27:12 +01:00
|
|
|
|
* wl_egl_window, and window->version points to wl_surface */
|
|
|
|
|
if (_eglPointerIsDereferencable((void *)(window->version))) {
|
|
|
|
|
return wl_proxy_create_wrapper((void *)(window->version));
|
|
|
|
|
}
|
|
|
|
|
return wl_proxy_create_wrapper(window->surface);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().
|
2011-02-04 11:39:40 +00:00
|
|
|
|
*/
|
|
|
|
|
static _EGLSurface *
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,
|
|
|
|
|
void *native_window, const EGLint *attrib_list)
|
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;
|
2018-02-06 10:07:23 +00:00
|
|
|
|
int visual_idx;
|
2015-06-10 01:49:29 +01:00
|
|
|
|
const __DRIconfig *config;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2021-07-20 13:40:00 +01:00
|
|
|
|
if (!window) {
|
|
|
|
|
_eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (window->driver_private) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
2018-02-06 10:07:23 +00:00
|
|
|
|
if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,
|
2019-05-01 23:42:26 +01:00
|
|
|
|
attrib_list, false, native_window))
|
2011-02-04 11:39:40 +00:00
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
|
2018-02-06 10:07:23 +00:00
|
|
|
|
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
|
|
|
|
|
dri2_surf->base.GLColorspace);
|
2018-05-02 17:20:16 +01:00
|
|
|
|
|
|
|
|
|
if (!config) {
|
|
|
|
|
_eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");
|
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-04 11:22:49 +01:00
|
|
|
|
dri2_surf->base.Width = window->width;
|
|
|
|
|
dri2_surf->base.Height = window->height;
|
|
|
|
|
|
2021-08-02 21:16:34 +01:00
|
|
|
|
#ifndef NDEBUG
|
|
|
|
|
/* Enforce that every visual has an opaque variant (requirement to support
|
|
|
|
|
* EGL_EXT_present_opaque)
|
|
|
|
|
*/
|
|
|
|
|
for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
|
|
|
|
|
const struct dri2_wl_visual *transparent_visual = &dri2_wl_visuals[i];
|
|
|
|
|
if (transparent_visual->rgba_sizes[3] == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool found_opaque_equivalent = false;
|
|
|
|
|
for (unsigned int j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) {
|
|
|
|
|
const struct dri2_wl_visual *opaque_visual = &dri2_wl_visuals[j];
|
|
|
|
|
if (opaque_visual->rgba_sizes[3] != 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int cmp_rgb_shifts = memcmp(transparent_visual->rgba_shifts,
|
|
|
|
|
opaque_visual->rgba_shifts,
|
|
|
|
|
3 * sizeof(opaque_visual->rgba_shifts[0]));
|
|
|
|
|
int cmp_rgb_sizes = memcmp(transparent_visual->rgba_sizes,
|
|
|
|
|
opaque_visual->rgba_sizes,
|
|
|
|
|
3 * sizeof(opaque_visual->rgba_sizes[0]));
|
|
|
|
|
|
|
|
|
|
if (cmp_rgb_shifts == 0 && cmp_rgb_sizes == 0) {
|
|
|
|
|
found_opaque_equivalent = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert(found_opaque_equivalent);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config,
|
|
|
|
|
dri2_surf->base.PresentOpaque);
|
2018-02-06 10:07:23 +00:00
|
|
|
|
assert(visual_idx != -1);
|
|
|
|
|
|
2017-08-27 11:20:32 +01:00
|
|
|
|
if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) {
|
2018-02-06 10:07:23 +00:00
|
|
|
|
dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format;
|
2017-02-13 14:06:10 +00:00
|
|
|
|
} else {
|
2017-05-12 14:19:59 +01:00
|
|
|
|
assert(dri2_dpy->wl_shm);
|
2018-02-06 10:07:23 +00:00
|
|
|
|
dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format;
|
2017-02-13 14:06:10 +00:00
|
|
|
|
}
|
2011-08-31 21:45:04 +01: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
|
|
|
|
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);
|
|
|
|
|
|
2017-07-20 01:27:12 +01:00
|
|
|
|
dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(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
|
|
|
|
if (!dri2_surf->wl_surface_wrapper) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
2017-08-27 11:20:27 +01:00
|
|
|
|
goto cleanup_dpy_wrapper;
|
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 *)dri2_surf->wl_surface_wrapper,
|
|
|
|
|
dri2_surf->wl_queue);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2017-08-27 11:20:34 +01:00
|
|
|
|
dri2_surf->wl_win = window;
|
2018-05-29 15:41:28 +01:00
|
|
|
|
dri2_surf->wl_win->driver_private = dri2_surf;
|
2016-10-24 09:48:11 +01:00
|
|
|
|
dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;
|
2017-08-27 11:20:34 +01:00
|
|
|
|
if (dri2_dpy->flush)
|
|
|
|
|
dri2_surf->wl_win->resize_callback = resize_callback;
|
2012-11-30 15:41:02 +00:00
|
|
|
|
|
2019-06-07 06:12:42 +01:00
|
|
|
|
if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))
|
2017-08-27 11:20:27 +01:00
|
|
|
|
goto cleanup_surf_wrapper;
|
2016-11-28 18:25:19 +00:00
|
|
|
|
|
2017-07-31 14:49:31 +01:00
|
|
|
|
dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;
|
2016-11-28 18:25:19 +00:00
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return &dri2_surf->base;
|
|
|
|
|
|
2017-08-27 11:20:27 +01:00
|
|
|
|
cleanup_surf_wrapper:
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
|
|
|
|
|
cleanup_dpy_wrapper:
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
|
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 *
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,
|
|
|
|
|
void *native_window, const EGLint *attrib_list)
|
2014-02-09 17:13:27 +00:00
|
|
|
|
{
|
|
|
|
|
/* 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
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglDestroySurface(), drv->DestroySurface().
|
2011-02-04 11:39:40 +00:00
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_destroy_surface(_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);
|
|
|
|
|
|
2015-11-25 05:27:02 +00:00
|
|
|
|
dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2012-12-14 04:30:45 +00:00
|
|
|
|
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
|
|
|
|
|
2017-08-04 16:16:11 +01:00
|
|
|
|
if (dri2_dpy->dri2)
|
|
|
|
|
dri2_egl_surface_free_local_buffers(dri2_surf);
|
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) {
|
2018-05-29 15:41:28 +01:00
|
|
|
|
dri2_surf->wl_win->driver_private = NULL;
|
2016-10-24 09:48:11 +01:00
|
|
|
|
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
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);
|
2017-08-27 11:20:28 +01:00
|
|
|
|
if (dri2_surf->wl_drm_wrapper)
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);
|
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_event_queue_destroy(dri2_surf->wl_queue);
|
|
|
|
|
|
2017-09-15 18:32:42 +01:00
|
|
|
|
dri2_fini_surface(surf);
|
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);
|
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2018-08-30 09:14:49 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].wl_buffer) {
|
|
|
|
|
if (dri2_surf->color_buffers[i].locked) {
|
|
|
|
|
dri2_surf->color_buffers[i].wl_release = true;
|
|
|
|
|
} else {
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
|
|
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;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
}
|
2011-09-01 08:17:04 +01:00
|
|
|
|
|
2017-08-04 16:16:11 +01:00
|
|
|
|
if (dri2_dpy->dri2)
|
|
|
|
|
dri2_egl_surface_free_local_buffers(dri2_surf);
|
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);
|
2017-06-22 19:00:40 +01:00
|
|
|
|
int use_flags;
|
2018-02-06 11:51:17 +00:00
|
|
|
|
int visual_idx;
|
2015-02-11 03:15:31 +00:00
|
|
|
|
unsigned int dri_image_format;
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
unsigned int linear_dri_image_format;
|
2017-06-16 18:01:23 +01:00
|
|
|
|
uint64_t *modifiers;
|
|
|
|
|
int num_modifiers;
|
2015-02-11 03:15:31 +00:00
|
|
|
|
|
2018-02-06 11:51:17 +00:00
|
|
|
|
visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
|
|
|
|
|
assert(visual_idx != -1);
|
|
|
|
|
dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format;
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
linear_dri_image_format = dri_image_format;
|
2018-02-06 10:29:13 +00:00
|
|
|
|
modifiers = u_vector_tail(&dri2_dpy->wl_modifiers[visual_idx]);
|
|
|
|
|
num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers[visual_idx]);
|
2011-02-11 01:23:14 +00:00
|
|
|
|
|
2019-09-26 22:45:39 +01:00
|
|
|
|
if (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {
|
|
|
|
|
/* For the purposes of this function, an INVALID modifier on its own
|
|
|
|
|
* means the modifiers aren't supported.
|
|
|
|
|
*/
|
|
|
|
|
num_modifiers = 0;
|
|
|
|
|
}
|
|
|
|
|
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
/* Substitute dri image format if server does not support original format */
|
2018-11-27 12:27:45 +00:00
|
|
|
|
if (!BITSET_TEST(dri2_dpy->formats, visual_idx))
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format;
|
|
|
|
|
|
|
|
|
|
/* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and
|
|
|
|
|
* the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free
|
|
|
|
|
* of bugs.
|
|
|
|
|
*/
|
|
|
|
|
assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE);
|
2018-11-27 12:27:45 +00:00
|
|
|
|
assert(BITSET_TEST(dri2_dpy->formats,
|
|
|
|
|
dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format)));
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01: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) {
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2018-08-10 12:37:17 +01:00
|
|
|
|
/* Get an unlocked buffer, preferably one with a dri_buffer
|
2013-11-15 13:50:50 +00:00
|
|
|
|
* 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
|
2017-08-07 16:34:51 +01:00
|
|
|
|
* us, and try again. wl_display_dispatch_queue will process any pending
|
|
|
|
|
* events, however not all servers flush on issuing a buffer release
|
|
|
|
|
* event. So, we spam the server with roundtrips as they always cause a
|
|
|
|
|
* client flush.
|
|
|
|
|
*/
|
|
|
|
|
if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy,
|
|
|
|
|
dri2_surf->wl_queue) < 0)
|
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
|
|
|
|
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;
|
|
|
|
|
|
2020-05-11 17:26:30 +01:00
|
|
|
|
if (dri2_surf->base.ProtectedContent) {
|
|
|
|
|
/* Protected buffers can't be read from another GPU */
|
|
|
|
|
if (dri2_dpy->is_different_gpu)
|
|
|
|
|
return -1;
|
|
|
|
|
use_flags |= __DRI_IMAGE_USE_PROTECTED;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu &&
|
|
|
|
|
dri2_surf->back->linear_copy == NULL) {
|
2017-06-16 18:01:23 +01:00
|
|
|
|
/* The LINEAR modifier should be a perfect alias of the LINEAR use
|
|
|
|
|
* flag; try the new interface first before the old, then fall back. */
|
2020-12-15 13:39:32 +00:00
|
|
|
|
uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR;
|
|
|
|
|
|
|
|
|
|
dri2_surf->back->linear_copy =
|
|
|
|
|
loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
linear_dri_image_format,
|
|
|
|
|
use_flags | __DRI_IMAGE_USE_LINEAR,
|
|
|
|
|
&linear_mod, 1, NULL);
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_surf->back->linear_copy == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->back->dri_image == NULL) {
|
2017-06-16 18:01:23 +01:00
|
|
|
|
/* If our DRIImage implementation does not support
|
|
|
|
|
* createImageWithModifiers, then fall back to the old createImage,
|
|
|
|
|
* and hope it allocates an image which is acceptable to the winsys.
|
|
|
|
|
*/
|
2020-12-15 13:39:32 +00:00
|
|
|
|
dri2_surf->back->dri_image =
|
|
|
|
|
loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
dri_image_format,
|
|
|
|
|
dri2_dpy->is_different_gpu ? 0 : use_flags,
|
|
|
|
|
modifiers, num_modifiers, NULL);
|
2017-06-16 18:01:23 +01:00
|
|
|
|
|
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
|
|
|
|
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_surf->back->locked = true;
|
2013-11-09 06:10:36 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
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);
|
2012-11-22 13:34:49 +00:00
|
|
|
|
|
2021-07-20 13:54:16 +01:00
|
|
|
|
if (dri2_surf->wl_win &&
|
|
|
|
|
(dri2_surf->base.Width != dri2_surf->wl_win->width ||
|
|
|
|
|
dri2_surf->base.Height != dri2_surf->wl_win->height)) {
|
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
|
|
|
|
|
2021-10-08 14:55:44 +01:00
|
|
|
|
if (dri2_surf->resized) {
|
|
|
|
|
dri2_wl_release_buffers(dri2_surf);
|
|
|
|
|
dri2_surf->resized = false;
|
2018-11-20 17:06:38 +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. */
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2012-12-14 04:30:45 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-06 08:54:27 +01:00
|
|
|
|
static int
|
|
|
|
|
update_buffers_if_needed(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
if (dri2_surf->back != NULL)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return update_buffers(dri2_surf);
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
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++) {
|
2017-08-04 16:16:11 +01:00
|
|
|
|
__DRIbuffer *local;
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
switch (attachments[i]) {
|
|
|
|
|
case __DRI_BUFFER_BACK_LEFT:
|
|
|
|
|
back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
|
2017-06-10 14:54:05 +01:00
|
|
|
|
break;
|
2013-11-09 06:10:36 +00:00
|
|
|
|
default:
|
2017-08-04 16:16:11 +01:00
|
|
|
|
local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],
|
|
|
|
|
attachments[i + 1]);
|
|
|
|
|
|
|
|
|
|
if (!local) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");
|
2017-06-10 14:54:05 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2017-08-04 16:16:11 +01:00
|
|
|
|
dri2_surf->buffers[j] = *local;
|
2017-06-10 14:54:05 +01:00
|
|
|
|
break;
|
2013-11-09 06:10:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
*out_count = j;
|
|
|
|
|
if (j == 0)
|
2017-06-10 14:54:05 +01:00
|
|
|
|
return NULL;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
*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;
|
2018-02-06 11:58:45 +00:00
|
|
|
|
int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);
|
2015-02-11 03:15:31 +00:00
|
|
|
|
|
2018-02-06 11:58:45 +00:00
|
|
|
|
if (visual_idx == -1)
|
2015-02-11 03:15:31 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < count; ++i) {
|
2011-02-04 11:39:40 +00:00
|
|
|
|
attachments_with_format[2*i] = attachments[i];
|
2018-02-06 11:58:45 +00:00
|
|
|
|
attachments_with_format[2*i + 1] = dri2_wl_visuals[visual_idx].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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 16:53:11 +01:00
|
|
|
|
static unsigned
|
|
|
|
|
dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap)
|
|
|
|
|
{
|
|
|
|
|
switch (cap) {
|
|
|
|
|
case DRI_LOADER_CAP_FP16:
|
|
|
|
|
return 1;
|
2021-09-23 20:37:19 +01:00
|
|
|
|
case DRI_LOADER_CAP_RGBA_ORDERING:
|
|
|
|
|
return 1;
|
2019-09-10 16:53:11 +01:00
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 18:21:48 +01:00
|
|
|
|
static const __DRIdri2LoaderExtension dri2_loader_extension = {
|
2019-09-10 16:53:11 +01:00
|
|
|
|
.base = { __DRI_DRI2_LOADER, 4 },
|
2016-08-16 18:21:48 +01:00
|
|
|
|
|
|
|
|
|
.getBuffers = dri2_wl_get_buffers,
|
|
|
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
|
|
|
|
.getBuffersWithFormat = dri2_wl_get_buffers_with_format,
|
2019-09-10 16:53:11 +01:00
|
|
|
|
.getCapability = dri2_wl_get_capability,
|
2016-08-16 18:21:48 +01:00
|
|
|
|
};
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
static const __DRIimageLoaderExtension image_loader_extension = {
|
2019-09-10 16:53:11 +01:00
|
|
|
|
.base = { __DRI_IMAGE_LOADER, 2 },
|
2014-02-12 18:32:59 +00:00
|
|
|
|
|
|
|
|
|
.getBuffers = image_get_buffers,
|
2014-01-28 20:47:38 +00:00
|
|
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
2019-09-10 16:53:11 +01:00
|
|
|
|
.getCapability = dri2_wl_get_capability,
|
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
|
|
|
|
};
|
|
|
|
|
|
2017-10-30 20:52:22 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
get_fourcc(struct dri2_egl_display *dri2_dpy,
|
|
|
|
|
__DRIimage *image, int *fourcc)
|
|
|
|
|
{
|
|
|
|
|
EGLBoolean query;
|
2017-11-16 10:02:15 +00:00
|
|
|
|
int dri_format;
|
2018-02-06 11:51:17 +00:00
|
|
|
|
int visual_idx;
|
2017-10-30 20:52:22 +00:00
|
|
|
|
|
|
|
|
|
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC,
|
|
|
|
|
fourcc);
|
|
|
|
|
if (query)
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT,
|
|
|
|
|
&dri_format);
|
|
|
|
|
if (!query)
|
|
|
|
|
return false;
|
|
|
|
|
|
2018-02-06 11:51:17 +00:00
|
|
|
|
visual_idx = dri2_wl_visual_idx_from_dri_image_format(dri_format);
|
|
|
|
|
if (visual_idx == -1)
|
2017-10-30 20:52:22 +00:00
|
|
|
|
return false;
|
2018-02-06 11:51:17 +00:00
|
|
|
|
|
|
|
|
|
*fourcc = dri2_wl_visuals[visual_idx].wl_drm_format;
|
|
|
|
|
return true;
|
2017-10-30 20:52:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-16 17:29:42 +01:00
|
|
|
|
static struct wl_buffer *
|
|
|
|
|
create_wl_buffer(struct dri2_egl_display *dri2_dpy,
|
|
|
|
|
struct dri2_egl_surface *dri2_surf,
|
|
|
|
|
__DRIimage *image)
|
2013-02-02 17:26:12 +00:00
|
|
|
|
{
|
2017-06-16 17:29:42 +01:00
|
|
|
|
struct wl_buffer *ret;
|
2017-10-02 16:40:53 +01:00
|
|
|
|
EGLBoolean query;
|
2017-06-16 18:01:23 +01:00
|
|
|
|
int width, height, fourcc, num_planes;
|
2017-10-02 16:40:53 +01:00
|
|
|
|
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
|
2017-06-16 17:33:56 +01:00
|
|
|
|
|
2017-10-02 16:40:53 +01:00
|
|
|
|
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
|
|
|
|
|
query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT,
|
|
|
|
|
&height);
|
2017-10-30 20:52:22 +00:00
|
|
|
|
query &= get_fourcc(dri2_dpy, image, &fourcc);
|
2017-10-02 16:40:53 +01:00
|
|
|
|
if (!query)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,
|
|
|
|
|
&num_planes);
|
|
|
|
|
if (!query)
|
|
|
|
|
num_planes = 1;
|
2017-06-16 18:01:23 +01:00
|
|
|
|
|
2017-10-02 16:40:53 +01:00
|
|
|
|
if (dri2_dpy->image->base.version >= 15) {
|
2017-06-16 18:01:23 +01:00
|
|
|
|
int mod_hi, mod_lo;
|
|
|
|
|
|
2017-10-02 16:40:53 +01:00
|
|
|
|
query = dri2_dpy->image->queryImage(image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
|
|
|
|
|
&mod_hi);
|
|
|
|
|
query &= dri2_dpy->image->queryImage(image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
|
|
|
|
|
&mod_lo);
|
2017-10-02 16:40:53 +01:00
|
|
|
|
if (query) {
|
2018-08-16 15:22:46 +01:00
|
|
|
|
modifier = combine_u32_into_u64(mod_hi, mod_lo);
|
2017-10-02 16:40:53 +01:00
|
|
|
|
}
|
2017-10-02 16:40:53 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-09-26 22:45:39 +01:00
|
|
|
|
bool supported_modifier = false;
|
2020-03-24 03:19:51 +00:00
|
|
|
|
bool mod_invalid_supported = false;
|
|
|
|
|
int visual_idx = dri2_wl_visual_idx_from_fourcc(fourcc);
|
|
|
|
|
assert(visual_idx != -1);
|
|
|
|
|
|
|
|
|
|
uint64_t *mod;
|
|
|
|
|
u_vector_foreach(mod, &dri2_dpy->wl_modifiers[visual_idx]) {
|
|
|
|
|
if (*mod == DRM_FORMAT_MOD_INVALID) {
|
|
|
|
|
mod_invalid_supported = true;
|
2019-09-26 22:45:39 +01:00
|
|
|
|
}
|
2020-03-24 03:19:51 +00:00
|
|
|
|
if (*mod == modifier) {
|
|
|
|
|
supported_modifier = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!supported_modifier && mod_invalid_supported) {
|
|
|
|
|
/* If the server has advertised DRM_FORMAT_MOD_INVALID then we trust
|
|
|
|
|
* that the client has allocated the buffer with the right implicit
|
|
|
|
|
* modifier for the format, even though it's allocated a buffer the
|
|
|
|
|
* server hasn't explicitly claimed to support. */
|
|
|
|
|
modifier = DRM_FORMAT_MOD_INVALID;
|
|
|
|
|
supported_modifier = true;
|
2019-09-26 22:45:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->wl_dmabuf && supported_modifier) {
|
2017-10-02 16:40:53 +01:00
|
|
|
|
struct zwp_linux_buffer_params_v1 *params;
|
|
|
|
|
int i;
|
2017-06-16 18:01:23 +01:00
|
|
|
|
|
|
|
|
|
/* We don't need a wrapper for wl_dmabuf objects, because we have to
|
|
|
|
|
* create the intermediate params object; we can set the queue on this,
|
|
|
|
|
* and the wl_buffer inherits it race-free. */
|
|
|
|
|
params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);
|
|
|
|
|
if (dri2_surf)
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_planes; i++) {
|
|
|
|
|
__DRIimage *p_image;
|
2017-10-02 16:40:53 +01:00
|
|
|
|
int stride, offset;
|
|
|
|
|
int fd = -1;
|
2017-06-16 18:01:23 +01:00
|
|
|
|
|
2017-09-28 08:18:33 +01:00
|
|
|
|
p_image = dri2_dpy->image->fromPlanar(image, i, NULL);
|
2017-06-16 18:01:23 +01:00
|
|
|
|
if (!p_image) {
|
2017-09-28 08:18:33 +01:00
|
|
|
|
assert(i == 0);
|
|
|
|
|
p_image = image;
|
2017-06-16 18:01:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-02 16:40:53 +01:00
|
|
|
|
query = dri2_dpy->image->queryImage(p_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_FD,
|
|
|
|
|
&fd);
|
|
|
|
|
query &= dri2_dpy->image->queryImage(p_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_STRIDE,
|
|
|
|
|
&stride);
|
|
|
|
|
query &= dri2_dpy->image->queryImage(p_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_OFFSET,
|
|
|
|
|
&offset);
|
2017-06-16 18:01:23 +01:00
|
|
|
|
if (image != p_image)
|
|
|
|
|
dri2_dpy->image->destroyImage(p_image);
|
|
|
|
|
|
2017-10-02 16:40:53 +01:00
|
|
|
|
if (!query) {
|
|
|
|
|
if (fd >= 0)
|
|
|
|
|
close(fd);
|
|
|
|
|
zwp_linux_buffer_params_v1_destroy(params);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-16 18:01:23 +01:00
|
|
|
|
zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,
|
2017-10-02 16:40:53 +01:00
|
|
|
|
modifier >> 32, modifier & 0xffffffff);
|
2017-06-16 18:01:23 +01:00
|
|
|
|
close(fd);
|
|
|
|
|
}
|
2013-02-02 17:26:12 +00:00
|
|
|
|
|
2017-06-16 18:01:23 +01:00
|
|
|
|
ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,
|
|
|
|
|
fourcc, 0);
|
|
|
|
|
zwp_linux_buffer_params_v1_destroy(params);
|
|
|
|
|
} else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
|
2017-06-16 17:37:19 +01:00
|
|
|
|
struct wl_drm *wl_drm =
|
|
|
|
|
dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
|
2017-06-16 17:33:56 +01:00
|
|
|
|
int fd, stride;
|
|
|
|
|
|
2017-06-16 18:01:23 +01:00
|
|
|
|
if (num_planes > 1)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
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);
|
2017-06-16 17:37:19 +01:00
|
|
|
|
ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,
|
|
|
|
|
stride, 0, 0, 0, 0);
|
2013-02-02 17:26:12 +00:00
|
|
|
|
close(fd);
|
|
|
|
|
} else {
|
2017-06-16 17:37:19 +01:00
|
|
|
|
struct wl_drm *wl_drm =
|
|
|
|
|
dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;
|
2017-06-16 17:33:56 +01:00
|
|
|
|
int name, stride;
|
|
|
|
|
|
2017-06-16 18:01:23 +01:00
|
|
|
|
if (num_planes > 1)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
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);
|
2017-06-16 17:37:19 +01:00
|
|
|
|
ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc);
|
2013-02-02 17:26:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-16 17:29:42 +01:00
|
|
|
|
return ret;
|
2013-02-02 17:26:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
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;
|
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < n_rects; i++) {
|
2016-02-16 16:34:39 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2020-05-23 00:44:52 +01:00
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglSwapBuffers(), drv->SwapBuffers().
|
2011-02-04 11:39:40 +00:00
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp,
|
2014-01-28 20:47:38 +00:00
|
|
|
|
_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);
|
|
|
|
|
|
2021-07-20 13:54:16 +01:00
|
|
|
|
if (!dri2_surf->wl_win)
|
|
|
|
|
return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");
|
|
|
|
|
|
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;
|
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
|
2012-12-14 04:32:14 +00:00
|
|
|
|
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. */
|
2019-05-06 08:54:27 +01:00
|
|
|
|
if (update_buffers_if_needed(dri2_surf) < 0)
|
2017-06-20 15:40:28 +01:00
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
|
2013-02-06 20:41:54 +00:00
|
|
|
|
|
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;
|
|
|
|
|
|
2017-06-16 17:29:42 +01:00
|
|
|
|
if (!dri2_surf->current->wl_buffer) {
|
|
|
|
|
__DRIimage *image;
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->is_different_gpu)
|
|
|
|
|
image = dri2_surf->current->linear_copy;
|
|
|
|
|
else
|
|
|
|
|
image = dri2_surf->current->dri_image;
|
|
|
|
|
|
|
|
|
|
dri2_surf->current->wl_buffer =
|
|
|
|
|
create_wl_buffer(dri2_dpy, dri2_surf, image);
|
|
|
|
|
|
2018-08-30 09:14:49 +01:00
|
|
|
|
dri2_surf->current->wl_release = false;
|
|
|
|
|
|
2017-06-16 17:29:42 +01:00
|
|
|
|
wl_buffer_add_listener(dri2_surf->current->wl_buffer,
|
|
|
|
|
&wl_buffer_listener, 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
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
|
2012-12-14 04:32:14 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
|
|
|
|
|
|
2019-05-06 08:54:27 +01:00
|
|
|
|
if (update_buffers_if_needed(dri2_surf) < 0) {
|
2012-12-14 04:32:14 +00:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
|
2017-06-08 10:24:24 +01:00
|
|
|
|
return -1;
|
2012-12-14 04:32:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dri2_surf->back->age;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 16:59:31 +00:00
|
|
|
|
static EGLBoolean
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
|
2012-02-10 16:59:31 +00:00
|
|
|
|
{
|
2018-04-22 15:48:15 +01:00
|
|
|
|
return dri2_wl_swap_buffers_with_damage(disp, draw, NULL, 0);
|
2012-02-10 16:59:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-28 15:07:03 +00:00
|
|
|
|
static struct wl_buffer *
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_create_wayland_buffer_from_image(_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;
|
2018-02-06 10:15:32 +00:00
|
|
|
|
int format, visual_idx;
|
2013-10-28 15:07:03 +00:00
|
|
|
|
|
2018-02-06 10:15:32 +00:00
|
|
|
|
/* Check the upstream display supports this buffer's format. */
|
2013-10-28 15:07:03 +00:00
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
|
2018-02-06 10:15:32 +00:00
|
|
|
|
visual_idx = dri2_wl_visual_idx_from_dri_image_format(format);
|
|
|
|
|
if (visual_idx == -1)
|
|
|
|
|
goto bad_format;
|
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
if (!BITSET_TEST(dri2_dpy->formats, visual_idx))
|
2013-10-28 15:07:03 +00:00
|
|
|
|
goto bad_format;
|
|
|
|
|
|
2017-06-16 17:37:19 +01:00
|
|
|
|
buffer = create_wl_buffer(dri2_dpy, NULL, image);
|
2013-10-28 15:07:03 +00:00
|
|
|
|
|
|
|
|
|
/* The buffer object will have been created with our internal event queue
|
2017-08-27 11:20:30 +01:00
|
|
|
|
* because it is using wl_dmabuf/wl_drm as a proxy factory. We want the
|
2013-10-28 15:07:03 +00:00
|
|
|
|
* buffer to be used by the application so we'll reset it to the display's
|
2017-06-16 17:37:19 +01:00
|
|
|
|
* default event queue. This isn't actually racy, as the only event the
|
|
|
|
|
* buffer can get is a buffer release, which doesn't happen with an explicit
|
|
|
|
|
* attach. */
|
2013-10-28 15:07:03 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_dpy->authenticated = false;
|
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 */
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_dpy->authenticated = true;
|
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)",
|
2017-06-10 14:54:05 +01:00
|
|
|
|
dri2_dpy->device_name, strerror(errno));
|
2018-11-27 11:36:01 +00:00
|
|
|
|
free(dri2_dpy->device_name);
|
2018-11-28 17:30:36 +00:00
|
|
|
|
dri2_dpy->device_name = NULL;
|
2011-04-14 15:42:41 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 12:27:06 +01:00
|
|
|
|
if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_dpy->authenticated = true;
|
2015-05-01 00:30:10 +01:00
|
|
|
|
} else {
|
2018-11-23 12:55:38 +00:00
|
|
|
|
if (drmGetMagic(dri2_dpy->fd, &magic)) {
|
|
|
|
|
close(dri2_dpy->fd);
|
|
|
|
|
dri2_dpy->fd = -1;
|
|
|
|
|
free(dri2_dpy->device_name);
|
2018-11-28 17:30:36 +00:00
|
|
|
|
dri2_dpy->device_name = NULL;
|
2018-11-23 12:55:38 +00:00
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: drmGetMagic failed");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-05-01 00:30:10 +01:00
|
|
|
|
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;
|
2018-02-06 10:20:39 +00:00
|
|
|
|
int visual_idx = dri2_wl_visual_idx_from_fourcc(format);
|
2011-08-31 21:45:04 +01:00
|
|
|
|
|
2018-02-06 10:20:39 +00:00
|
|
|
|
if (visual_idx == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
BITSET_SET(dri2_dpy->formats, visual_idx);
|
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;
|
|
|
|
|
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_dpy->authenticated = true;
|
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
|
|
|
|
};
|
|
|
|
|
|
2017-06-16 18:01:23 +01:00
|
|
|
|
static void
|
|
|
|
|
dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
|
|
|
|
|
uint32_t format)
|
|
|
|
|
{
|
|
|
|
|
/* formats are implicitly advertised by the 'modifier' event, so ignore */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,
|
|
|
|
|
uint32_t format, uint32_t modifier_hi,
|
|
|
|
|
uint32_t modifier_lo)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
2018-02-06 10:20:39 +00:00
|
|
|
|
int visual_idx = dri2_wl_visual_idx_from_fourcc(format);
|
2018-02-06 10:29:13 +00:00
|
|
|
|
uint64_t *mod;
|
2017-06-16 18:01:23 +01:00
|
|
|
|
|
2018-02-06 10:29:13 +00:00
|
|
|
|
if (visual_idx == -1)
|
2017-07-21 12:05:17 +01:00
|
|
|
|
return;
|
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
BITSET_SET(dri2_dpy->formats, visual_idx);
|
2018-02-06 10:29:13 +00:00
|
|
|
|
|
|
|
|
|
mod = u_vector_add(&dri2_dpy->wl_modifiers[visual_idx]);
|
2018-08-16 15:22:46 +01:00
|
|
|
|
*mod = combine_u32_into_u64(modifier_hi, modifier_lo);
|
2017-06-16 18:01:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
|
|
|
|
|
.format = dmabuf_ignore_format,
|
|
|
|
|
.modifier = dmabuf_handle_modifier,
|
|
|
|
|
};
|
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
static void
|
2017-06-10 14:54:05 +01:00
|
|
|
|
registry_handle_global_drm(void *data, struct wl_registry *registry,
|
|
|
|
|
uint32_t name, const char *interface,
|
|
|
|
|
uint32_t version)
|
2012-10-11 03:10:42 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
if (strcmp(interface, "wl_drm") == 0) {
|
|
|
|
|
dri2_dpy->wl_drm =
|
2017-06-10 14:54:44 +01:00
|
|
|
|
wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2));
|
2012-10-11 03:10:42 +01:00
|
|
|
|
wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
|
2017-06-16 18:01:23 +01:00
|
|
|
|
} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {
|
|
|
|
|
dri2_dpy->wl_dmabuf =
|
|
|
|
|
wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,
|
|
|
|
|
MIN2(version, 3));
|
|
|
|
|
zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,
|
|
|
|
|
dri2_dpy);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-18 21:53:46 +01:00
|
|
|
|
static void
|
|
|
|
|
registry_handle_global_remove(void *data, struct wl_registry *registry,
|
2017-06-10 14:54:05 +01:00
|
|
|
|
uint32_t name)
|
2013-06-18 21:53:46 +01:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
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 void
|
2017-08-05 00:25:46 +01:00
|
|
|
|
dri2_wl_setup_swap_interval(_EGLDisplay *disp)
|
2013-11-15 13:50:50 +00:00
|
|
|
|
{
|
|
|
|
|
/* 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 */
|
|
|
|
|
|
2017-08-05 00:25:46 +01:00
|
|
|
|
dri2_setup_swap_interval(disp, 1);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
.destroy_surface = dri2_wl_destroy_surface,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.create_image = dri2_create_image_khr,
|
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
|
|
|
|
.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,
|
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
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_add_configs_for_visuals(_EGLDisplay *disp)
|
2016-08-25 14:55:06 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2018-02-06 09:32:22 +00:00
|
|
|
|
unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 };
|
2017-06-22 19:00:40 +01:00
|
|
|
|
unsigned int count = 0;
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
bool assigned;
|
2016-08-25 14:55:06 +01:00
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
assigned = false;
|
|
|
|
|
|
2018-02-06 09:32:22 +00:00
|
|
|
|
for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) {
|
2016-08-25 14:55:06 +01:00
|
|
|
|
struct dri2_egl_config *dri2_conf;
|
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
if (!BITSET_TEST(dri2_dpy->formats, j))
|
2016-08-25 14:55:06 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
|
2019-01-25 00:32:48 +00:00
|
|
|
|
count + 1, EGL_WINDOW_BIT, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes);
|
2016-08-25 14:55:06 +01:00
|
|
|
|
if (dri2_conf) {
|
2017-06-21 21:55:56 +01:00
|
|
|
|
if (dri2_conf->base.ConfigID == count + 1)
|
|
|
|
|
count++;
|
2016-08-25 14:55:06 +01:00
|
|
|
|
format_count[j]++;
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
assigned = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!assigned && dri2_dpy->is_different_gpu) {
|
|
|
|
|
struct dri2_egl_config *dri2_conf;
|
|
|
|
|
int alt_dri_image_format, c, s;
|
|
|
|
|
|
|
|
|
|
/* No match for config. Try if we can blitImage convert to a visual */
|
|
|
|
|
c = dri2_wl_visual_idx_from_config(dri2_dpy,
|
2021-08-02 21:16:34 +01:00
|
|
|
|
dri2_dpy->driver_configs[i],
|
|
|
|
|
false);
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
|
|
|
|
|
if (c == -1)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Find optimal target visual for blitImage conversion, if any. */
|
|
|
|
|
alt_dri_image_format = dri2_wl_visuals[c].alt_dri_image_format;
|
|
|
|
|
s = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format);
|
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
if (s == -1 || !BITSET_TEST(dri2_dpy->formats, s))
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Visual s works for the Wayland server, and c can be converted into s
|
|
|
|
|
* by our client gpu during PRIME blitImage conversion to a linear
|
|
|
|
|
* wl_buffer, so add visual c as supported by the client renderer.
|
|
|
|
|
*/
|
|
|
|
|
dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
|
|
|
|
|
count + 1, EGL_WINDOW_BIT, NULL,
|
2019-01-25 00:32:48 +00:00
|
|
|
|
dri2_wl_visuals[c].rgba_shifts,
|
|
|
|
|
dri2_wl_visuals[c].rgba_sizes);
|
egl/wayland: Allow client->server format conversion for PRIME offload. (v2)
Support PRIME render offload between a Wayland server gpu and a Wayland
client gpu with different channel ordering for their color formats,
e.g., between Intel drivers which currently only support ARGB2101010
and XRGB2101010 import/display and nouveau which only supports ABGR2101010
rendering and display on nv-50 and later.
In the wl_visuals table, we also store for each format an alternate
sibling format which stores colors at the same precision, but with
different channel ordering, e.g., ARGB2101010 <-> ABGR2101010.
If a given client-gpu renderable format is not supported by the server
for import, but the alternate format is supported by the server, expose
the client-gpu renderable format as a valid EGLConfig to the client. At
eglSwapBuffers time, during the blitImage() detiling blit from the client
backbuffer to the linear buffer, the client format is converted to the
server supported format. As we have to do a copy for PRIME anyway,
this channel swizzling conversion comes essentially for free.
Note that even if a server gpu in principle does support sampling
from the clients native format, this conversion will be a performance
advantage if it allows to convert to the servers preferred format
for direct scanout, as the Wayland compositor may then be able to
directly page-flip a fullscreen client wl_buffer onto the primary
plane, or onto a hardware overlay plane, avoiding an extra data copy
for desktop composition.
Tested so far under Weston with: nouveau single-gpu, Intel single-gpu,
AMD single-gpu, "Optimus" Intel server iGPU for display + NVidia
client dGPU for rendering.
v2: Implement minor review comments by Eric Engestrom: Add some
comment and assert, and some style fixes for clarity.
No functional change.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
2018-06-13 05:04:14 +01:00
|
|
|
|
if (dri2_conf) {
|
|
|
|
|
if (dri2_conf->base.ConfigID == count + 1)
|
|
|
|
|
count++;
|
|
|
|
|
format_count[c]++;
|
|
|
|
|
if (format_count[c] == 1)
|
|
|
|
|
_eglLog(_EGL_DEBUG, "Client format %s to server format %s via "
|
|
|
|
|
"PRIME blitImage.", dri2_wl_visuals[c].format_name,
|
|
|
|
|
dri2_wl_visuals[s].format_name);
|
2016-08-25 14:55:06 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
|
2016-08-25 14:55:06 +01:00
|
|
|
|
if (!format_count[i]) {
|
|
|
|
|
_eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
|
2018-02-06 09:32:22 +00:00
|
|
|
|
dri2_wl_visuals[i].format_name);
|
2016-08-25 14:55:06 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (count != 0);
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static EGLBoolean
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_initialize_wayland_drm(_EGLDisplay *disp)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
2018-09-04 11:20:03 +01:00
|
|
|
|
_EGLDevice *dev;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy;
|
|
|
|
|
|
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;
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_dpy->own_device = true;
|
2011-06-11 21:07:02 +01:00
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->wl_dpy = disp->PlatformDisplay;
|
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2018-02-06 10:29:13 +00:00
|
|
|
|
dri2_dpy->wl_modifiers =
|
|
|
|
|
calloc(ARRAY_SIZE(dri2_wl_visuals), sizeof(*dri2_dpy->wl_modifiers));
|
|
|
|
|
if (!dri2_dpy->wl_modifiers)
|
2017-06-16 18:01:23 +01:00
|
|
|
|
goto cleanup;
|
2018-02-06 10:29:13 +00:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {
|
2021-10-05 19:58:58 +01:00
|
|
|
|
if (!u_vector_init_pow2(&dri2_dpy->wl_modifiers[i], 4, sizeof(uint64_t)))
|
2018-02-06 10:29:13 +00:00
|
|
|
|
goto cleanup;
|
2017-06-16 18:01:23 +01: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
|
|
|
|
|
2021-03-19 08:17:44 +00:00
|
|
|
|
if (!dri2_dpy->authenticated &&
|
|
|
|
|
(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);
|
2018-09-04 11:20:03 +01:00
|
|
|
|
dev = _eglAddDevice(dri2_dpy->fd, false);
|
|
|
|
|
if (!dev) {
|
|
|
|
|
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
disp->Device = dev;
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
/* render nodes cannot use Gem names, and thus do not support
|
|
|
|
|
* the __DRI_DRI2_LOADER extension */
|
2017-05-11 22:49:04 +01:00
|
|
|
|
if (!dri2_dpy->is_render_node) {
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->loader_extensions = dri2_loader_extensions;
|
2017-05-11 22:49:04 +01:00
|
|
|
|
if (!dri2_load_driver(disp)) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "DRI2: failed to load driver");
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->loader_extensions = image_loader_extensions;
|
2017-05-11 22:49:04 +01:00
|
|
|
|
if (!dri2_load_driver_dri3(disp)) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "DRI3: failed to load driver");
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
}
|
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);
|
|
|
|
|
|
2017-08-05 00:25:46 +01:00
|
|
|
|
dri2_wl_setup_swap_interval(disp);
|
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
|
|
|
|
}
|
|
|
|
|
|
2018-04-22 15:48:15 +01:00
|
|
|
|
if (!dri2_wl_add_configs_for_visuals(disp)) {
|
2016-08-25 14:55:06 +01:00
|
|
|
|
_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
|
|
|
|
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_set_WL_bind_wayland_display(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;
|
|
|
|
|
|
2021-08-02 21:16:34 +01:00
|
|
|
|
disp->Extensions.EXT_present_opaque = 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)
|
|
|
|
|
{
|
2018-02-06 11:58:45 +00:00
|
|
|
|
int visual_idx = dri2_wl_visual_idx_from_shm_format(format);
|
|
|
|
|
|
2018-02-15 11:10:22 +00:00
|
|
|
|
assume(visual_idx != -1);
|
|
|
|
|
|
2018-02-06 11:58:45 +00:00
|
|
|
|
return w * (dri2_wl_visuals[visual_idx].bpp / 8);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2018-08-10 12:37:17 +01:00
|
|
|
|
/* Create a shareable buffer */
|
2018-01-18 20:29:14 +00:00
|
|
|
|
fd = os_create_anonymous_file(size_map, NULL);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
/* we need to do the following operations only once per frame */
|
|
|
|
|
if (dri2_surf->back)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2021-07-20 13:54:16 +01:00
|
|
|
|
if (dri2_surf->wl_win &&
|
|
|
|
|
(dri2_surf->base.Width != dri2_surf->wl_win->width ||
|
|
|
|
|
dri2_surf->base.Height != dri2_surf->wl_win->height)) {
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
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 */
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2015-05-01 10:11:20 +01:00
|
|
|
|
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) {
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2015-05-01 10:11:20 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_surf->back->locked = true;
|
2015-05-01 10:11:20 +01: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. */
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2015-05-01 10:11:20 +01:00
|
|
|
|
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) {
|
2018-03-22 15:20:43 +00:00
|
|
|
|
dri2_surf->throttle_callback = wl_display_sync(dri2_surf->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
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_wl_swrast_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
|
2015-05-01 10:11:20 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
|
|
|
|
|
|
2021-07-20 13:54:16 +01:00
|
|
|
|
if (!dri2_surf->wl_win)
|
|
|
|
|
return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
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;
|
2018-02-06 10:20:39 +00:00
|
|
|
|
int visual_idx = dri2_wl_visual_idx_from_shm_format(format);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
2018-02-06 10:20:39 +00:00
|
|
|
|
if (visual_idx == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
BITSET_SET(dri2_dpy->formats, visual_idx);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
2017-06-10 14:54:05 +01:00
|
|
|
|
registry_handle_global_swrast(void *data, struct wl_registry *registry,
|
|
|
|
|
uint32_t name, const char *interface,
|
|
|
|
|
uint32_t version)
|
2015-05-01 10:11:20 +01:00
|
|
|
|
{
|
|
|
|
|
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,
|
|
|
|
|
.destroy_surface = dri2_wl_destroy_surface,
|
2017-08-01 22:51:40 +01:00
|
|
|
|
.create_image = dri2_create_image_khr,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
.swap_buffers = dri2_wl_swrast_swap_buffers,
|
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,
|
2017-08-01 22:51:40 +01:00
|
|
|
|
&image_lookup_extension.base,
|
2016-08-24 23:32:27 +01:00
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static EGLBoolean
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_initialize_wayland_swrast(_EGLDisplay *disp)
|
2015-05-01 10:11:20 +01:00
|
|
|
|
{
|
2018-09-04 11:20:03 +01:00
|
|
|
|
_EGLDevice *dev;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy;
|
|
|
|
|
|
|
|
|
|
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;
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_dpy->own_device = true;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->wl_dpy = disp->PlatformDisplay;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-04 11:20:03 +01:00
|
|
|
|
dev = _eglAddDevice(dri2_dpy->fd, true);
|
|
|
|
|
if (!dev) {
|
|
|
|
|
_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
disp->Device = dev;
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
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
|
|
|
|
|
2018-11-27 12:27:45 +00:00
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || !BITSET_TEST_RANGE(dri2_dpy->formats,
|
|
|
|
|
0, EGL_DRI2_MAX_FORMATS))
|
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);
|
|
|
|
|
|
2017-08-05 00:25:46 +01:00
|
|
|
|
dri2_wl_setup_swap_interval(disp);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
2018-04-22 15:48:15 +01:00
|
|
|
|
if (!dri2_wl_add_configs_for_visuals(disp)) {
|
2016-08-25 14:55:06 +01:00
|
|
|
|
_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
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_initialize_wayland(_EGLDisplay *disp)
|
2015-05-01 10:11:20 +01:00
|
|
|
|
{
|
2020-08-17 19:32:12 +01:00
|
|
|
|
if (disp->Options.ForceSoftware)
|
|
|
|
|
return dri2_initialize_wayland_swrast(disp);
|
|
|
|
|
else
|
|
|
|
|
return dri2_initialize_wayland_drm(disp);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
}
|
2017-11-09 19:13:09 +00:00
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)
|
|
|
|
|
{
|
|
|
|
|
if (dri2_dpy->wl_drm)
|
|
|
|
|
wl_drm_destroy(dri2_dpy->wl_drm);
|
|
|
|
|
if (dri2_dpy->wl_dmabuf)
|
|
|
|
|
zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);
|
|
|
|
|
if (dri2_dpy->wl_shm)
|
|
|
|
|
wl_shm_destroy(dri2_dpy->wl_shm);
|
|
|
|
|
if (dri2_dpy->wl_registry)
|
|
|
|
|
wl_registry_destroy(dri2_dpy->wl_registry);
|
|
|
|
|
if (dri2_dpy->wl_queue)
|
|
|
|
|
wl_event_queue_destroy(dri2_dpy->wl_queue);
|
|
|
|
|
if (dri2_dpy->wl_dpy_wrapper)
|
|
|
|
|
wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
|
2018-02-06 10:29:13 +00:00
|
|
|
|
|
|
|
|
|
for (int i = 0; dri2_dpy->wl_modifiers && i < ARRAY_SIZE(dri2_wl_visuals); i++)
|
|
|
|
|
u_vector_finish(&dri2_dpy->wl_modifiers[i]);
|
|
|
|
|
free(dri2_dpy->wl_modifiers);
|
|
|
|
|
|
2017-11-09 19:13:09 +00:00
|
|
|
|
if (dri2_dpy->own_device)
|
|
|
|
|
wl_display_disconnect(dri2_dpy->wl_dpy);
|
|
|
|
|
}
|