2011-02-04 11:39:40 +00:00
|
|
|
|
/*
|
2012-12-14 04:30:45 +00:00
|
|
|
|
* Copyright © 2011-2012 Intel Corporation
|
2015-05-01 10:11:20 +01:00
|
|
|
|
* Copyright © 2012 Collabora, Ltd.
|
2011-02-04 11:39:40 +00:00
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
|
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
|
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
|
* DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* Kristian Høgsberg <krh@bitplanet.net>
|
|
|
|
|
* Benjamin Franzke <benjaminfranzke@googlemail.com>
|
|
|
|
|
*/
|
|
|
|
|
|
2015-02-28 17:12:40 +00:00
|
|
|
|
#include <stdint.h>
|
2011-02-04 11:39:40 +00:00
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <unistd.h>
|
2011-04-14 15:42:41 +01:00
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <xf86drm.h>
|
2015-05-01 10:11:20 +01:00
|
|
|
|
#include <sys/mman.h>
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
#include "egl_dri2.h"
|
2014-01-28 20:34:19 +00:00
|
|
|
|
#include "egl_dri2_fallbacks.h"
|
2014-01-11 04:52:48 +00:00
|
|
|
|
#include "loader.h"
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#include <wayland-client.h>
|
|
|
|
|
#include "wayland-drm-client-protocol.h"
|
|
|
|
|
|
2011-08-31 21:45:04 +01:00
|
|
|
|
enum wl_drm_format_flags {
|
2012-01-11 19:23:24 +00:00
|
|
|
|
HAS_ARGB8888 = 1,
|
2013-10-16 02:10:12 +01:00
|
|
|
|
HAS_XRGB8888 = 2,
|
|
|
|
|
HAS_RGB565 = 4,
|
2011-08-31 21:45:04 +01:00
|
|
|
|
};
|
|
|
|
|
|
2014-01-28 00:42:10 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_wl_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
|
|
|
|
|
EGLint interval);
|
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
static void
|
|
|
|
|
sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
|
|
|
|
|
{
|
|
|
|
|
int *done = data;
|
|
|
|
|
|
|
|
|
|
*done = 1;
|
|
|
|
|
wl_callback_destroy(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_callback_listener sync_listener = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.done = sync_callback
|
2012-10-11 03:10:42 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
roundtrip(struct dri2_egl_display *dri2_dpy)
|
|
|
|
|
{
|
|
|
|
|
struct wl_callback *callback;
|
|
|
|
|
int done = 0, ret = 0;
|
|
|
|
|
|
|
|
|
|
callback = wl_display_sync(dri2_dpy->wl_dpy);
|
|
|
|
|
wl_callback_add_listener(callback, &sync_listener, &done);
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) callback, dri2_dpy->wl_queue);
|
|
|
|
|
while (ret != -1 && !done)
|
|
|
|
|
ret = wl_display_dispatch_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);
|
|
|
|
|
|
2012-12-25 12:01:08 +00:00
|
|
|
|
if (!done)
|
|
|
|
|
wl_callback_destroy(callback);
|
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-06 18:13:29 +01:00
|
|
|
|
static void
|
|
|
|
|
wl_buffer_release(void *data, struct wl_buffer *buffer)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = data;
|
|
|
|
|
int i;
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)
|
|
|
|
|
if (dri2_surf->color_buffers[i].wl_buffer == buffer)
|
2011-05-06 18:13:29 +01:00
|
|
|
|
break;
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
if (i == ARRAY_SIZE(dri2_surf->color_buffers)) {
|
|
|
|
|
wl_buffer_destroy(buffer);
|
2011-05-06 18:13:29 +01:00
|
|
|
|
return;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].locked = 0;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 12:24:11 +01:00
|
|
|
|
static const struct wl_buffer_listener wl_buffer_listener = {
|
|
|
|
|
.release = wl_buffer_release
|
2011-05-06 18:13:29 +01:00
|
|
|
|
};
|
2011-02-11 01:23:14 +00:00
|
|
|
|
|
2012-11-30 15:41:02 +00:00
|
|
|
|
static void
|
|
|
|
|
resize_callback(struct wl_egl_window *wl_win, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = data;
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
|
|
|
|
|
(*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
|
|
|
|
|
*/
|
|
|
|
|
static _EGLSurface *
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_wl_create_surface(_EGLDriver *drv, _EGLDisplay *disp,
|
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
|
|
|
|
_EGLConfig *conf, void *native_window,
|
2014-01-28 20:47:38 +00:00
|
|
|
|
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;
|
2015-06-10 01:49:29 +01:00
|
|
|
|
const __DRIconfig *config;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
2014-09-22 05:15:26 +01:00
|
|
|
|
dri2_surf = calloc(1, sizeof *dri2_surf);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (!dri2_surf) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2015-06-13 08:36:27 +01:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list))
|
2011-02-04 11:39:40 +00:00
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
|
2013-10-16 02:10:12 +01:00
|
|
|
|
if (conf->RedSize == 5)
|
|
|
|
|
dri2_surf->format = WL_DRM_FORMAT_RGB565;
|
|
|
|
|
else if (conf->AlphaSize == 0)
|
2012-01-11 19:23:24 +00:00
|
|
|
|
dri2_surf->format = WL_DRM_FORMAT_XRGB8888;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
else
|
2012-01-11 19:23:24 +00:00
|
|
|
|
dri2_surf->format = WL_DRM_FORMAT_ARGB8888;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
|
2015-06-18 20:19:32 +01:00
|
|
|
|
if (!window) {
|
|
|
|
|
_eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");
|
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_surf->wl_win = window;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_surf->wl_win->private = dri2_surf;
|
|
|
|
|
dri2_surf->wl_win->resize_callback = resize_callback;
|
2012-11-30 15:41:02 +00:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_surf->base.Width = -1;
|
|
|
|
|
dri2_surf->base.Height = -1;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-06-10 01:49:29 +01:00
|
|
|
|
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
|
|
|
|
|
dri2_surf->base.GLColorspace);
|
|
|
|
|
|
|
|
|
|
dri2_surf->dri_drawable =
|
|
|
|
|
(*dri2_dpy->dri2->createNewDrawable)(dri2_dpy->dri_screen, config,
|
|
|
|
|
dri2_surf);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (dri2_surf->dri_drawable == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
|
2015-06-18 20:22:54 +01:00
|
|
|
|
goto cleanup_surf;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &dri2_surf->base;
|
|
|
|
|
|
|
|
|
|
cleanup_surf:
|
|
|
|
|
free(dri2_surf);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
|
|
|
|
|
*/
|
|
|
|
|
static _EGLSurface *
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
|
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
|
|
|
|
_EGLConfig *conf, void *native_window,
|
2014-01-28 20:47:38 +00:00
|
|
|
|
const EGLint *attrib_list)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
2013-11-15 13:50:50 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
_EGLSurface *surf;
|
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
surf = dri2_wl_create_surface(drv, disp, conf, native_window, attrib_list);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
|
|
|
|
|
if (surf != NULL)
|
2014-01-28 00:42:10 +00:00
|
|
|
|
dri2_wl_swap_interval(drv, disp, surf, dri2_dpy->default_swap_interval);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
|
|
|
|
|
return surf;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-02-09 17:13:27 +00:00
|
|
|
|
static _EGLSurface *
|
|
|
|
|
dri2_wl_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
|
|
|
|
|
_EGLConfig *conf, void *native_window,
|
|
|
|
|
const EGLint *attrib_list)
|
|
|
|
|
{
|
|
|
|
|
/* From the EGL_EXT_platform_wayland spec, version 3:
|
|
|
|
|
*
|
|
|
|
|
* It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>
|
|
|
|
|
* that belongs to Wayland. Any such call fails and generates
|
|
|
|
|
* EGL_BAD_PARAMETER.
|
|
|
|
|
*/
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "
|
|
|
|
|
"Wayland");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglDestroySurface(), drv->API.DestroySurface().
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
(*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (dri2_surf->color_buffers[i].wl_buffer)
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->color_buffers[i].dri_image)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].linear_copy)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].data)
|
|
|
|
|
munmap(dri2_surf->color_buffers[i].data,
|
|
|
|
|
dri2_surf->color_buffers[i].data_size);
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_dpy->dri2) {
|
|
|
|
|
for (i = 0; i < __DRI_BUFFER_COUNT; i++)
|
|
|
|
|
if (dri2_surf->dri_buffers[i] &&
|
|
|
|
|
dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
|
|
|
|
|
dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->dri_buffers[i]);
|
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
if (dri2_surf->throttle_callback)
|
|
|
|
|
wl_callback_destroy(dri2_surf->throttle_callback);
|
2012-10-27 23:50:12 +01:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
dri2_surf->wl_win->private = NULL;
|
|
|
|
|
dri2_surf->wl_win->resize_callback = NULL;
|
2012-11-30 15:41:02 +00:00
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
free(surf);
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2012-12-14 04:30:45 +00:00
|
|
|
|
int i;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (dri2_surf->color_buffers[i].wl_buffer &&
|
|
|
|
|
!dri2_surf->color_buffers[i].locked)
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->color_buffers[i].dri_image)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].linear_copy)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_surf->color_buffers[i].data)
|
|
|
|
|
munmap(dri2_surf->color_buffers[i].data,
|
|
|
|
|
dri2_surf->color_buffers[i].data_size);
|
2011-02-09 14:30:20 +00:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_surf->color_buffers[i].dri_image = NULL;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_surf->color_buffers[i].linear_copy = NULL;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_surf->color_buffers[i].data = NULL;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].locked = 0;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
}
|
2011-09-01 08:17:04 +01:00
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_dpy->dri2) {
|
|
|
|
|
for (i = 0; i < __DRI_BUFFER_COUNT; i++)
|
|
|
|
|
if (dri2_surf->dri_buffers[i] &&
|
|
|
|
|
dri2_surf->dri_buffers[i]->attachment != __DRI_BUFFER_BACK_LEFT)
|
|
|
|
|
dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->dri_buffers[i]);
|
|
|
|
|
}
|
2011-02-11 01:23:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
static int
|
2013-11-09 06:10:36 +00:00
|
|
|
|
get_back_bo(struct dri2_egl_surface *dri2_surf)
|
2011-02-11 01:23:14 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2015-10-21 11:28:00 +01:00
|
|
|
|
int i, use_flags;
|
2015-02-11 03:15:31 +00:00
|
|
|
|
unsigned int dri_image_format;
|
|
|
|
|
|
|
|
|
|
/* currently supports three WL DRM formats,
|
|
|
|
|
* WL_DRM_FORMAT_ARGB8888, WL_DRM_FORMAT_XRGB8888,
|
|
|
|
|
* and WL_DRM_FORMAT_RGB565
|
|
|
|
|
*/
|
|
|
|
|
switch (dri2_surf->format) {
|
|
|
|
|
case WL_DRM_FORMAT_ARGB8888:
|
|
|
|
|
dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_DRM_FORMAT_XRGB8888:
|
|
|
|
|
dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_DRM_FORMAT_RGB565:
|
|
|
|
|
dri_image_format = __DRI_IMAGE_FORMAT_RGB565;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* format is not supported */
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2011-02-11 01:23:14 +00:00
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
/* We always want to throttle to some event (either a frame callback or
|
|
|
|
|
* a sync request) after the commit so that we can be sure the
|
|
|
|
|
* compositor has had a chance to handle it and send us a release event
|
|
|
|
|
* before we look for a free buffer */
|
|
|
|
|
while (dri2_surf->throttle_callback != NULL)
|
|
|
|
|
if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
|
|
|
|
|
dri2_dpy->wl_queue) == -1)
|
2013-12-10 00:13:35 +00:00
|
|
|
|
return -1;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
if (dri2_surf->back == NULL) {
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
2013-11-15 13:50:50 +00:00
|
|
|
|
/* Get an unlocked buffer, preferrably one with a dri_buffer
|
|
|
|
|
* already allocated. */
|
|
|
|
|
if (dri2_surf->color_buffers[i].locked)
|
2012-12-14 04:30:45 +00:00
|
|
|
|
continue;
|
|
|
|
|
if (dri2_surf->back == NULL)
|
2013-11-15 13:50:50 +00:00
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
2013-02-02 12:40:51 +00:00
|
|
|
|
else if (dri2_surf->back->dri_image == NULL)
|
2013-11-15 13:50:50 +00:00
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
2011-02-11 01:23:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
if (dri2_surf->back == NULL)
|
|
|
|
|
return -1;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
|
2015-10-21 11:28:00 +01:00
|
|
|
|
use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu &&
|
|
|
|
|
dri2_surf->back->linear_copy == NULL) {
|
|
|
|
|
dri2_surf->back->linear_copy =
|
|
|
|
|
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
dri_image_format,
|
2015-10-21 11:28:00 +01:00
|
|
|
|
use_flags |
|
2015-05-01 00:16:24 +01:00
|
|
|
|
__DRI_IMAGE_USE_LINEAR,
|
|
|
|
|
NULL);
|
|
|
|
|
if (dri2_surf->back->linear_copy == NULL)
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->back->dri_image == NULL) {
|
2015-06-13 08:36:27 +01:00
|
|
|
|
dri2_surf->back->dri_image =
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
2015-02-11 03:15:31 +00:00
|
|
|
|
dri_image_format,
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->is_different_gpu ?
|
2015-10-21 11:28:00 +01:00
|
|
|
|
0 : use_flags,
|
2013-02-02 12:40:51 +00:00
|
|
|
|
NULL);
|
2012-12-14 04:32:14 +00:00
|
|
|
|
dri2_surf->back->age = 0;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2013-02-02 12:40:51 +00:00
|
|
|
|
if (dri2_surf->back->dri_image == NULL)
|
2012-12-14 04:30:45 +00:00
|
|
|
|
return -1;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
dri2_surf->back->locked = 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
__DRIimage *image;
|
|
|
|
|
int name, pitch;
|
|
|
|
|
|
2013-02-02 12:40:51 +00:00
|
|
|
|
image = dri2_surf->back->dri_image;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
|
|
|
|
|
|
|
|
|
|
buffer->attachment = __DRI_BUFFER_BACK_LEFT;
|
|
|
|
|
buffer->name = name;
|
|
|
|
|
buffer->pitch = pitch;
|
|
|
|
|
buffer->cpp = 4;
|
|
|
|
|
buffer->flags = 0;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
static int
|
|
|
|
|
get_aux_bo(struct dri2_egl_surface *dri2_surf,
|
|
|
|
|
unsigned int attachment, unsigned int format, __DRIbuffer *buffer)
|
2011-05-06 18:13:29 +01:00
|
|
|
|
{
|
2012-12-14 04:30:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
__DRIbuffer *b = dri2_surf->dri_buffers[attachment];
|
|
|
|
|
|
|
|
|
|
if (b == NULL) {
|
|
|
|
|
b = dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen,
|
|
|
|
|
attachment, format,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height);
|
|
|
|
|
dri2_surf->dri_buffers[attachment] = b;
|
|
|
|
|
}
|
|
|
|
|
if (b == NULL)
|
|
|
|
|
return -1;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
memcpy(buffer, b, sizeof *buffer);
|
2011-05-06 18:13:29 +01:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
return 0;
|
2011-05-06 18:13:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
static int
|
|
|
|
|
update_buffers(struct dri2_egl_surface *dri2_surf)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2013-11-09 06:10:36 +00:00
|
|
|
|
int i;
|
2012-11-22 13:34:49 +00:00
|
|
|
|
|
2015-05-01 10:16:41 +01:00
|
|
|
|
if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
|
|
|
|
|
dri2_surf->base.Height != dri2_surf->wl_win->height) {
|
2011-02-11 01:23:14 +00:00
|
|
|
|
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_release_buffers(dri2_surf);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
dri2_surf->base.Width = dri2_surf->wl_win->width;
|
|
|
|
|
dri2_surf->base.Height = dri2_surf->wl_win->height;
|
|
|
|
|
dri2_surf->dx = dri2_surf->wl_win->dx;
|
|
|
|
|
dri2_surf->dy = dri2_surf->wl_win->dy;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
if (get_back_bo(dri2_surf) < 0) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");
|
|
|
|
|
return -1;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
/* If we have an extra unlocked buffer at this point, we had to do triple
|
|
|
|
|
* buffering for a while, but now can go back to just double buffering.
|
|
|
|
|
* That means we can free any unlocked buffer now. */
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked &&
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer) {
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu)
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
2013-02-02 12:40:51 +00:00
|
|
|
|
dri2_surf->color_buffers[i].dri_image = NULL;
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_surf->color_buffers[i].linear_copy = NULL;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static __DRIbuffer *
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,
|
|
|
|
|
int *width, int *height,
|
|
|
|
|
unsigned int *attachments, int count,
|
|
|
|
|
int *out_count, void *loaderPrivate)
|
2013-11-09 06:10:36 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
|
|
if (update_buffers(dri2_surf) < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < 2 * count; i += 2, j++) {
|
|
|
|
|
switch (attachments[i]) {
|
|
|
|
|
case __DRI_BUFFER_BACK_LEFT:
|
|
|
|
|
back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (get_aux_bo(dri2_surf, attachments[i], attachments[i + 1],
|
|
|
|
|
&dri2_surf->buffers[j]) < 0) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to allocate aux buffer");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
*out_count = j;
|
|
|
|
|
if (j == 0)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
*width = dri2_surf->base.Width;
|
|
|
|
|
*height = dri2_surf->base.Height;
|
|
|
|
|
|
|
|
|
|
return dri2_surf->buffers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static __DRIbuffer *
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_get_buffers(__DRIdrawable * driDrawable,
|
|
|
|
|
int *width, int *height,
|
|
|
|
|
unsigned int *attachments, int count,
|
|
|
|
|
int *out_count, void *loaderPrivate)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
2015-02-11 03:15:31 +00:00
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
unsigned int *attachments_with_format;
|
|
|
|
|
__DRIbuffer *buffer;
|
2015-02-11 03:15:31 +00:00
|
|
|
|
unsigned int bpp;
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
2015-02-11 03:15:31 +00:00
|
|
|
|
switch (dri2_surf->format) {
|
|
|
|
|
case WL_DRM_FORMAT_ARGB8888:
|
|
|
|
|
case WL_DRM_FORMAT_XRGB8888:
|
|
|
|
|
bpp = 32;
|
|
|
|
|
break;
|
|
|
|
|
case WL_DRM_FORMAT_RGB565:
|
|
|
|
|
bpp = 16;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* format is not supported */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-03 22:33:18 +01:00
|
|
|
|
attachments_with_format = calloc(count, 2 * sizeof(unsigned int));
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (!attachments_with_format) {
|
|
|
|
|
*out_count = 0;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
|
attachments_with_format[2*i] = attachments[i];
|
2015-02-11 03:15:31 +00:00
|
|
|
|
attachments_with_format[2*i + 1] = bpp;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buffer =
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_get_buffers_with_format(driDrawable,
|
|
|
|
|
width, height,
|
|
|
|
|
attachments_with_format, count,
|
|
|
|
|
out_count, loaderPrivate);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
free(attachments_with_format);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
static int
|
|
|
|
|
image_get_buffers(__DRIdrawable *driDrawable,
|
|
|
|
|
unsigned int format,
|
|
|
|
|
uint32_t *stamp,
|
|
|
|
|
void *loaderPrivate,
|
|
|
|
|
uint32_t buffer_mask,
|
|
|
|
|
struct __DRIimageList *buffers)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
|
|
|
|
|
if (update_buffers(dri2_surf) < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;
|
|
|
|
|
buffers->back = dri2_surf->back->dri_image;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
static void
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
(void) driDrawable;
|
|
|
|
|
(void) loaderPrivate;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 18:21:48 +01:00
|
|
|
|
static const __DRIdri2LoaderExtension dri2_loader_extension = {
|
|
|
|
|
.base = { __DRI_DRI2_LOADER, 3 },
|
|
|
|
|
|
|
|
|
|
.getBuffers = dri2_wl_get_buffers,
|
|
|
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
|
|
|
|
.getBuffersWithFormat = dri2_wl_get_buffers_with_format,
|
|
|
|
|
};
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
static const __DRIimageLoaderExtension image_loader_extension = {
|
2014-02-12 18:32:59 +00:00
|
|
|
|
.base = { __DRI_IMAGE_LOADER, 1 },
|
|
|
|
|
|
|
|
|
|
.getBuffers = image_get_buffers,
|
2014-01-28 20:47:38 +00:00
|
|
|
|
.flushFrontBuffer = dri2_wl_flush_front_buffer,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
};
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
static void
|
2013-11-15 13:50:50 +00:00
|
|
|
|
wayland_throttle_callback(void *data,
|
|
|
|
|
struct wl_callback *callback,
|
|
|
|
|
uint32_t time)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = data;
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
dri2_surf->throttle_callback = NULL;
|
2011-08-17 03:38:22 +01:00
|
|
|
|
wl_callback_destroy(callback);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
static const struct wl_callback_listener throttle_listener = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.done = wayland_throttle_callback
|
2011-08-17 03:38:22 +01:00
|
|
|
|
};
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
static void
|
|
|
|
|
create_wl_buffer(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
2015-05-01 00:16:24 +01:00
|
|
|
|
__DRIimage *image;
|
2013-11-09 06:10:36 +00:00
|
|
|
|
int fd, stride, name;
|
2013-02-02 17:26:12 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_surf->current->wl_buffer != NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
if (dri2_dpy->is_different_gpu) {
|
|
|
|
|
image = dri2_surf->current->linear_copy;
|
|
|
|
|
} else {
|
|
|
|
|
image = dri2_surf->current->dri_image;
|
|
|
|
|
}
|
2013-02-02 17:26:12 +00:00
|
|
|
|
if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
|
2013-02-02 17:26:12 +00:00
|
|
|
|
|
|
|
|
|
dri2_surf->current->wl_buffer =
|
|
|
|
|
wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
|
|
|
|
|
fd,
|
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
|
|
|
|
dri2_surf->format,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
0, stride,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
0, 0,
|
|
|
|
|
0, 0);
|
|
|
|
|
close(fd);
|
|
|
|
|
} else {
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);
|
2013-11-09 06:10:36 +00:00
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
dri2_surf->current->wl_buffer =
|
|
|
|
|
wl_drm_create_buffer(dri2_dpy->wl_drm,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
name,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
dri2_surf->base.Width,
|
|
|
|
|
dri2_surf->base.Height,
|
2013-11-09 06:10:36 +00:00
|
|
|
|
stride,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
dri2_surf->format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_surf->current->wl_buffer,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
wl_buffer_add_listener(dri2_surf->current->wl_buffer,
|
|
|
|
|
&wl_buffer_listener, dri2_surf);
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-16 16:34:39 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
try_damage_buffer(struct dri2_egl_surface *dri2_surf,
|
|
|
|
|
const EGLint *rects,
|
|
|
|
|
EGLint n_rects)
|
|
|
|
|
{
|
|
|
|
|
/* The WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION macro and
|
|
|
|
|
* wl_proxy_get_version() were both introduced in wayland 1.10.
|
|
|
|
|
* Instead of bumping our wayland dependency we just make this
|
|
|
|
|
* function conditional on the required 1.10 features, falling
|
|
|
|
|
* back to old (correct but suboptimal) behaviour for older
|
|
|
|
|
* wayland.
|
|
|
|
|
*/
|
|
|
|
|
#ifdef WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_win->surface)
|
|
|
|
|
< WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_rects; i++) {
|
|
|
|
|
const int *rect = &rects[i * 4];
|
|
|
|
|
|
|
|
|
|
wl_surface_damage_buffer(dri2_surf->wl_win->surface,
|
|
|
|
|
rect[0],
|
|
|
|
|
dri2_surf->base.Height - rect[1] - rect[3],
|
|
|
|
|
rect[2], rect[3]);
|
|
|
|
|
}
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
#endif
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglSwapBuffers(), drv->API.SwapBuffers().
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_swap_buffers_with_damage(_EGLDriver *drv,
|
|
|
|
|
_EGLDisplay *disp,
|
|
|
|
|
_EGLSurface *draw,
|
|
|
|
|
const EGLint *rects,
|
|
|
|
|
EGLint n_rects)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
|
2013-11-15 13:50:49 +00:00
|
|
|
|
int i;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-12-14 04:32:14 +00:00
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)
|
|
|
|
|
if (dri2_surf->color_buffers[i].age > 0)
|
|
|
|
|
dri2_surf->color_buffers[i].age++;
|
|
|
|
|
|
2013-02-06 20:41:54 +00:00
|
|
|
|
/* Make sure we have a back buffer in case we're swapping without ever
|
|
|
|
|
* rendering. */
|
2013-11-09 06:10:36 +00:00
|
|
|
|
if (get_back_bo(dri2_surf) < 0) {
|
2013-02-06 20:41:54 +00:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
if (draw->SwapInterval > 0) {
|
|
|
|
|
dri2_surf->throttle_callback =
|
|
|
|
|
wl_surface_frame(dri2_surf->wl_win->surface);
|
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
}
|
2013-11-15 13:50:49 +00:00
|
|
|
|
|
2012-12-14 04:32:14 +00:00
|
|
|
|
dri2_surf->back->age = 1;
|
2012-12-14 04:30:45 +00:00
|
|
|
|
dri2_surf->current = dri2_surf->back;
|
|
|
|
|
dri2_surf->back = NULL;
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
create_wl_buffer(dri2_surf);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-12-14 04:30:45 +00:00
|
|
|
|
wl_surface_attach(dri2_surf->wl_win->surface,
|
|
|
|
|
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))
|
|
|
|
|
wl_surface_damage(dri2_surf->wl_win->surface,
|
|
|
|
|
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);
|
2012-11-30 18:29:17 +00:00
|
|
|
|
(*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2013-12-04 20:08:35 +00:00
|
|
|
|
wl_surface_commit(dri2_surf->wl_win->surface);
|
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) {
|
|
|
|
|
dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy);
|
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-03 16:38:09 +00:00
|
|
|
|
wl_display_flush(dri2_dpy->wl_dpy);
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-14 04:32:14 +00:00
|
|
|
|
static EGLint
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_query_buffer_age(_EGLDriver *drv,
|
|
|
|
|
_EGLDisplay *disp, _EGLSurface *surface)
|
2012-12-14 04:32:14 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
|
|
|
|
|
|
2013-11-09 06:10:36 +00:00
|
|
|
|
if (get_back_bo(dri2_surf) < 0) {
|
2012-12-14 04:32:14 +00:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dri2_surf->back->age;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-10 16:59:31 +00:00
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
|
2012-02-10 16:59:31 +00:00
|
|
|
|
{
|
2014-01-28 20:47:38 +00:00
|
|
|
|
return dri2_wl_swap_buffers_with_damage (drv, disp, draw, NULL, 0);
|
2012-02-10 16:59:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-10-28 15:07:03 +00:00
|
|
|
|
static struct wl_buffer *
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_wl_create_wayland_buffer_from_image(_EGLDriver *drv,
|
|
|
|
|
_EGLDisplay *disp,
|
|
|
|
|
_EGLImage *img)
|
2013-10-28 15:07:03 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
|
|
|
__DRIimage *image = dri2_img->dri_image;
|
|
|
|
|
struct wl_buffer *buffer;
|
|
|
|
|
int width, height, format, pitch;
|
|
|
|
|
enum wl_drm_format wl_format;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case __DRI_IMAGE_FORMAT_ARGB8888:
|
|
|
|
|
if (!(dri2_dpy->formats & HAS_ARGB8888))
|
|
|
|
|
goto bad_format;
|
|
|
|
|
wl_format = WL_DRM_FORMAT_ARGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case __DRI_IMAGE_FORMAT_XRGB8888:
|
|
|
|
|
if (!(dri2_dpy->formats & HAS_XRGB8888))
|
|
|
|
|
goto bad_format;
|
|
|
|
|
wl_format = WL_DRM_FORMAT_XRGB8888;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
goto bad_format;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);
|
|
|
|
|
|
|
|
|
|
buffer =
|
|
|
|
|
wl_drm_create_prime_buffer(dri2_dpy->wl_drm,
|
|
|
|
|
fd,
|
|
|
|
|
width, height,
|
|
|
|
|
wl_format,
|
|
|
|
|
0, pitch,
|
|
|
|
|
0, 0,
|
|
|
|
|
0, 0);
|
|
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
|
} else {
|
|
|
|
|
int name;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);
|
|
|
|
|
|
|
|
|
|
buffer =
|
|
|
|
|
wl_drm_create_buffer(dri2_dpy->wl_drm,
|
|
|
|
|
name,
|
|
|
|
|
width, height,
|
|
|
|
|
pitch,
|
|
|
|
|
wl_format);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The buffer object will have been created with our internal event queue
|
|
|
|
|
* because it is using the wl_drm object as a proxy factory. We want the
|
|
|
|
|
* buffer to be used by the application so we'll reset it to the display's
|
|
|
|
|
* default event queue */
|
|
|
|
|
if (buffer)
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
|
|
|
|
|
bad_format:
|
|
|
|
|
_eglError(EGL_BAD_MATCH, "unsupported image format");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
static int
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)
|
2011-02-21 15:22:34 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
if (dri2_dpy->is_render_node) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: client asks server to "
|
|
|
|
|
"authenticate for render-nodes");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-05-31 10:45:51 +01:00
|
|
|
|
dri2_dpy->authenticated = 0;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
wl_drm_authenticate(dri2_dpy->wl_drm, id);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
if (roundtrip(dri2_dpy) < 0)
|
|
|
|
|
ret = -1;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
if (!dri2_dpy->authenticated)
|
2011-02-21 15:22:34 +00:00
|
|
|
|
ret = -1;
|
|
|
|
|
|
|
|
|
|
/* reset authenticated */
|
2011-05-31 10:45:51 +01:00
|
|
|
|
dri2_dpy->authenticated = 1;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_device(void *data, struct wl_drm *drm, const char *device)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
drm_magic_t magic;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->device_name = strdup(device);
|
|
|
|
|
if (!dri2_dpy->device_name)
|
|
|
|
|
return;
|
|
|
|
|
|
2015-06-17 17:28:51 +01:00
|
|
|
|
dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);
|
2011-04-14 15:42:41 +01:00
|
|
|
|
if (dri2_dpy->fd == -1) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",
|
|
|
|
|
dri2_dpy->device_name, strerror(errno));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-10 12:27:06 +01:00
|
|
|
|
if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {
|
2015-05-01 00:30:10 +01:00
|
|
|
|
dri2_dpy->authenticated = 1;
|
|
|
|
|
} else {
|
|
|
|
|
drmGetMagic(dri2_dpy->fd, &magic);
|
|
|
|
|
wl_drm_authenticate(dri2_dpy->wl_drm, magic);
|
|
|
|
|
}
|
2011-04-14 15:42:41 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-31 21:45:04 +01:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
2012-01-11 19:23:24 +00:00
|
|
|
|
case WL_DRM_FORMAT_ARGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_ARGB8888;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
break;
|
2012-01-11 19:23:24 +00:00
|
|
|
|
case WL_DRM_FORMAT_XRGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_XRGB8888;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
break;
|
2013-10-16 02:10:12 +01:00
|
|
|
|
case WL_DRM_FORMAT_RGB565:
|
|
|
|
|
dri2_dpy->formats |= HAS_RGB565;
|
|
|
|
|
break;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->capabilities = value;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 15:42:41 +01:00
|
|
|
|
static void
|
|
|
|
|
drm_handle_authenticated(void *data, struct wl_drm *drm)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
2011-05-31 10:45:51 +01:00
|
|
|
|
dri2_dpy->authenticated = 1;
|
2011-04-14 15:42:41 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_drm_listener drm_listener = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.device = drm_handle_device,
|
|
|
|
|
.format = drm_handle_format,
|
|
|
|
|
.authenticated = drm_handle_authenticated,
|
|
|
|
|
.capabilities = drm_handle_capabilities
|
2011-04-14 15:42:41 +01:00
|
|
|
|
};
|
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
static void
|
2015-05-01 10:11:20 +01:00
|
|
|
|
registry_handle_global_drm(void *data, struct wl_registry *registry, uint32_t name,
|
2012-10-11 03:10:42 +01:00
|
|
|
|
const char *interface, uint32_t version)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
if (version > 1)
|
|
|
|
|
version = 2;
|
2012-10-11 03:10:42 +01:00
|
|
|
|
if (strcmp(interface, "wl_drm") == 0) {
|
|
|
|
|
dri2_dpy->wl_drm =
|
2013-02-02 17:26:12 +00:00
|
|
|
|
wl_registry_bind(registry, name, &wl_drm_interface, version);
|
2012-10-11 03:10:42 +01:00
|
|
|
|
wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-06-18 21:53:46 +01:00
|
|
|
|
static void
|
|
|
|
|
registry_handle_global_remove(void *data, struct wl_registry *registry,
|
|
|
|
|
uint32_t name)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static const struct wl_registry_listener registry_listener_drm = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.global = registry_handle_global_drm,
|
|
|
|
|
.global_remove = registry_handle_global_remove
|
2012-10-11 03:10:42 +01:00
|
|
|
|
};
|
|
|
|
|
|
2013-11-15 13:50:50 +00:00
|
|
|
|
static EGLBoolean
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_swap_interval(_EGLDriver *drv,
|
2013-11-15 13:50:50 +00:00
|
|
|
|
_EGLDisplay *disp,
|
|
|
|
|
_EGLSurface *surf,
|
|
|
|
|
EGLint interval)
|
|
|
|
|
{
|
|
|
|
|
if (interval > surf->Config->MaxSwapInterval)
|
|
|
|
|
interval = surf->Config->MaxSwapInterval;
|
|
|
|
|
else if (interval < surf->Config->MinSwapInterval)
|
|
|
|
|
interval = surf->Config->MinSwapInterval;
|
|
|
|
|
|
|
|
|
|
surf->SwapInterval = interval;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_setup_swap_interval(struct dri2_egl_display *dri2_dpy)
|
2013-11-15 13:50:50 +00:00
|
|
|
|
{
|
|
|
|
|
GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
|
|
|
|
|
|
|
|
|
|
/* We can't use values greater than 1 on Wayland because we are using the
|
|
|
|
|
* frame callback to synchronise the frame and the only way we be sure to
|
|
|
|
|
* get a frame callback is to attach a new buffer. Therefore we can't just
|
|
|
|
|
* sit drawing nothing to wait until the next ‘n’ frame callbacks */
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->config)
|
|
|
|
|
dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
|
|
|
|
|
"vblank_mode", &vblank_mode);
|
|
|
|
|
switch (vblank_mode) {
|
|
|
|
|
case DRI_CONF_VBLANK_NEVER:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = 0;
|
|
|
|
|
dri2_dpy->default_swap_interval = 0;
|
|
|
|
|
break;
|
|
|
|
|
case DRI_CONF_VBLANK_ALWAYS_SYNC:
|
|
|
|
|
dri2_dpy->min_swap_interval = 1;
|
|
|
|
|
dri2_dpy->max_swap_interval = 1;
|
|
|
|
|
dri2_dpy->default_swap_interval = 1;
|
|
|
|
|
break;
|
|
|
|
|
case DRI_CONF_VBLANK_DEF_INTERVAL_0:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = 1;
|
|
|
|
|
dri2_dpy->default_swap_interval = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
case DRI_CONF_VBLANK_DEF_INTERVAL_1:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = 1;
|
|
|
|
|
dri2_dpy->default_swap_interval = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-28 19:41:46 +00:00
|
|
|
|
static struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {
|
2014-01-28 20:47:38 +00:00
|
|
|
|
.authenticate = dri2_wl_authenticate,
|
2014-01-29 00:39:09 +00:00
|
|
|
|
.create_window_surface = dri2_wl_create_window_surface,
|
2014-02-09 17:13:27 +00:00
|
|
|
|
.create_pixmap_surface = dri2_wl_create_pixmap_surface,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.destroy_surface = dri2_wl_destroy_surface,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.create_image = dri2_create_image_khr,
|
2014-01-28 20:34:19 +00:00
|
|
|
|
.swap_interval = dri2_wl_swap_interval,
|
2014-01-29 00:21:21 +00:00
|
|
|
|
.swap_buffers = dri2_wl_swap_buffers,
|
2014-01-29 00:26:44 +00:00
|
|
|
|
.swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.swap_buffers_region = dri2_fallback_swap_buffers_region,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.post_sub_buffer = dri2_fallback_post_sub_buffer,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.copy_buffers = dri2_fallback_copy_buffers,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.query_buffer_age = dri2_wl_query_buffer_age,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
.create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,
|
2014-05-06 20:10:57 +01:00
|
|
|
|
.get_sync_values = dri2_fallback_get_sync_values,
|
2015-07-21 16:43:59 +01:00
|
|
|
|
.get_dri_drawable = dri2_surface_get_dri_drawable,
|
2014-01-28 19:41:46 +00:00
|
|
|
|
};
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_initialize_wayland_drm(_EGLDriver *drv, _EGLDisplay *disp)
|
2011-02-04 11:39:40 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
const __DRIconfig *config;
|
2012-10-11 03:10:42 +01:00
|
|
|
|
uint32_t types;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
int i;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
static const unsigned int argb_masks[4] =
|
|
|
|
|
{ 0xff0000, 0xff00, 0xff, 0xff000000 };
|
|
|
|
|
static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
|
2013-10-16 02:10:12 +01:00
|
|
|
|
static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 };
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2014-01-11 04:52:48 +00:00
|
|
|
|
loader_set_logger(_eglLog);
|
|
|
|
|
|
2012-09-05 07:09:22 +01:00
|
|
|
|
dri2_dpy = calloc(1, sizeof *dri2_dpy);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (!dri2_dpy)
|
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
goto cleanup_dpy;
|
2011-12-13 13:43:48 +00:00
|
|
|
|
dri2_dpy->own_device = 1;
|
2011-06-11 21:07:02 +01:00
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->wl_dpy = disp->PlatformDisplay;
|
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
|
2013-02-26 17:49:40 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->own_device)
|
|
|
|
|
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
|
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
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)
|
2015-04-30 23:03:32 +01:00
|
|
|
|
goto cleanup_registry;
|
2012-10-11 03:10:42 +01:00
|
|
|
|
|
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)
|
2011-04-14 15:42:41 +01:00
|
|
|
|
goto cleanup_drm;
|
2011-02-04 20:37:51 +00:00
|
|
|
|
|
2012-10-11 03:10:42 +01:00
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)
|
2011-04-14 15:42:41 +01:00
|
|
|
|
goto cleanup_fd;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,
|
|
|
|
|
&dri2_dpy->is_different_gpu);
|
|
|
|
|
if (dri2_dpy->is_different_gpu) {
|
|
|
|
|
free(dri2_dpy->device_name);
|
|
|
|
|
dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);
|
|
|
|
|
if (!dri2_dpy->device_name) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "
|
|
|
|
|
"for requested GPU");
|
|
|
|
|
goto cleanup_fd;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
2014-01-11 04:52:48 +00:00
|
|
|
|
dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
if (dri2_dpy->driver_name == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");
|
|
|
|
|
goto cleanup_fd;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
if (!dri2_load_driver(disp))
|
2011-04-14 15:42:41 +01:00
|
|
|
|
goto cleanup_driver_name;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
dri2_dpy->extensions[0] = &image_loader_extension.base;
|
|
|
|
|
dri2_dpy->extensions[1] = &image_lookup_extension.base;
|
|
|
|
|
dri2_dpy->extensions[2] = &use_invalidate.base;
|
|
|
|
|
|
|
|
|
|
/* render nodes cannot use Gem names, and thus do not support
|
|
|
|
|
* the __DRI_DRI2_LOADER extension */
|
|
|
|
|
if (!dri2_dpy->is_render_node) {
|
2016-08-16 18:21:48 +01:00
|
|
|
|
dri2_dpy->extensions[3] = &dri2_loader_extension.base;
|
2015-05-01 00:30:10 +01:00
|
|
|
|
dri2_dpy->extensions[4] = NULL;
|
|
|
|
|
} else
|
|
|
|
|
dri2_dpy->extensions[3] = NULL;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
|
|
|
|
if (!dri2_create_screen(disp))
|
|
|
|
|
goto cleanup_driver;
|
|
|
|
|
|
2014-01-28 20:47:38 +00:00
|
|
|
|
dri2_wl_setup_swap_interval(dri2_dpy);
|
2013-11-15 13:50:50 +00:00
|
|
|
|
|
2015-05-01 00:16:24 +01:00
|
|
|
|
/* To use Prime, we must have _DRI_IMAGE v7 at least.
|
|
|
|
|
* createImageFromFds support indicates that Prime export/import
|
|
|
|
|
* is supported by the driver. Fall back to
|
|
|
|
|
* gem names if we don't have Prime support. */
|
2013-03-19 17:20:36 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->image->base.version < 7 ||
|
|
|
|
|
dri2_dpy->image->createImageFromFds == NULL)
|
2014-04-08 21:28:40 +01:00
|
|
|
|
dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;
|
2013-03-19 17:20:36 +00:00
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
/* We cannot use Gem names with render-nodes, only prime fds (dma-buf).
|
|
|
|
|
* The server needs to accept them */
|
|
|
|
|
if (dri2_dpy->is_render_node &&
|
|
|
|
|
!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");
|
|
|
|
|
goto cleanup_screen;
|
|
|
|
|
}
|
|
|
|
|
|
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");
|
|
|
|
|
goto cleanup_screen;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-16 19:30:53 +01:00
|
|
|
|
types = EGL_WINDOW_BIT;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
for (i = 0; dri2_dpy->driver_configs[i]; i++) {
|
|
|
|
|
config = dri2_dpy->driver_configs[i];
|
2012-01-11 19:23:24 +00:00
|
|
|
|
if (dri2_dpy->formats & HAS_XRGB8888)
|
2013-09-15 07:13:22 +01:00
|
|
|
|
dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks);
|
2012-01-11 19:23:24 +00:00
|
|
|
|
if (dri2_dpy->formats & HAS_ARGB8888)
|
2013-09-15 07:13:22 +01:00
|
|
|
|
dri2_add_config(disp, config, i + 1, types, NULL, argb_masks);
|
2013-10-16 02:10:12 +01:00
|
|
|
|
if (dri2_dpy->formats & HAS_RGB565)
|
2013-09-15 07:13:22 +01:00
|
|
|
|
dri2_add_config(disp, config, i + 1, types, NULL, rgb565_masks);
|
2011-08-31 21:45:04 +01:00
|
|
|
|
}
|
2011-02-04 11:39:40 +00:00
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
|
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 */
|
|
|
|
|
if (!dri2_dpy->is_different_gpu) {
|
|
|
|
|
disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
dri2_wl_display_vtbl.create_wayland_buffer_from_image =
|
|
|
|
|
dri2_fallback_create_wayland_buffer_from_image;
|
|
|
|
|
}
|
2012-12-14 04:32:14 +00:00
|
|
|
|
disp->Extensions.EXT_buffer_age = EGL_TRUE;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2012-02-10 16:59:31 +00:00
|
|
|
|
disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;
|
|
|
|
|
|
2014-01-28 19:41:46 +00:00
|
|
|
|
/* Fill vtbl last to prevent accidentally calling virtual function during
|
|
|
|
|
* initialization.
|
|
|
|
|
*/
|
|
|
|
|
dri2_dpy->vtbl = &dri2_wl_display_vtbl;
|
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
|
2015-05-01 00:30:10 +01:00
|
|
|
|
cleanup_screen:
|
|
|
|
|
dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
cleanup_driver:
|
|
|
|
|
dlclose(dri2_dpy->driver);
|
|
|
|
|
cleanup_driver_name:
|
|
|
|
|
free(dri2_dpy->driver_name);
|
|
|
|
|
cleanup_fd:
|
|
|
|
|
close(dri2_dpy->fd);
|
2011-04-14 15:42:41 +01:00
|
|
|
|
cleanup_drm:
|
|
|
|
|
free(dri2_dpy->device_name);
|
|
|
|
|
wl_drm_destroy(dri2_dpy->wl_drm);
|
2015-04-30 23:03:32 +01:00
|
|
|
|
cleanup_registry:
|
|
|
|
|
wl_registry_destroy(dri2_dpy->wl_registry);
|
|
|
|
|
wl_event_queue_destroy(dri2_dpy->wl_queue);
|
2011-02-04 11:39:40 +00:00
|
|
|
|
cleanup_dpy:
|
|
|
|
|
free(dri2_dpy);
|
2016-08-04 03:07:51 +01:00
|
|
|
|
disp->DriverData = NULL;
|
2015-06-13 08:36:27 +01:00
|
|
|
|
|
2011-02-04 11:39:40 +00:00
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
dri2_wl_swrast_get_stride_for_format(int format, int w)
|
|
|
|
|
{
|
|
|
|
|
if (format == WL_SHM_FORMAT_RGB565)
|
|
|
|
|
return 2 * w;
|
|
|
|
|
else /* ARGB8888 || XRGB8888 */
|
|
|
|
|
return 4 * w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Taken from weston shared/os-compatibility.c
|
|
|
|
|
*/
|
|
|
|
|
|
2015-08-21 14:44:36 +01:00
|
|
|
|
#ifndef HAVE_MKOSTEMP
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static int
|
|
|
|
|
set_cloexec_or_close(int fd)
|
|
|
|
|
{
|
|
|
|
|
long flags;
|
|
|
|
|
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
flags = fcntl(fd, F_GETFD);
|
|
|
|
|
if (flags == -1)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
|
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
close(fd);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-21 14:44:36 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
/*
|
|
|
|
|
* Taken from weston shared/os-compatibility.c
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
create_tmpfile_cloexec(char *tmpname)
|
|
|
|
|
{
|
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_MKOSTEMP
|
|
|
|
|
fd = mkostemp(tmpname, O_CLOEXEC);
|
|
|
|
|
if (fd >= 0)
|
|
|
|
|
unlink(tmpname);
|
|
|
|
|
#else
|
|
|
|
|
fd = mkstemp(tmpname);
|
|
|
|
|
if (fd >= 0) {
|
|
|
|
|
fd = set_cloexec_or_close(fd);
|
|
|
|
|
unlink(tmpname);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Taken from weston shared/os-compatibility.c
|
|
|
|
|
*
|
|
|
|
|
* Create a new, unique, anonymous file of the given size, and
|
|
|
|
|
* return the file descriptor for it. The file descriptor is set
|
|
|
|
|
* CLOEXEC. The file is immediately suitable for mmap()'ing
|
|
|
|
|
* the given size at offset zero.
|
|
|
|
|
*
|
|
|
|
|
* The file should not have a permanent backing store like a disk,
|
|
|
|
|
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
|
|
|
|
|
*
|
|
|
|
|
* The file name is deleted from the file system.
|
|
|
|
|
*
|
|
|
|
|
* The file is suitable for buffer sharing between processes by
|
|
|
|
|
* transmitting the file descriptor over Unix sockets using the
|
|
|
|
|
* SCM_RIGHTS methods.
|
|
|
|
|
*
|
|
|
|
|
* If the C library implements posix_fallocate(), it is used to
|
|
|
|
|
* guarantee that disk space is available for the file at the
|
|
|
|
|
* given size. If disk space is insufficent, errno is set to ENOSPC.
|
|
|
|
|
* If posix_fallocate() is not supported, program may receive
|
|
|
|
|
* SIGBUS on accessing mmap()'ed file contents instead.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
os_create_anonymous_file(off_t size)
|
|
|
|
|
{
|
|
|
|
|
static const char template[] = "/mesa-shared-XXXXXX";
|
|
|
|
|
const char *path;
|
|
|
|
|
char *name;
|
|
|
|
|
int fd;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
path = getenv("XDG_RUNTIME_DIR");
|
|
|
|
|
if (!path) {
|
|
|
|
|
errno = ENOENT;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name = malloc(strlen(path) + sizeof(template));
|
|
|
|
|
if (!name)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
strcpy(name, path);
|
|
|
|
|
strcat(name, template);
|
|
|
|
|
|
|
|
|
|
fd = create_tmpfile_cloexec(name);
|
|
|
|
|
|
|
|
|
|
free(name);
|
|
|
|
|
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
ret = ftruncate(fd, size);
|
|
|
|
|
if (ret < 0) {
|
|
|
|
|
close(fd);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_wl_swrast_allocate_buffer(struct dri2_egl_display *dri2_dpy,
|
|
|
|
|
int format, int w, int h,
|
|
|
|
|
void **data, int *size,
|
|
|
|
|
struct wl_buffer **buffer)
|
|
|
|
|
{
|
|
|
|
|
struct wl_shm_pool *pool;
|
|
|
|
|
int fd, stride, size_map;
|
|
|
|
|
void *data_map;
|
|
|
|
|
|
|
|
|
|
stride = dri2_wl_swrast_get_stride_for_format(format, w);
|
|
|
|
|
size_map = h * stride;
|
|
|
|
|
|
|
|
|
|
/* Create a sharable buffer */
|
|
|
|
|
fd = os_create_anonymous_file(size_map);
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
|
|
|
|
if (data_map == MAP_FAILED) {
|
|
|
|
|
close(fd);
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Share it in a wl_buffer */
|
|
|
|
|
pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);
|
|
|
|
|
*buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);
|
|
|
|
|
wl_shm_pool_destroy(pool);
|
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
|
|
*data = data_map;
|
|
|
|
|
*size = size_map;
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
swrast_update_buffers(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* we need to do the following operations only once per frame */
|
|
|
|
|
if (dri2_surf->back)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (dri2_surf->base.Width != dri2_surf->wl_win->width ||
|
|
|
|
|
dri2_surf->base.Height != dri2_surf->wl_win->height) {
|
|
|
|
|
|
|
|
|
|
dri2_wl_release_buffers(dri2_surf);
|
|
|
|
|
|
|
|
|
|
dri2_surf->base.Width = dri2_surf->wl_win->width;
|
|
|
|
|
dri2_surf->base.Height = dri2_surf->wl_win->height;
|
|
|
|
|
dri2_surf->dx = dri2_surf->wl_win->dx;
|
|
|
|
|
dri2_surf->dy = dri2_surf->wl_win->dy;
|
|
|
|
|
dri2_surf->current = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* find back buffer */
|
|
|
|
|
|
|
|
|
|
/* We always want to throttle to some event (either a frame callback or
|
|
|
|
|
* a sync request) after the commit so that we can be sure the
|
|
|
|
|
* compositor has had a chance to handle it and send us a release event
|
|
|
|
|
* before we look for a free buffer */
|
|
|
|
|
while (dri2_surf->throttle_callback != NULL)
|
|
|
|
|
if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,
|
|
|
|
|
dri2_dpy->wl_queue) == -1)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
/* try get free buffer already created */
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked &&
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer) {
|
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* else choose any another free location */
|
|
|
|
|
if (!dri2_surf->back) {
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked) {
|
|
|
|
|
dri2_surf->back = &dri2_surf->color_buffers[i];
|
|
|
|
|
if (!dri2_wl_swrast_allocate_buffer(dri2_dpy,
|
|
|
|
|
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_proxy_set_queue((struct wl_proxy *) dri2_surf->back->wl_buffer,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
wl_buffer_add_listener(dri2_surf->back->wl_buffer,
|
|
|
|
|
&wl_buffer_listener, dri2_surf);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!dri2_surf->back) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "failed to find free buffer");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_surf->back->locked = 1;
|
|
|
|
|
|
|
|
|
|
/* If we have an extra unlocked buffer at this point, we had to do triple
|
|
|
|
|
* buffering for a while, but now can go back to just double buffering.
|
|
|
|
|
* That means we can free any unlocked buffer now. */
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
|
|
|
|
|
if (!dri2_surf->color_buffers[i].locked &&
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer) {
|
|
|
|
|
wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);
|
|
|
|
|
munmap(dri2_surf->color_buffers[i].data,
|
|
|
|
|
dri2_surf->color_buffers[i].data_size);
|
|
|
|
|
dri2_surf->color_buffers[i].wl_buffer = NULL;
|
|
|
|
|
dri2_surf->color_buffers[i].data = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void*
|
|
|
|
|
dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
/* if there has been a resize: */
|
|
|
|
|
if (!dri2_surf->current)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return dri2_surf->current->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void*
|
|
|
|
|
dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
assert(dri2_surf->back);
|
|
|
|
|
return dri2_surf->back->data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
|
|
|
|
|
if (dri2_surf->base.SwapInterval > 0) {
|
|
|
|
|
dri2_surf->throttle_callback =
|
|
|
|
|
wl_surface_frame(dri2_surf->wl_win->surface);
|
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_surf->current = dri2_surf->back;
|
|
|
|
|
dri2_surf->back = NULL;
|
|
|
|
|
|
|
|
|
|
wl_surface_attach(dri2_surf->wl_win->surface,
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
wl_surface_damage(dri2_surf->wl_win->surface,
|
|
|
|
|
0, 0, INT32_MAX, INT32_MAX);
|
|
|
|
|
wl_surface_commit(dri2_surf->wl_win->surface);
|
|
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
|
dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy);
|
|
|
|
|
wl_callback_add_listener(dri2_surf->throttle_callback,
|
|
|
|
|
&throttle_listener, dri2_surf);
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface().
|
|
|
|
|
*/
|
|
|
|
|
static _EGLSurface *
|
|
|
|
|
dri2_wl_swrast_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
|
|
|
|
|
_EGLConfig *conf, void *native_window,
|
|
|
|
|
const EGLint *attrib_list)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
|
|
|
|
|
struct wl_egl_window *window = native_window;
|
|
|
|
|
struct dri2_egl_surface *dri2_surf;
|
2015-09-13 12:36:54 +01:00
|
|
|
|
const __DRIconfig *config;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
dri2_surf = calloc(1, sizeof *dri2_surf);
|
|
|
|
|
if (!dri2_surf) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_surface");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, attrib_list))
|
|
|
|
|
goto cleanup_surf;
|
|
|
|
|
|
|
|
|
|
if (conf->RedSize == 5)
|
|
|
|
|
dri2_surf->format = WL_SHM_FORMAT_RGB565;
|
|
|
|
|
else if (conf->AlphaSize == 0)
|
|
|
|
|
dri2_surf->format = WL_SHM_FORMAT_XRGB8888;
|
|
|
|
|
else
|
|
|
|
|
dri2_surf->format = WL_SHM_FORMAT_ARGB8888;
|
|
|
|
|
|
|
|
|
|
dri2_surf->wl_win = window;
|
|
|
|
|
|
|
|
|
|
dri2_surf->base.Width = -1;
|
|
|
|
|
dri2_surf->base.Height = -1;
|
|
|
|
|
|
2015-09-13 12:36:54 +01:00
|
|
|
|
config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,
|
|
|
|
|
dri2_surf->base.GLColorspace);
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_surf->dri_drawable =
|
2015-09-13 12:36:54 +01:00
|
|
|
|
(*dri2_dpy->swrast->createNewDrawable)(dri2_dpy->dri_screen,
|
|
|
|
|
config, dri2_surf);
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_surf->dri_drawable == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "swrast->createNewDrawable");
|
|
|
|
|
goto cleanup_dri_drawable;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_wl_swap_interval(drv, disp, &dri2_surf->base,
|
|
|
|
|
dri2_dpy->default_swap_interval);
|
|
|
|
|
|
|
|
|
|
return &dri2_surf->base;
|
|
|
|
|
|
|
|
|
|
cleanup_dri_drawable:
|
|
|
|
|
dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
|
|
|
|
|
cleanup_surf:
|
|
|
|
|
free(dri2_surf);
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
|
|
|
|
|
|
|
|
|
|
dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
|
case WL_SHM_FORMAT_ARGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_ARGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_SHM_FORMAT_XRGB8888:
|
|
|
|
|
dri2_dpy->formats |= HAS_XRGB8888;
|
|
|
|
|
break;
|
|
|
|
|
case WL_SHM_FORMAT_RGB565:
|
|
|
|
|
dri2_dpy->formats |= HAS_RGB565;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_shm_listener shm_listener = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.format = shm_handle_format
|
2015-05-01 10:11:20 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
registry_handle_global_swrast(void *data, struct wl_registry *registry, uint32_t name,
|
|
|
|
|
const char *interface, uint32_t version)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = data;
|
|
|
|
|
|
|
|
|
|
if (strcmp(interface, "wl_shm") == 0) {
|
|
|
|
|
dri2_dpy->wl_shm =
|
|
|
|
|
wl_registry_bind(registry, name, &wl_shm_interface, 1);
|
|
|
|
|
wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct wl_registry_listener registry_listener_swrast = {
|
2015-07-10 12:24:11 +01:00
|
|
|
|
.global = registry_handle_global_swrast,
|
|
|
|
|
.global_remove = registry_handle_global_remove
|
2015-05-01 10:11:20 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {
|
|
|
|
|
.authenticate = NULL,
|
|
|
|
|
.create_window_surface = dri2_wl_swrast_create_window_surface,
|
|
|
|
|
.create_pixmap_surface = dri2_wl_create_pixmap_surface,
|
|
|
|
|
.create_pbuffer_surface = dri2_fallback_create_pbuffer_surface,
|
|
|
|
|
.destroy_surface = dri2_wl_destroy_surface,
|
|
|
|
|
.create_image = dri2_fallback_create_image_khr,
|
|
|
|
|
.swap_interval = dri2_wl_swap_interval,
|
|
|
|
|
.swap_buffers = dri2_wl_swrast_swap_buffers,
|
|
|
|
|
.swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
|
|
|
|
|
.swap_buffers_region = dri2_fallback_swap_buffers_region,
|
|
|
|
|
.post_sub_buffer = dri2_fallback_post_sub_buffer,
|
|
|
|
|
.copy_buffers = dri2_fallback_copy_buffers,
|
|
|
|
|
.query_buffer_age = dri2_fallback_query_buffer_age,
|
|
|
|
|
.create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image,
|
|
|
|
|
.get_sync_values = dri2_fallback_get_sync_values,
|
2015-07-21 16:43:59 +01:00
|
|
|
|
.get_dri_drawable = dri2_surface_get_dri_drawable,
|
2015-05-01 10:11:20 +01:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-16 18:39:14 +01:00
|
|
|
|
static const __DRIswrastLoaderExtension swrast_loader_extension = {
|
|
|
|
|
.base = { __DRI_SWRAST_LOADER, 2 },
|
|
|
|
|
|
|
|
|
|
.getDrawableInfo = dri2_wl_swrast_get_drawable_info,
|
|
|
|
|
.putImage = dri2_wl_swrast_put_image,
|
|
|
|
|
.getImage = dri2_wl_swrast_get_image,
|
|
|
|
|
.putImage2 = dri2_wl_swrast_put_image2,
|
|
|
|
|
};
|
|
|
|
|
|
2015-05-01 10:11:20 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy;
|
|
|
|
|
const __DRIconfig *config;
|
|
|
|
|
uint32_t types;
|
|
|
|
|
int i;
|
|
|
|
|
static const unsigned int argb_masks[4] =
|
|
|
|
|
{ 0xff0000, 0xff00, 0xff, 0xff000000 };
|
|
|
|
|
static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 };
|
|
|
|
|
static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 };
|
|
|
|
|
|
|
|
|
|
loader_set_logger(_eglLog);
|
|
|
|
|
|
|
|
|
|
dri2_dpy = calloc(1, sizeof *dri2_dpy);
|
|
|
|
|
if (!dri2_dpy)
|
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "eglInitialize");
|
|
|
|
|
|
|
|
|
|
disp->DriverData = (void *) dri2_dpy;
|
|
|
|
|
if (disp->PlatformDisplay == NULL) {
|
|
|
|
|
dri2_dpy->wl_dpy = wl_display_connect(NULL);
|
|
|
|
|
if (dri2_dpy->wl_dpy == NULL)
|
|
|
|
|
goto cleanup_dpy;
|
|
|
|
|
dri2_dpy->own_device = 1;
|
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->wl_dpy = disp->PlatformDisplay;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->own_device)
|
|
|
|
|
wl_display_dispatch_pending(dri2_dpy->wl_dpy);
|
|
|
|
|
|
|
|
|
|
dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy);
|
|
|
|
|
wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry,
|
|
|
|
|
dri2_dpy->wl_queue);
|
|
|
|
|
wl_registry_add_listener(dri2_dpy->wl_registry,
|
|
|
|
|
®istry_listener_swrast, dri2_dpy);
|
|
|
|
|
|
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)
|
|
|
|
|
goto cleanup_registry;
|
|
|
|
|
|
|
|
|
|
if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0)
|
|
|
|
|
goto cleanup_shm;
|
|
|
|
|
|
2015-09-10 14:41:38 +01:00
|
|
|
|
dri2_dpy->fd = -1;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_dpy->driver_name = strdup("swrast");
|
|
|
|
|
if (!dri2_load_driver_swrast(disp))
|
|
|
|
|
goto cleanup_shm;
|
|
|
|
|
|
2016-08-16 18:39:14 +01:00
|
|
|
|
dri2_dpy->extensions[0] = &swrast_loader_extension.base;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
dri2_dpy->extensions[1] = NULL;
|
|
|
|
|
|
|
|
|
|
if (!dri2_create_screen(disp))
|
|
|
|
|
goto cleanup_driver;
|
|
|
|
|
|
|
|
|
|
dri2_wl_setup_swap_interval(dri2_dpy);
|
|
|
|
|
|
|
|
|
|
types = EGL_WINDOW_BIT;
|
|
|
|
|
for (i = 0; dri2_dpy->driver_configs[i]; i++) {
|
|
|
|
|
config = dri2_dpy->driver_configs[i];
|
|
|
|
|
if (dri2_dpy->formats & HAS_XRGB8888)
|
|
|
|
|
dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks);
|
|
|
|
|
if (dri2_dpy->formats & HAS_ARGB8888)
|
|
|
|
|
dri2_add_config(disp, config, i + 1, types, NULL, argb_masks);
|
|
|
|
|
if (dri2_dpy->formats & HAS_RGB565)
|
|
|
|
|
dri2_add_config(disp, config, i + 1, types, NULL, rgb565_masks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Fill vtbl last to prevent accidentally calling virtual function during
|
|
|
|
|
* initialization.
|
|
|
|
|
*/
|
|
|
|
|
dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
|
|
|
|
|
cleanup_driver:
|
|
|
|
|
dlclose(dri2_dpy->driver);
|
|
|
|
|
cleanup_shm:
|
|
|
|
|
wl_shm_destroy(dri2_dpy->wl_shm);
|
|
|
|
|
cleanup_registry:
|
|
|
|
|
wl_registry_destroy(dri2_dpy->wl_registry);
|
|
|
|
|
wl_event_queue_destroy(dri2_dpy->wl_queue);
|
|
|
|
|
cleanup_dpy:
|
|
|
|
|
free(dri2_dpy);
|
2016-08-04 03:07:51 +01:00
|
|
|
|
disp->DriverData = NULL;
|
2015-05-01 10:11:20 +01:00
|
|
|
|
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
EGLBoolean initialized = EGL_TRUE;
|
|
|
|
|
|
|
|
|
|
int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
|
|
|
|
|
|
|
|
|
|
if (hw_accel) {
|
|
|
|
|
if (!dri2_initialize_wayland_drm(drv, disp)) {
|
|
|
|
|
initialized = dri2_initialize_wayland_swrast(drv, disp);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
initialized = dri2_initialize_wayland_swrast(drv, disp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return initialized;
|
|
|
|
|
|
|
|
|
|
}
|