2010-02-03 15:18:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright © 2010 Intel Corporation
|
|
|
|
|
*
|
|
|
|
|
* 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>
|
|
|
|
|
*/
|
|
|
|
|
|
2014-01-29 02:53:56 +00:00
|
|
|
|
#define WL_HIDE_DEPRECATED
|
|
|
|
|
|
2015-07-21 16:43:56 +01:00
|
|
|
|
#include <stdbool.h>
|
2015-02-28 17:12:40 +00:00
|
|
|
|
#include <stdint.h>
|
2015-06-10 01:49:29 +01:00
|
|
|
|
#include <stdbool.h>
|
2010-02-03 15:18:28 +00:00
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <unistd.h>
|
2016-04-05 01:14:10 +01:00
|
|
|
|
#include <c11/threads.h>
|
|
|
|
|
#include <time.h>
|
2014-05-28 14:36:46 +01:00
|
|
|
|
#ifdef HAVE_LIBDRM
|
2010-02-03 15:18:28 +00:00
|
|
|
|
#include <xf86drm.h>
|
2013-03-22 13:58:05 +00:00
|
|
|
|
#include <drm_fourcc.h>
|
2013-11-10 18:32:01 +00:00
|
|
|
|
#endif
|
2010-02-03 15:18:28 +00:00
|
|
|
|
#include <GL/gl.h>
|
|
|
|
|
#include <GL/internal/dri_interface.h>
|
2016-03-03 14:59:48 +00:00
|
|
|
|
#include "GL/mesa_glinterop.h"
|
2010-06-03 03:48:06 +01:00
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
2013-07-18 13:11:25 +01:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
|
|
|
|
#include "wayland-drm.h"
|
2014-01-29 02:53:56 +00:00
|
|
|
|
#include "wayland-drm-client-protocol.h"
|
2013-07-18 13:11:25 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2017-05-29 12:18:27 +01:00
|
|
|
|
#ifdef HAVE_X11_PLATFORM
|
|
|
|
|
#include "X11/Xlibint.h"
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-01-29 02:53:56 +00:00
|
|
|
|
#include "egl_dri2.h"
|
2016-11-09 14:50:06 +00:00
|
|
|
|
#include "loader/loader.h"
|
2015-08-07 18:55:40 +01:00
|
|
|
|
#include "util/u_atomic.h"
|
2014-01-29 02:53:56 +00:00
|
|
|
|
|
2015-06-23 23:48:17 +01:00
|
|
|
|
/* The kernel header drm_fourcc.h defines the DRM formats below. We duplicate
|
|
|
|
|
* some of the definitions here so that building Mesa won't bleeding-edge
|
|
|
|
|
* kernel headers.
|
|
|
|
|
*/
|
|
|
|
|
#ifndef DRM_FORMAT_R8
|
|
|
|
|
#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef DRM_FORMAT_RG88
|
|
|
|
|
#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef DRM_FORMAT_GR88
|
|
|
|
|
#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-01-05 15:58:56 +00:00
|
|
|
|
#ifndef DRM_FORMAT_R16
|
|
|
|
|
#define DRM_FORMAT_R16 fourcc_code('R', '1', '6', ' ') /* [15:0] R 16 little endian */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef DRM_FORMAT_GR1616
|
|
|
|
|
#define DRM_FORMAT_GR1616 fourcc_code('G', 'R', '3', '2') /* [31:0] R:G 16:16 little endian */
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-05-30 12:53:37 +01:00
|
|
|
|
#ifndef DRM_FORMAT_MOD_INVALID
|
|
|
|
|
#define DRM_FORMAT_MOD_INVALID ((1ULL<<56) - 1)
|
|
|
|
|
#endif
|
|
|
|
|
|
2012-12-28 01:39:37 +00:00
|
|
|
|
static void
|
|
|
|
|
dri_set_background_context(void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
|
|
|
|
_EGLThreadInfo *t = _eglGetCurrentThread();
|
|
|
|
|
|
|
|
|
|
_eglBindContextToThread(ctx, t);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-29 12:18:27 +01:00
|
|
|
|
static GLboolean
|
|
|
|
|
dri_is_thread_safe(void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
_EGLDisplay *display = dri2_surf->base.Resource.Display;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_X11_PLATFORM
|
|
|
|
|
Display *xdpy = (Display*)display->PlatformDisplay;
|
|
|
|
|
|
|
|
|
|
/* Check Xlib is running in thread safe mode when running on EGL/X11-xlib
|
|
|
|
|
* platform
|
|
|
|
|
*
|
|
|
|
|
* 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'.
|
|
|
|
|
* It wll be NULL if XInitThreads wasn't called.
|
|
|
|
|
*/
|
|
|
|
|
if (display->Platform == _EGL_PLATFORM_X11 && xdpy && !xdpy->lock_fns)
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
|
|
|
|
if (display->Platform == _EGL_PLATFORM_WAYLAND)
|
|
|
|
|
return true;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-28 01:39:37 +00:00
|
|
|
|
const __DRIbackgroundCallableExtension background_callable_extension = {
|
2017-05-29 12:18:27 +01:00
|
|
|
|
.base = { __DRI_BACKGROUND_CALLABLE, 2 },
|
2012-12-28 01:39:37 +00:00
|
|
|
|
|
|
|
|
|
.setBackgroundContext = dri_set_background_context,
|
2017-05-29 12:18:27 +01:00
|
|
|
|
.isThreadSafe = dri_is_thread_safe,
|
2012-12-28 01:39:37 +00:00
|
|
|
|
};
|
|
|
|
|
|
2011-02-03 03:21:13 +00:00
|
|
|
|
const __DRIuseInvalidateExtension use_invalidate = {
|
2014-02-12 20:13:15 +00:00
|
|
|
|
.base = { __DRI_USE_INVALIDATE, 1 }
|
2010-06-03 03:48:06 +01:00
|
|
|
|
};
|
|
|
|
|
|
2017-05-01 19:40:31 +01:00
|
|
|
|
static const EGLint dri2_to_egl_attribute_map[__DRI_ATTRIB_MAX] = {
|
2017-04-28 17:01:03 +01:00
|
|
|
|
[__DRI_ATTRIB_BUFFER_SIZE ] = EGL_BUFFER_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_LEVEL] = EGL_LEVEL,
|
|
|
|
|
[__DRI_ATTRIB_RED_SIZE] = EGL_RED_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_GREEN_SIZE] = EGL_GREEN_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_BLUE_SIZE] = EGL_BLUE_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_LUMINANCE_SIZE] = EGL_LUMINANCE_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_ALPHA_SIZE] = EGL_ALPHA_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_DEPTH_SIZE] = EGL_DEPTH_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_STENCIL_SIZE] = EGL_STENCIL_SIZE,
|
|
|
|
|
[__DRI_ATTRIB_SAMPLE_BUFFERS] = EGL_SAMPLE_BUFFERS,
|
|
|
|
|
[__DRI_ATTRIB_SAMPLES] = EGL_SAMPLES,
|
|
|
|
|
[__DRI_ATTRIB_MAX_PBUFFER_WIDTH] = EGL_MAX_PBUFFER_WIDTH,
|
|
|
|
|
[__DRI_ATTRIB_MAX_PBUFFER_HEIGHT] = EGL_MAX_PBUFFER_HEIGHT,
|
|
|
|
|
[__DRI_ATTRIB_MAX_PBUFFER_PIXELS] = EGL_MAX_PBUFFER_PIXELS,
|
|
|
|
|
[__DRI_ATTRIB_MAX_SWAP_INTERVAL] = EGL_MAX_SWAP_INTERVAL,
|
|
|
|
|
[__DRI_ATTRIB_MIN_SWAP_INTERVAL] = EGL_MIN_SWAP_INTERVAL,
|
|
|
|
|
[__DRI_ATTRIB_YINVERTED] = EGL_Y_INVERTED_NOK,
|
2010-02-03 15:18:28 +00:00
|
|
|
|
};
|
|
|
|
|
|
2015-06-10 01:49:29 +01:00
|
|
|
|
const __DRIconfig *
|
|
|
|
|
dri2_get_dri_config(struct dri2_egl_config *conf, EGLint surface_type,
|
|
|
|
|
EGLenum colorspace)
|
|
|
|
|
{
|
2015-09-13 12:25:27 +01:00
|
|
|
|
const bool srgb = colorspace == EGL_GL_COLORSPACE_SRGB_KHR;
|
|
|
|
|
|
|
|
|
|
return surface_type == EGL_WINDOW_BIT ? conf->dri_double_config[srgb] :
|
|
|
|
|
conf->dri_single_config[srgb];
|
2015-06-10 01:49:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-06-11 22:00:40 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_match_config(const _EGLConfig *conf, const _EGLConfig *criteria)
|
|
|
|
|
{
|
|
|
|
|
if (_eglCompareConfigs(conf, criteria, NULL, EGL_FALSE) != 0)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
if (!_eglMatchConfig(conf, criteria))
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-03 03:10:40 +00:00
|
|
|
|
struct dri2_egl_config *
|
2010-02-10 01:49:40 +00:00
|
|
|
|
dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
EGLint surface_type, const EGLint *attr_list,
|
|
|
|
|
const unsigned int *rgba_masks)
|
2010-02-03 15:18:28 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_config *conf;
|
2016-07-15 12:47:37 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2010-02-10 02:01:04 +00:00
|
|
|
|
_EGLConfig base;
|
2010-02-05 02:49:44 +00:00
|
|
|
|
unsigned int attrib, value, double_buffer;
|
2015-06-10 01:49:29 +01:00
|
|
|
|
bool srgb = false;
|
2010-02-05 02:49:44 +00:00
|
|
|
|
EGLint key, bind_to_texture_rgb, bind_to_texture_rgba;
|
2011-08-05 06:36:14 +01:00
|
|
|
|
unsigned int dri_masks[4] = { 0, 0, 0, 0 };
|
2011-02-09 14:30:20 +00:00
|
|
|
|
_EGLConfig *matching_config;
|
|
|
|
|
EGLint num_configs = 0;
|
2016-11-09 21:45:07 +00:00
|
|
|
|
EGLint config_id;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
int i;
|
|
|
|
|
|
2010-02-10 02:01:04 +00:00
|
|
|
|
_eglInitConfig(&base, disp, id);
|
2015-06-13 08:36:27 +01:00
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
i = 0;
|
2010-07-27 23:25:54 +01:00
|
|
|
|
double_buffer = 0;
|
|
|
|
|
bind_to_texture_rgb = 0;
|
|
|
|
|
bind_to_texture_rgba = 0;
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
while (dri2_dpy->core->indexConfigAttrib(dri_config, i++, &attrib, &value)) {
|
|
|
|
|
switch (attrib) {
|
|
|
|
|
case __DRI_ATTRIB_RENDER_TYPE:
|
2016-08-25 00:12:13 +01:00
|
|
|
|
if (value & __DRI_ATTRIB_RGBA_BIT)
|
|
|
|
|
value = EGL_RGB_BUFFER;
|
|
|
|
|
else if (value & __DRI_ATTRIB_LUMINANCE_BIT)
|
|
|
|
|
value = EGL_LUMINANCE_BUFFER;
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
|
|
|
|
_eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value);
|
|
|
|
|
break;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_CONFIG_CAVEAT:
|
|
|
|
|
if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
|
|
|
|
|
value = EGL_NON_CONFORMANT_CONFIG;
|
|
|
|
|
else if (value & __DRI_ATTRIB_SLOW_BIT)
|
|
|
|
|
value = EGL_SLOW_CONFIG;
|
2016-08-25 00:12:13 +01:00
|
|
|
|
else
|
|
|
|
|
value = EGL_NONE;
|
|
|
|
|
_eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2010-02-05 02:49:44 +00:00
|
|
|
|
case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB:
|
2016-08-25 00:12:13 +01:00
|
|
|
|
bind_to_texture_rgb = value;
|
|
|
|
|
break;
|
2010-02-05 02:49:44 +00:00
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA:
|
2016-08-25 00:12:13 +01:00
|
|
|
|
bind_to_texture_rgba = value;
|
|
|
|
|
break;
|
2010-02-05 02:49:44 +00:00
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
case __DRI_ATTRIB_DOUBLE_BUFFER:
|
2016-08-25 00:12:13 +01:00
|
|
|
|
double_buffer = value;
|
|
|
|
|
break;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2011-08-05 06:36:14 +01:00
|
|
|
|
case __DRI_ATTRIB_RED_MASK:
|
|
|
|
|
dri_masks[0] = value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_GREEN_MASK:
|
|
|
|
|
dri_masks[1] = value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_BLUE_MASK:
|
|
|
|
|
dri_masks[2] = value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_ALPHA_MASK:
|
|
|
|
|
dri_masks[3] = value;
|
|
|
|
|
break;
|
|
|
|
|
|
2015-04-09 22:25:07 +01:00
|
|
|
|
case __DRI_ATTRIB_ACCUM_RED_SIZE:
|
|
|
|
|
case __DRI_ATTRIB_ACCUM_GREEN_SIZE:
|
|
|
|
|
case __DRI_ATTRIB_ACCUM_BLUE_SIZE:
|
|
|
|
|
case __DRI_ATTRIB_ACCUM_ALPHA_SIZE:
|
|
|
|
|
/* Don't expose visuals with the accumulation buffer. */
|
|
|
|
|
if (value > 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
2015-06-10 01:49:29 +01:00
|
|
|
|
case __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE:
|
|
|
|
|
srgb = value != 0;
|
2015-11-29 16:48:51 +00:00
|
|
|
|
if (!disp->Extensions.KHR_gl_colorspace && srgb)
|
|
|
|
|
return NULL;
|
2015-06-10 01:49:29 +01:00
|
|
|
|
break;
|
|
|
|
|
|
2016-10-20 08:33:33 +01:00
|
|
|
|
case __DRI_ATTRIB_MAX_PBUFFER_WIDTH:
|
|
|
|
|
_eglSetConfigKey(&base, EGL_MAX_PBUFFER_WIDTH,
|
|
|
|
|
_EGL_MAX_PBUFFER_WIDTH);
|
|
|
|
|
break;
|
|
|
|
|
case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT:
|
|
|
|
|
_eglSetConfigKey(&base, EGL_MAX_PBUFFER_HEIGHT,
|
|
|
|
|
_EGL_MAX_PBUFFER_HEIGHT);
|
|
|
|
|
break;
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
default:
|
2016-08-25 00:12:13 +01:00
|
|
|
|
key = dri2_to_egl_attribute_map[attrib];
|
|
|
|
|
if (key != 0)
|
|
|
|
|
_eglSetConfigKey(&base, key, value);
|
|
|
|
|
break;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 14:30:20 +00:00
|
|
|
|
if (attr_list)
|
|
|
|
|
for (i = 0; attr_list[i] != EGL_NONE; i += 2)
|
|
|
|
|
_eglSetConfigKey(&base, attr_list[i], attr_list[i+1]);
|
2010-02-10 01:49:40 +00:00
|
|
|
|
|
2011-08-05 06:36:14 +01:00
|
|
|
|
if (rgba_masks && memcmp(rgba_masks, dri_masks, sizeof(dri_masks)))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2010-10-22 08:03:11 +01:00
|
|
|
|
base.NativeRenderable = EGL_TRUE;
|
2010-02-10 02:01:04 +00:00
|
|
|
|
|
2010-10-22 08:03:11 +01:00
|
|
|
|
base.SurfaceType = surface_type;
|
2011-02-04 11:32:30 +00:00
|
|
|
|
if (surface_type & (EGL_PBUFFER_BIT |
|
|
|
|
|
(disp->Extensions.NOK_texture_from_pixmap ? EGL_PIXMAP_BIT : 0))) {
|
2010-10-22 08:03:11 +01:00
|
|
|
|
base.BindToTextureRGB = bind_to_texture_rgb;
|
|
|
|
|
if (base.AlphaSize > 0)
|
|
|
|
|
base.BindToTextureRGBA = bind_to_texture_rgba;
|
2010-02-05 02:49:44 +00:00
|
|
|
|
}
|
2010-02-10 01:49:40 +00:00
|
|
|
|
|
2011-01-13 08:53:13 +00:00
|
|
|
|
base.RenderableType = disp->ClientAPIs;
|
|
|
|
|
base.Conformant = disp->ClientAPIs;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
egl/dri2: Fix min/max swap interval of configs
The commit below exposed a bug in dri2_add_config.
commit 3998f8c6b5da1a223926249755e54d8f701f81ab
Author: Ralf Jung <post@ralfj.de>
Date: Tue Apr 9 14:09:50 2013 +0200
egl/x11: Fix initialisation of swap_interval
This little code snippet near the bottom of dri2_add_config,
if (double_buffer) {
...
conf->base.MinSwapInterval = dri2_dpy->min_swap_interval;
conf->base.MaxSwapInterval = dri2_dpy->max_swap_interval;
}
it never did what it claimed to do. The assignment never changed the value
of conf->base.MaxSwapInterval, because dri2_dpy->max_swap_interval was,
until the above exposing commit, unitialized here. That is,
conf->base.MaxSwapInterval was 0 before and after assignment. Ditto for
the min swap interval.
Above the troublesome code snippet, the call to _eglFilterArray rejects
the config as unmatching if its swap interval bounds differ from the base
config's. Before the exposing commit, at the call to _eglFilterArray, the
swap interval bounds were always [0,0], and hence no config was rejected
due to swap interval.
After the exposing commit, _eglFilterArray incorrectly rejected some
configs, which prevented dri2_egl_config::dri_double_config from getting
set for the rejected config, which resulted in a NULL pointer getting
passed into dri2CreateNewDrawable, and then segfault.
The solution: set the swap interval bounds before _eglFilterArray.
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=63447
Tested-by: Lu Hua <huax.lu@intel.com>
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
2013-04-23 03:17:48 +01:00
|
|
|
|
base.MinSwapInterval = dri2_dpy->min_swap_interval;
|
|
|
|
|
base.MaxSwapInterval = dri2_dpy->max_swap_interval;
|
|
|
|
|
|
2010-02-10 02:01:04 +00:00
|
|
|
|
if (!_eglValidateConfig(&base, EGL_FALSE)) {
|
2010-02-05 02:49:44 +00:00
|
|
|
|
_eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
|
2010-07-27 23:25:54 +01:00
|
|
|
|
return NULL;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-09 21:45:07 +00:00
|
|
|
|
config_id = base.ConfigID;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
base.ConfigID = EGL_DONT_CARE;
|
|
|
|
|
base.SurfaceType = EGL_DONT_CARE;
|
|
|
|
|
num_configs = _eglFilterArray(disp->Configs, (void **) &matching_config, 1,
|
2011-06-11 22:00:40 +01:00
|
|
|
|
(_EGLArrayForEach) dri2_match_config, &base);
|
2011-02-09 14:30:20 +00:00
|
|
|
|
|
|
|
|
|
if (num_configs == 1) {
|
|
|
|
|
conf = (struct dri2_egl_config *) matching_config;
|
|
|
|
|
|
2015-09-13 12:25:27 +01:00
|
|
|
|
if (double_buffer && !conf->dri_double_config[srgb])
|
|
|
|
|
conf->dri_double_config[srgb] = dri_config;
|
|
|
|
|
else if (!double_buffer && !conf->dri_single_config[srgb])
|
|
|
|
|
conf->dri_single_config[srgb] = dri_config;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
else
|
2011-05-12 18:30:05 +01:00
|
|
|
|
/* a similar config type is already added (unlikely) => discard */
|
|
|
|
|
return NULL;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
}
|
2011-05-12 15:23:48 +01:00
|
|
|
|
else if (num_configs == 0) {
|
2015-06-10 01:49:29 +01:00
|
|
|
|
conf = calloc(1, sizeof *conf);
|
2011-02-09 14:30:20 +00:00
|
|
|
|
if (conf == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2015-09-13 12:25:27 +01:00
|
|
|
|
if (double_buffer)
|
|
|
|
|
conf->dri_double_config[srgb] = dri_config;
|
|
|
|
|
else
|
|
|
|
|
conf->dri_single_config[srgb] = dri_config;
|
2015-10-07 05:18:14 +01:00
|
|
|
|
|
2015-10-07 05:18:15 +01:00
|
|
|
|
memcpy(&conf->base, &base, sizeof base);
|
2015-10-07 05:18:14 +01:00
|
|
|
|
conf->base.SurfaceType = 0;
|
2016-11-09 21:45:07 +00:00
|
|
|
|
conf->base.ConfigID = config_id;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
|
2010-10-22 17:47:22 +01:00
|
|
|
|
_eglLinkConfig(&conf->base);
|
2010-02-10 02:01:04 +00:00
|
|
|
|
}
|
2011-05-12 15:23:48 +01:00
|
|
|
|
else {
|
|
|
|
|
assert(0);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-07-27 23:25:54 +01:00
|
|
|
|
|
2011-12-20 16:17:02 +00:00
|
|
|
|
if (double_buffer) {
|
2011-08-31 23:20:06 +01:00
|
|
|
|
surface_type &= ~EGL_PIXMAP_BIT;
|
2011-12-20 16:17:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 08:03:32 +01:00
|
|
|
|
/* No support for pbuffer + MSAA for now.
|
|
|
|
|
*
|
|
|
|
|
* XXX TODO: pbuffer + MSAA does not work and causes crashes.
|
|
|
|
|
* See QT bugreport: https://bugreports.qt.io/browse/QTBUG-47509
|
|
|
|
|
*/
|
|
|
|
|
if (base.Samples) {
|
|
|
|
|
surface_type &= ~EGL_PBUFFER_BIT;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-31 23:20:06 +01:00
|
|
|
|
conf->base.SurfaceType |= surface_type;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
|
2010-07-27 23:25:54 +01:00
|
|
|
|
return conf;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-05-30 09:50:52 +01:00
|
|
|
|
__DRIimage *
|
2010-09-23 03:01:17 +01:00
|
|
|
|
dri2_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
|
2010-02-12 00:28:26 +00:00
|
|
|
|
{
|
2010-09-23 03:01:17 +01:00
|
|
|
|
_EGLDisplay *disp = data;
|
2010-02-12 00:28:26 +00:00
|
|
|
|
struct dri2_egl_image *dri2_img;
|
|
|
|
|
_EGLImage *img;
|
|
|
|
|
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) screen;
|
|
|
|
|
|
2010-02-12 00:28:26 +00:00
|
|
|
|
img = _eglLookupImage(image, disp);
|
|
|
|
|
if (img == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_lookup_egl_image");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_img = dri2_egl_image(image);
|
|
|
|
|
|
|
|
|
|
return dri2_img->dri_image;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-03 03:10:40 +00:00
|
|
|
|
const __DRIimageLookupExtension image_lookup_extension = {
|
2014-02-12 20:13:15 +00:00
|
|
|
|
.base = { __DRI_IMAGE_LOOKUP, 1 },
|
|
|
|
|
|
|
|
|
|
.lookupEGLImage = dri2_lookup_egl_image
|
2010-06-03 03:48:06 +01:00
|
|
|
|
};
|
|
|
|
|
|
2010-02-09 15:57:43 +00:00
|
|
|
|
struct dri2_extension_match {
|
|
|
|
|
const char *name;
|
|
|
|
|
int version;
|
|
|
|
|
int offset;
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-25 00:52:36 +01:00
|
|
|
|
static const struct dri2_extension_match dri3_driver_extensions[] = {
|
2015-07-21 16:44:00 +01:00
|
|
|
|
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
|
|
|
|
|
{ __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },
|
|
|
|
|
{ NULL, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
2016-08-25 00:52:36 +01:00
|
|
|
|
static const struct dri2_extension_match dri2_driver_extensions[] = {
|
2010-02-09 15:57:43 +00:00
|
|
|
|
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
|
2012-07-18 21:17:50 +01:00
|
|
|
|
{ __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },
|
2010-09-23 17:40:58 +01:00
|
|
|
|
{ NULL, 0, 0 }
|
2010-02-09 15:57:43 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-25 00:52:36 +01:00
|
|
|
|
static const struct dri2_extension_match dri2_core_extensions[] = {
|
2010-02-09 15:57:43 +00:00
|
|
|
|
{ __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
|
2010-02-09 20:49:28 +00:00
|
|
|
|
{ __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
|
2013-03-19 17:20:36 +00:00
|
|
|
|
{ __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
|
2010-09-23 17:40:58 +01:00
|
|
|
|
{ NULL, 0, 0 }
|
2010-02-09 15:57:43 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-25 00:52:36 +01:00
|
|
|
|
static const struct dri2_extension_match swrast_driver_extensions[] = {
|
2011-02-17 04:05:15 +00:00
|
|
|
|
{ __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
|
|
|
|
|
{ __DRI_SWRAST, 2, offsetof(struct dri2_egl_display, swrast) },
|
2012-07-19 19:08:02 +01:00
|
|
|
|
{ NULL, 0, 0 }
|
2011-02-17 04:05:15 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-25 00:52:36 +01:00
|
|
|
|
static const struct dri2_extension_match swrast_core_extensions[] = {
|
2011-02-17 04:05:15 +00:00
|
|
|
|
{ __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
|
2012-07-19 19:08:02 +01:00
|
|
|
|
{ NULL, 0, 0 }
|
2011-02-17 04:05:15 +00:00
|
|
|
|
};
|
|
|
|
|
|
2016-08-25 00:52:36 +01:00
|
|
|
|
static const struct dri2_extension_match optional_core_extensions[] = {
|
2016-08-25 00:51:05 +01:00
|
|
|
|
{ __DRI2_ROBUSTNESS, 1, offsetof(struct dri2_egl_display, robustness) },
|
|
|
|
|
{ __DRI2_CONFIG_QUERY, 1, offsetof(struct dri2_egl_display, config) },
|
|
|
|
|
{ __DRI2_FENCE, 1, offsetof(struct dri2_egl_display, fence) },
|
|
|
|
|
{ __DRI2_RENDERER_QUERY, 1, offsetof(struct dri2_egl_display, rendererQuery) },
|
|
|
|
|
{ __DRI2_INTEROP, 1, offsetof(struct dri2_egl_display, interop) },
|
|
|
|
|
{ NULL, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
2010-02-09 15:57:43 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
|
2016-08-25 00:52:36 +01:00
|
|
|
|
const struct dri2_extension_match *matches,
|
2016-08-25 00:16:01 +01:00
|
|
|
|
const __DRIextension **extensions,
|
|
|
|
|
bool optional)
|
2010-02-09 15:57:43 +00:00
|
|
|
|
{
|
|
|
|
|
int i, j, ret = EGL_TRUE;
|
|
|
|
|
void *field;
|
|
|
|
|
|
|
|
|
|
for (i = 0; extensions[i]; i++) {
|
2015-10-30 15:16:35 +00:00
|
|
|
|
_eglLog(_EGL_DEBUG, "found extension `%s'", extensions[i]->name);
|
2010-02-09 15:57:43 +00:00
|
|
|
|
for (j = 0; matches[j].name; j++) {
|
2016-08-25 00:12:13 +01:00
|
|
|
|
if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
|
|
|
|
|
extensions[i]->version >= matches[j].version) {
|
|
|
|
|
field = ((char *) dri2_dpy + matches[j].offset);
|
|
|
|
|
*(const __DRIextension **) field = extensions[i];
|
|
|
|
|
_eglLog(_EGL_INFO, "found extension %s version %d",
|
|
|
|
|
extensions[i]->name, extensions[i]->version);
|
2016-08-25 09:51:54 +01:00
|
|
|
|
break;
|
2016-08-25 00:12:13 +01:00
|
|
|
|
}
|
2010-02-09 15:57:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2015-06-13 08:36:27 +01:00
|
|
|
|
|
2010-02-09 15:57:43 +00:00
|
|
|
|
for (j = 0; matches[j].name; j++) {
|
|
|
|
|
field = ((char *) dri2_dpy + matches[j].offset);
|
|
|
|
|
if (*(const __DRIextension **) field == NULL) {
|
2016-08-25 00:16:01 +01:00
|
|
|
|
if (optional) {
|
|
|
|
|
_eglLog(_EGL_DEBUG, "did not find optional extension %s version %d",
|
|
|
|
|
matches[j].name, matches[j].version);
|
|
|
|
|
} else {
|
|
|
|
|
_eglLog(_EGL_WARNING, "did not find extension %s version %d",
|
|
|
|
|
matches[j].name, matches[j].version);
|
|
|
|
|
ret = EGL_FALSE;
|
|
|
|
|
}
|
2010-02-09 15:57:43 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-08 09:33:55 +01:00
|
|
|
|
static const __DRIextension **
|
|
|
|
|
dri2_open_driver(_EGLDisplay *disp)
|
2010-03-02 20:34:18 +00:00
|
|
|
|
{
|
2016-07-15 12:47:37 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2013-09-24 19:05:22 +01:00
|
|
|
|
const __DRIextension **extensions = NULL;
|
2010-03-02 20:34:18 +00:00
|
|
|
|
char path[PATH_MAX], *search_paths, *p, *next, *end;
|
2013-09-24 19:05:22 +01:00
|
|
|
|
char *get_extensions_name;
|
|
|
|
|
const __DRIextension **(*get_extensions)(void);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
|
|
|
|
search_paths = NULL;
|
|
|
|
|
if (geteuid() == getuid()) {
|
|
|
|
|
/* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
|
|
|
|
|
search_paths = getenv("LIBGL_DRIVERS_PATH");
|
|
|
|
|
}
|
|
|
|
|
if (search_paths == NULL)
|
|
|
|
|
search_paths = DEFAULT_DRIVER_DIR;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->driver = NULL;
|
|
|
|
|
end = search_paths + strlen(search_paths);
|
2015-06-09 20:16:19 +01:00
|
|
|
|
for (p = search_paths; p < end; p = next + 1) {
|
2010-05-20 22:44:43 +01:00
|
|
|
|
int len;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
next = strchr(p, ':');
|
|
|
|
|
if (next == NULL)
|
|
|
|
|
next = end;
|
|
|
|
|
|
2010-05-20 22:44:43 +01:00
|
|
|
|
len = next - p;
|
|
|
|
|
#if GLX_USE_TLS
|
2010-02-03 15:18:28 +00:00
|
|
|
|
snprintf(path, sizeof path,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
"%.*s/tls/%s_dri.so", len, p, dri2_dpy->driver_name);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
|
2010-05-20 22:44:43 +01:00
|
|
|
|
#endif
|
|
|
|
|
if (dri2_dpy->driver == NULL) {
|
2016-08-25 00:12:13 +01:00
|
|
|
|
snprintf(path, sizeof path,
|
|
|
|
|
"%.*s/%s_dri.so", len, p, dri2_dpy->driver_name);
|
|
|
|
|
dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
|
|
|
|
|
if (dri2_dpy->driver == NULL)
|
|
|
|
|
_eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror());
|
2010-05-20 22:44:43 +01:00
|
|
|
|
}
|
2013-12-19 05:11:00 +00:00
|
|
|
|
/* not need continue to loop all paths once the driver is found */
|
|
|
|
|
if (dri2_dpy->driver != NULL)
|
|
|
|
|
break;
|
2015-05-20 04:25:30 +01:00
|
|
|
|
|
|
|
|
|
#ifdef ANDROID
|
|
|
|
|
snprintf(path, sizeof path, "%.*s/gallium_dri.so", len, p);
|
|
|
|
|
dri2_dpy->driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
|
|
|
|
|
if (dri2_dpy->driver == NULL)
|
|
|
|
|
_eglLog(_EGL_DEBUG, "failed to open %s: %s\n", path, dlerror());
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->driver == NULL) {
|
2010-05-13 20:42:51 +01:00
|
|
|
|
_eglLog(_EGL_WARNING,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
"DRI2: failed to open %s (search paths %s)",
|
|
|
|
|
dri2_dpy->driver_name, search_paths);
|
2011-06-08 09:33:55 +01:00
|
|
|
|
return NULL;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_eglLog(_EGL_DEBUG, "DRI2: dlopen(%s)", path);
|
2013-09-24 19:05:22 +01:00
|
|
|
|
|
2016-11-09 14:50:06 +00:00
|
|
|
|
get_extensions_name = loader_get_extensions_name(dri2_dpy->driver_name);
|
|
|
|
|
if (get_extensions_name) {
|
2013-09-24 19:05:22 +01:00
|
|
|
|
get_extensions = dlsym(dri2_dpy->driver, get_extensions_name);
|
|
|
|
|
if (get_extensions) {
|
|
|
|
|
extensions = get_extensions();
|
|
|
|
|
} else {
|
|
|
|
|
_eglLog(_EGL_DEBUG, "driver does not expose %s(): %s\n",
|
|
|
|
|
get_extensions_name, dlerror());
|
|
|
|
|
}
|
|
|
|
|
free(get_extensions_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!extensions)
|
|
|
|
|
extensions = dlsym(dri2_dpy->driver, __DRI_DRIVER_EXTENSIONS);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
if (extensions == NULL) {
|
2010-05-13 20:42:51 +01:00
|
|
|
|
_eglLog(_EGL_WARNING,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
"DRI2: driver exports no extensions (%s)", dlerror());
|
2010-05-28 21:16:12 +01:00
|
|
|
|
dlclose(dri2_dpy->driver);
|
2011-06-08 09:33:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return extensions;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-21 16:44:00 +01:00
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_load_driver_dri3(_EGLDisplay *disp)
|
|
|
|
|
{
|
2016-07-15 12:47:37 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2015-07-21 16:44:00 +01:00
|
|
|
|
const __DRIextension **extensions;
|
|
|
|
|
|
|
|
|
|
extensions = dri2_open_driver(disp);
|
|
|
|
|
if (!extensions)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2016-08-25 00:16:01 +01:00
|
|
|
|
if (!dri2_bind_extensions(dri2_dpy, dri3_driver_extensions, extensions, false)) {
|
2015-07-21 16:44:00 +01:00
|
|
|
|
dlclose(dri2_dpy->driver);
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
dri2_dpy->driver_extensions = extensions;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-08 09:33:55 +01:00
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_load_driver(_EGLDisplay *disp)
|
|
|
|
|
{
|
2016-07-15 12:47:37 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2011-06-08 09:33:55 +01:00
|
|
|
|
const __DRIextension **extensions;
|
|
|
|
|
|
|
|
|
|
extensions = dri2_open_driver(disp);
|
|
|
|
|
if (!extensions)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2016-08-25 00:16:01 +01:00
|
|
|
|
if (!dri2_bind_extensions(dri2_dpy, dri2_driver_extensions, extensions, false)) {
|
2011-06-08 09:33:55 +01:00
|
|
|
|
dlclose(dri2_dpy->driver);
|
2010-05-28 21:16:12 +01:00
|
|
|
|
return EGL_FALSE;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
2013-09-27 19:39:25 +01:00
|
|
|
|
dri2_dpy->driver_extensions = extensions;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2011-06-08 09:33:55 +01:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_load_driver_swrast(_EGLDisplay *disp)
|
|
|
|
|
{
|
2016-07-15 12:47:37 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2011-06-08 09:33:55 +01:00
|
|
|
|
const __DRIextension **extensions;
|
|
|
|
|
|
|
|
|
|
extensions = dri2_open_driver(disp);
|
|
|
|
|
if (!extensions)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2016-08-25 00:16:01 +01:00
|
|
|
|
if (!dri2_bind_extensions(dri2_dpy, swrast_driver_extensions, extensions, false)) {
|
2011-06-08 09:33:55 +01:00
|
|
|
|
dlclose(dri2_dpy->driver);
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
2013-09-27 19:39:25 +01:00
|
|
|
|
dri2_dpy->driver_extensions = extensions;
|
2010-05-28 21:16:12 +01:00
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-10 13:45:58 +01:00
|
|
|
|
static unsigned
|
|
|
|
|
dri2_renderer_query_integer(struct dri2_egl_display *dri2_dpy, int param)
|
|
|
|
|
{
|
|
|
|
|
const __DRI2rendererQueryExtension *rendererQuery = dri2_dpy->rendererQuery;
|
|
|
|
|
unsigned int value = 0;
|
|
|
|
|
|
|
|
|
|
if (!rendererQuery ||
|
|
|
|
|
rendererQuery->queryInteger(dri2_dpy->dri_screen, param, &value) == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
2011-05-30 09:50:52 +01:00
|
|
|
|
void
|
|
|
|
|
dri2_setup_screen(_EGLDisplay *disp)
|
2010-05-28 21:16:12 +01:00
|
|
|
|
{
|
2011-05-30 09:50:52 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2010-05-28 21:16:12 +01:00
|
|
|
|
unsigned int api_mask;
|
|
|
|
|
|
2015-07-21 16:44:00 +01:00
|
|
|
|
if (dri2_dpy->image_driver) {
|
|
|
|
|
api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen);
|
|
|
|
|
} else if (dri2_dpy->dri2) {
|
2012-07-18 21:17:50 +01:00
|
|
|
|
api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
|
2011-02-17 04:05:15 +00:00
|
|
|
|
} else {
|
|
|
|
|
assert(dri2_dpy->swrast);
|
egl/dri2: Add plumbing for EGL_OPENGL_ES3_BIT_KHR
Fixes error EGL_BAD_ATTRIBUTE in the tests below on Intel Sandybridge:
* piglit egl-create-context-verify-gl-flavor, testcase OpenGL ES 3.0
* gles3conform, revision 19700, when runnning GL3Tests with -fbo
This plumbing is added in order to comply with the EGL_KHR_create_context
spec. According to the EGL_KHR_create_context spec, it is illegal to call
eglCreateContext(EGL_CONTEXT_MAJOR_VERSION_KHR=3) with a config whose
EGL_RENDERABLE_TYPE does not contain the EGL_OPENGL_ES3_BIT_KHR. The
pertinent
portion of the spec is quoted below; the key word is "respectively".
* If <config> is not a valid EGLConfig, or does not support the
requested client API, then an EGL_BAD_CONFIG error is generated
(this includes requesting creation of an OpenGL ES 1.x, 2.0, or
3.0 context when the EGL_RENDERABLE_TYPE attribute of <config>
does not contain EGL_OPENGL_ES_BIT, EGL_OPENGL_ES2_BIT, or
EGL_OPENGL_ES3_BIT_KHR respectively).
To create this patch, I searched for all the ES2 bit plumbing by calling
`git grep "ES2_BIT\|DRI_API_GLES2" src/egl`, and then at each location
added a case for ES3.
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-11-20 21:43:11 +00:00
|
|
|
|
api_mask = 1 << __DRI_API_OPENGL |
|
|
|
|
|
1 << __DRI_API_GLES |
|
|
|
|
|
1 << __DRI_API_GLES2 |
|
|
|
|
|
1 << __DRI_API_GLES3;
|
2011-02-17 04:05:15 +00:00
|
|
|
|
}
|
2010-06-03 03:48:06 +01:00
|
|
|
|
|
2011-01-13 08:53:13 +00:00
|
|
|
|
disp->ClientAPIs = 0;
|
2016-08-25 12:15:13 +01:00
|
|
|
|
if ((api_mask & (1 <<__DRI_API_OPENGL)) && _eglIsApiValid(EGL_OPENGL_API))
|
2011-01-13 08:53:13 +00:00
|
|
|
|
disp->ClientAPIs |= EGL_OPENGL_BIT;
|
2016-08-25 12:15:13 +01:00
|
|
|
|
if ((api_mask & (1 << __DRI_API_GLES)) && _eglIsApiValid(EGL_OPENGL_ES_API))
|
2011-01-13 08:53:13 +00:00
|
|
|
|
disp->ClientAPIs |= EGL_OPENGL_ES_BIT;
|
2016-08-25 12:15:13 +01:00
|
|
|
|
if ((api_mask & (1 << __DRI_API_GLES2)) && _eglIsApiValid(EGL_OPENGL_ES_API))
|
2011-01-13 08:53:13 +00:00
|
|
|
|
disp->ClientAPIs |= EGL_OPENGL_ES2_BIT;
|
2016-08-25 12:15:13 +01:00
|
|
|
|
if ((api_mask & (1 << __DRI_API_GLES3)) && _eglIsApiValid(EGL_OPENGL_ES_API))
|
egl/dri2: Add plumbing for EGL_OPENGL_ES3_BIT_KHR
Fixes error EGL_BAD_ATTRIBUTE in the tests below on Intel Sandybridge:
* piglit egl-create-context-verify-gl-flavor, testcase OpenGL ES 3.0
* gles3conform, revision 19700, when runnning GL3Tests with -fbo
This plumbing is added in order to comply with the EGL_KHR_create_context
spec. According to the EGL_KHR_create_context spec, it is illegal to call
eglCreateContext(EGL_CONTEXT_MAJOR_VERSION_KHR=3) with a config whose
EGL_RENDERABLE_TYPE does not contain the EGL_OPENGL_ES3_BIT_KHR. The
pertinent
portion of the spec is quoted below; the key word is "respectively".
* If <config> is not a valid EGLConfig, or does not support the
requested client API, then an EGL_BAD_CONFIG error is generated
(this includes requesting creation of an OpenGL ES 1.x, 2.0, or
3.0 context when the EGL_RENDERABLE_TYPE attribute of <config>
does not contain EGL_OPENGL_ES_BIT, EGL_OPENGL_ES2_BIT, or
EGL_OPENGL_ES3_BIT_KHR respectively).
To create this patch, I searched for all the ES2 bit plumbing by calling
`git grep "ES2_BIT\|DRI_API_GLES2" src/egl`, and then at each location
added a case for ES3.
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-11-20 21:43:11 +00:00
|
|
|
|
disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR;
|
2010-06-03 03:48:06 +01:00
|
|
|
|
|
2015-07-21 16:44:00 +01:00
|
|
|
|
assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast);
|
2016-09-09 17:25:34 +01:00
|
|
|
|
disp->Extensions.KHR_no_config_context = EGL_TRUE;
|
2012-07-18 21:17:50 +01:00
|
|
|
|
disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
|
2010-07-27 23:25:54 +01:00
|
|
|
|
|
2015-06-10 13:45:58 +01:00
|
|
|
|
if (dri2_renderer_query_integer(dri2_dpy,
|
|
|
|
|
__DRI2_RENDERER_HAS_FRAMEBUFFER_SRGB))
|
|
|
|
|
disp->Extensions.KHR_gl_colorspace = EGL_TRUE;
|
|
|
|
|
|
2015-07-21 16:44:00 +01:00
|
|
|
|
if (dri2_dpy->image_driver ||
|
|
|
|
|
(dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||
|
2015-07-21 16:43:58 +01:00
|
|
|
|
(dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) {
|
2012-07-20 00:04:01 +01:00
|
|
|
|
disp->Extensions.KHR_create_context = EGL_TRUE;
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->robustness)
|
|
|
|
|
disp->Extensions.EXT_create_context_robustness = EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-10 09:56:02 +01:00
|
|
|
|
if (dri2_dpy->fence) {
|
|
|
|
|
disp->Extensions.KHR_fence_sync = EGL_TRUE;
|
2015-04-10 11:04:18 +01:00
|
|
|
|
disp->Extensions.KHR_wait_sync = EGL_TRUE;
|
2015-04-10 12:16:30 +01:00
|
|
|
|
if (dri2_dpy->fence->get_fence_from_cl_event)
|
|
|
|
|
disp->Extensions.KHR_cl_event2 = EGL_TRUE;
|
2016-11-18 13:39:33 +00:00
|
|
|
|
if (dri2_dpy->fence->base.version >= 2) {
|
|
|
|
|
unsigned capabilities =
|
|
|
|
|
dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen);
|
|
|
|
|
disp->Extensions.ANDROID_native_fence_sync =
|
|
|
|
|
(capabilities & __DRI_FENCE_CAP_NATIVE_FD) != 0;
|
|
|
|
|
}
|
2015-04-10 09:56:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-05 01:14:10 +01:00
|
|
|
|
disp->Extensions.KHR_reusable_sync = EGL_TRUE;
|
|
|
|
|
|
2011-03-08 01:18:29 +00:00
|
|
|
|
if (dri2_dpy->image) {
|
2014-07-23 19:28:52 +01:00
|
|
|
|
if (dri2_dpy->image->base.version >= 10 &&
|
|
|
|
|
dri2_dpy->image->getCapabilities != NULL) {
|
|
|
|
|
int capabilities;
|
|
|
|
|
|
|
|
|
|
capabilities = dri2_dpy->image->getCapabilities(dri2_dpy->dri_screen);
|
|
|
|
|
disp->Extensions.MESA_drm_image = (capabilities & __DRI_IMAGE_CAP_GLOBAL_NAMES) != 0;
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->image->base.version >= 11)
|
|
|
|
|
disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
|
|
|
|
|
} else {
|
2014-07-23 19:28:52 +01:00
|
|
|
|
disp->Extensions.MESA_drm_image = EGL_TRUE;
|
2014-03-03 03:57:16 +00:00
|
|
|
|
if (dri2_dpy->image->base.version >= 11)
|
|
|
|
|
disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
|
|
|
|
|
}
|
2014-07-23 19:28:52 +01:00
|
|
|
|
|
2011-03-08 01:18:29 +00:00
|
|
|
|
disp->Extensions.KHR_image_base = EGL_TRUE;
|
|
|
|
|
disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
|
2012-11-27 13:19:54 +00:00
|
|
|
|
if (dri2_dpy->image->base.version >= 5 &&
|
|
|
|
|
dri2_dpy->image->createImageFromTexture) {
|
|
|
|
|
disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE;
|
|
|
|
|
disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE;
|
|
|
|
|
}
|
2015-06-10 13:45:58 +01:00
|
|
|
|
if (dri2_renderer_query_integer(dri2_dpy,
|
|
|
|
|
__DRI2_RENDERER_HAS_TEXTURE_3D))
|
|
|
|
|
disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE;
|
2015-01-14 19:36:04 +00:00
|
|
|
|
#ifdef HAVE_LIBDRM
|
2013-03-22 13:58:05 +00:00
|
|
|
|
if (dri2_dpy->image->base.version >= 8 &&
|
|
|
|
|
dri2_dpy->image->createImageFromDmaBufs) {
|
|
|
|
|
disp->Extensions.EXT_image_dma_buf_import = EGL_TRUE;
|
|
|
|
|
}
|
2013-11-10 18:32:01 +00:00
|
|
|
|
#endif
|
2011-03-08 01:18:29 +00:00
|
|
|
|
}
|
2011-05-30 09:50:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-05-11 16:20:04 +01:00
|
|
|
|
/* All platforms but DRM call this function to create the screen and populate
|
|
|
|
|
* the driver_configs. DRM inherits that information from its display - GBM.
|
2014-11-07 03:42:15 +00:00
|
|
|
|
*/
|
2011-05-30 09:50:52 +01:00
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_create_screen(_EGLDisplay *disp)
|
|
|
|
|
{
|
2016-07-15 12:47:37 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2011-05-30 09:50:52 +01:00
|
|
|
|
|
2015-07-21 16:44:00 +01:00
|
|
|
|
if (dri2_dpy->image_driver) {
|
|
|
|
|
dri2_dpy->dri_screen =
|
|
|
|
|
dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd,
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->loader_extensions,
|
2015-07-21 16:44:00 +01:00
|
|
|
|
dri2_dpy->driver_extensions,
|
|
|
|
|
&dri2_dpy->driver_configs,
|
|
|
|
|
disp);
|
|
|
|
|
} else if (dri2_dpy->dri2) {
|
2013-09-27 19:39:25 +01:00
|
|
|
|
if (dri2_dpy->dri2->base.version >= 4) {
|
|
|
|
|
dri2_dpy->dri_screen =
|
|
|
|
|
dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd,
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->loader_extensions,
|
2013-09-27 19:39:25 +01:00
|
|
|
|
dri2_dpy->driver_extensions,
|
|
|
|
|
&dri2_dpy->driver_configs, disp);
|
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->dri_screen =
|
|
|
|
|
dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd,
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->loader_extensions,
|
2013-09-27 19:39:25 +01:00
|
|
|
|
&dri2_dpy->driver_configs, disp);
|
|
|
|
|
}
|
2011-05-30 09:50:52 +01:00
|
|
|
|
} else {
|
|
|
|
|
assert(dri2_dpy->swrast);
|
2013-09-27 19:39:25 +01:00
|
|
|
|
if (dri2_dpy->swrast->base.version >= 4) {
|
|
|
|
|
dri2_dpy->dri_screen =
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->swrast->createNewScreen2(0, dri2_dpy->loader_extensions,
|
2013-09-27 19:39:25 +01:00
|
|
|
|
dri2_dpy->driver_extensions,
|
|
|
|
|
&dri2_dpy->driver_configs, disp);
|
|
|
|
|
} else {
|
|
|
|
|
dri2_dpy->dri_screen =
|
2016-08-24 23:32:27 +01:00
|
|
|
|
dri2_dpy->swrast->createNewScreen(0, dri2_dpy->loader_extensions,
|
2013-09-27 19:39:25 +01:00
|
|
|
|
&dri2_dpy->driver_configs, disp);
|
|
|
|
|
}
|
2011-05-30 09:50:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->dri_screen == NULL) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-27 09:23:34 +01:00
|
|
|
|
dri2_dpy->own_dri_screen = 1;
|
2017-05-11 16:20:04 +01:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_setup_extensions(_EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
const struct dri2_extension_match *mandatory_core_extensions;
|
|
|
|
|
const __DRIextension **extensions;
|
2011-06-27 09:23:34 +01:00
|
|
|
|
|
2011-05-30 09:50:52 +01:00
|
|
|
|
extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
|
2015-06-13 08:36:27 +01:00
|
|
|
|
|
2017-05-11 16:20:04 +01:00
|
|
|
|
if (dri2_dpy->image_driver || dri2_dpy->dri2)
|
|
|
|
|
mandatory_core_extensions = dri2_core_extensions;
|
|
|
|
|
else
|
|
|
|
|
mandatory_core_extensions = swrast_core_extensions;
|
2011-05-30 09:50:52 +01:00
|
|
|
|
|
2017-05-11 16:20:04 +01:00
|
|
|
|
if (!dri2_bind_extensions(dri2_dpy, mandatory_core_extensions, extensions, false))
|
|
|
|
|
return EGL_FALSE;
|
2011-03-08 01:18:29 +00:00
|
|
|
|
|
2017-05-11 16:20:04 +01:00
|
|
|
|
dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true);
|
2010-06-03 03:48:06 +01:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called via eglInitialize(), GLX_drv->API.Initialize().
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
*
|
|
|
|
|
* This must be guaranteed to be called exactly once, even if eglInitialize is
|
|
|
|
|
* called many times (without a eglTerminate in between).
|
2010-06-03 03:48:06 +01:00
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2011-01-13 08:53:13 +00:00
|
|
|
|
dri2_initialize(_EGLDriver *drv, _EGLDisplay *disp)
|
2010-06-03 03:48:06 +01:00
|
|
|
|
{
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
EGLBoolean ret = EGL_FALSE;
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
|
|
|
|
|
/* In the case where the application calls eglMakeCurrent(context1),
|
|
|
|
|
* eglTerminate, then eglInitialize again (without a call to eglReleaseThread
|
|
|
|
|
* or eglMakeCurrent(NULL) before that), dri2_dpy structure is still
|
|
|
|
|
* initialized, as we need it to be able to free context1 correctly.
|
|
|
|
|
*
|
|
|
|
|
* It would probably be safest to forcibly release the display with
|
|
|
|
|
* dri2_display_release, to make sure the display is reinitialized correctly.
|
|
|
|
|
* However, the EGL spec states that we need to keep a reference to the
|
|
|
|
|
* current context (so we cannot call dri2_make_current(NULL)), and therefore
|
|
|
|
|
* we would leak context1 as we would be missing the old display connection
|
|
|
|
|
* to free it up correctly.
|
|
|
|
|
*/
|
|
|
|
|
if (dri2_dpy) {
|
|
|
|
|
dri2_dpy->ref_count++;
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-12 20:40:38 +00:00
|
|
|
|
/* not until swrast_dri is supported */
|
|
|
|
|
if (disp->Options.UseFallback)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2016-08-03 14:54:22 +01:00
|
|
|
|
/* Nothing to initialize for a test only display */
|
|
|
|
|
if (disp->Options.TestOnly)
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
|
2010-06-03 03:48:06 +01:00
|
|
|
|
switch (disp->Platform) {
|
2015-06-12 18:10:58 +01:00
|
|
|
|
#ifdef HAVE_SURFACELESS_PLATFORM
|
|
|
|
|
case _EGL_PLATFORM_SURFACELESS:
|
2016-08-03 14:54:22 +01:00
|
|
|
|
ret = dri2_initialize_surfaceless(drv, disp);
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
break;
|
2015-06-12 18:10:58 +01:00
|
|
|
|
#endif
|
2011-05-11 18:58:37 +01:00
|
|
|
|
#ifdef HAVE_X11_PLATFORM
|
2010-06-03 03:48:06 +01:00
|
|
|
|
case _EGL_PLATFORM_X11:
|
2016-08-03 14:54:22 +01:00
|
|
|
|
ret = dri2_initialize_x11(drv, disp);
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
break;
|
2011-05-11 18:58:37 +01:00
|
|
|
|
#endif
|
2011-06-24 20:45:05 +01:00
|
|
|
|
#ifdef HAVE_DRM_PLATFORM
|
2010-06-03 03:48:06 +01:00
|
|
|
|
case _EGL_PLATFORM_DRM:
|
2016-08-03 14:54:22 +01:00
|
|
|
|
ret = dri2_initialize_drm(drv, disp);
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
break;
|
2011-06-24 20:45:05 +01:00
|
|
|
|
#endif
|
2011-02-04 11:39:40 +00:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
|
|
|
|
case _EGL_PLATFORM_WAYLAND:
|
2016-08-03 14:54:22 +01:00
|
|
|
|
ret = dri2_initialize_wayland(drv, disp);
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
break;
|
2011-02-04 11:39:40 +00:00
|
|
|
|
#endif
|
2011-08-05 06:39:18 +01:00
|
|
|
|
#ifdef HAVE_ANDROID_PLATFORM
|
|
|
|
|
case _EGL_PLATFORM_ANDROID:
|
2016-08-03 14:54:22 +01:00
|
|
|
|
ret = dri2_initialize_android(drv, disp);
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
break;
|
2010-06-03 03:48:06 +01:00
|
|
|
|
#endif
|
|
|
|
|
default:
|
2014-12-04 00:32:39 +00:00
|
|
|
|
_eglLog(_EGL_WARNING, "No EGL platform enabled.");
|
2010-06-03 03:48:06 +01:00
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
|
|
|
|
|
if (!dri2_dpy) {
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_dpy->ref_count++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
2010-06-03 03:48:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
/**
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
* Decrement display reference count, and free up display if necessary.
|
2010-02-03 15:18:28 +00:00
|
|
|
|
*/
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
static void
|
2016-08-16 11:03:33 +01:00
|
|
|
|
dri2_display_release(_EGLDisplay *disp)
|
|
|
|
|
{
|
2016-08-18 16:43:36 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2016-08-18 16:43:36 +01:00
|
|
|
|
if (!disp)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
assert(dri2_dpy->ref_count > 0);
|
|
|
|
|
dri2_dpy->ref_count--;
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->ref_count > 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
_eglCleanupDisplay(disp);
|
2017-05-11 17:13:33 +01:00
|
|
|
|
dri2_display_destroy(disp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dri2_display_destroy(_EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
unsigned i;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2011-06-27 09:23:34 +01:00
|
|
|
|
if (dri2_dpy->own_dri_screen)
|
|
|
|
|
dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
|
2015-09-10 14:41:38 +01:00
|
|
|
|
if (dri2_dpy->fd >= 0)
|
2011-02-17 04:05:15 +00:00
|
|
|
|
close(dri2_dpy->fd);
|
2011-06-27 09:23:34 +01:00
|
|
|
|
if (dri2_dpy->driver)
|
|
|
|
|
dlclose(dri2_dpy->driver);
|
2014-06-02 12:26:17 +01:00
|
|
|
|
free(dri2_dpy->driver_name);
|
2011-06-11 21:07:02 +01:00
|
|
|
|
|
2016-06-17 18:41:22 +01:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
|
|
|
|
free(dri2_dpy->device_name);
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-01-29 02:53:56 +00:00
|
|
|
|
switch (disp->Platform) {
|
2011-05-11 18:58:37 +01:00
|
|
|
|
#ifdef HAVE_X11_PLATFORM
|
2014-01-29 02:53:56 +00:00
|
|
|
|
case _EGL_PLATFORM_X11:
|
|
|
|
|
if (dri2_dpy->own_device) {
|
2011-06-11 21:07:02 +01:00
|
|
|
|
xcb_disconnect(dri2_dpy->conn);
|
2014-01-29 02:53:56 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2011-06-11 21:07:02 +01:00
|
|
|
|
#endif
|
2011-06-29 07:49:39 +01:00
|
|
|
|
#ifdef HAVE_DRM_PLATFORM
|
2014-01-29 02:53:56 +00:00
|
|
|
|
case _EGL_PLATFORM_DRM:
|
|
|
|
|
if (dri2_dpy->own_device) {
|
2017-05-09 18:47:20 +01:00
|
|
|
|
gbm_device_destroy(&dri2_dpy->gbm_dri->base);
|
2014-01-29 02:53:56 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2011-05-11 18:58:37 +01:00
|
|
|
|
#endif
|
2014-01-29 02:53:56 +00:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
|
|
|
|
case _EGL_PLATFORM_WAYLAND:
|
2015-05-01 10:11:20 +01:00
|
|
|
|
if (dri2_dpy->wl_drm)
|
|
|
|
|
wl_drm_destroy(dri2_dpy->wl_drm);
|
|
|
|
|
if (dri2_dpy->wl_shm)
|
|
|
|
|
wl_shm_destroy(dri2_dpy->wl_shm);
|
2015-04-30 23:03:32 +01:00
|
|
|
|
wl_registry_destroy(dri2_dpy->wl_registry);
|
|
|
|
|
wl_event_queue_destroy(dri2_dpy->wl_queue);
|
2017-01-13 15:05:10 +00:00
|
|
|
|
wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);
|
2014-01-29 02:53:56 +00:00
|
|
|
|
if (dri2_dpy->own_device) {
|
|
|
|
|
wl_display_disconnect(dri2_dpy->wl_dpy);
|
2011-06-11 21:07:02 +01:00
|
|
|
|
}
|
2014-01-29 02:53:56 +00:00
|
|
|
|
break;
|
|
|
|
|
#endif
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2011-06-11 21:07:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-11-07 03:33:56 +00:00
|
|
|
|
/* The drm platform does not create the screen/driver_configs but reuses
|
|
|
|
|
* the ones from the gbm device. As such the gbm itself is responsible
|
|
|
|
|
* for the cleanup.
|
|
|
|
|
*/
|
2017-05-12 10:18:32 +01:00
|
|
|
|
if (disp->Platform != _EGL_PLATFORM_DRM && dri2_dpy->driver_configs) {
|
2014-11-07 03:33:56 +00:00
|
|
|
|
for (i = 0; dri2_dpy->driver_configs[i]; i++)
|
|
|
|
|
free((__DRIconfig *) dri2_dpy->driver_configs[i]);
|
|
|
|
|
free(dri2_dpy->driver_configs);
|
|
|
|
|
}
|
2010-02-03 15:18:28 +00:00
|
|
|
|
free(dri2_dpy);
|
|
|
|
|
disp->DriverData = NULL;
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Called via eglTerminate(), drv->API.Terminate().
|
|
|
|
|
*
|
|
|
|
|
* This must be guaranteed to be called exactly once, even if eglTerminate is
|
|
|
|
|
* called many times (without a eglInitialize in between).
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
/* Release all non-current Context/Surfaces. */
|
|
|
|
|
_eglReleaseDisplayResources(drv, disp);
|
|
|
|
|
|
|
|
|
|
dri2_display_release(disp);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-09 22:06:41 +00:00
|
|
|
|
/**
|
|
|
|
|
* Set the error code after a call to
|
|
|
|
|
* dri2_egl_display::dri2::createContextAttribs.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
dri2_create_context_attribs_error(int dri_error)
|
|
|
|
|
{
|
|
|
|
|
EGLint egl_error;
|
|
|
|
|
|
|
|
|
|
switch (dri_error) {
|
|
|
|
|
case __DRI_CTX_ERROR_SUCCESS:
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case __DRI_CTX_ERROR_NO_MEMORY:
|
|
|
|
|
egl_error = EGL_BAD_ALLOC;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* From the EGL_KHR_create_context spec, section "Errors":
|
|
|
|
|
*
|
|
|
|
|
* * If <config> does not support a client API context compatible
|
|
|
|
|
* with the requested API major and minor version, [...] context flags,
|
|
|
|
|
* and context reset notification behavior (for client API types where
|
|
|
|
|
* these attributes are supported), then an EGL_BAD_MATCH error is
|
|
|
|
|
* generated.
|
|
|
|
|
*
|
|
|
|
|
* * If an OpenGL ES context is requested and the values for
|
|
|
|
|
* attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
|
|
|
|
|
* EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
|
|
|
|
|
* is not defined, than an EGL_BAD_MATCH error is generated.
|
|
|
|
|
*
|
|
|
|
|
* * If an OpenGL context is requested, the requested version is
|
|
|
|
|
* greater than 3.2, and the value for attribute
|
|
|
|
|
* EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has any
|
|
|
|
|
* bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR and
|
|
|
|
|
* EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has more than
|
|
|
|
|
* one of these bits set; or if the implementation does not support
|
|
|
|
|
* the requested profile, then an EGL_BAD_MATCH error is generated.
|
|
|
|
|
*/
|
|
|
|
|
case __DRI_CTX_ERROR_BAD_API:
|
|
|
|
|
case __DRI_CTX_ERROR_BAD_VERSION:
|
|
|
|
|
case __DRI_CTX_ERROR_BAD_FLAG:
|
|
|
|
|
egl_error = EGL_BAD_MATCH;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* From the EGL_KHR_create_context spec, section "Errors":
|
|
|
|
|
*
|
|
|
|
|
* * If an attribute name or attribute value in <attrib_list> is not
|
|
|
|
|
* recognized (including unrecognized bits in bitmask attributes),
|
|
|
|
|
* then an EGL_BAD_ATTRIBUTE error is generated."
|
|
|
|
|
*/
|
|
|
|
|
case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE:
|
|
|
|
|
case __DRI_CTX_ERROR_UNKNOWN_FLAG:
|
|
|
|
|
egl_error = EGL_BAD_ATTRIBUTE;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
egl_error = EGL_BAD_MATCH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_eglError(egl_error, "dri2_create_context");
|
|
|
|
|
}
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2015-07-21 16:43:56 +01:00
|
|
|
|
static bool
|
|
|
|
|
dri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx,
|
|
|
|
|
struct dri2_egl_display *dri2_dpy,
|
|
|
|
|
uint32_t *ctx_attribs,
|
|
|
|
|
unsigned *num_attribs)
|
|
|
|
|
{
|
|
|
|
|
int pos = 0;
|
|
|
|
|
|
|
|
|
|
assert(*num_attribs >= 8);
|
|
|
|
|
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
|
|
|
|
|
ctx_attribs[pos++] = dri2_ctx->base.ClientMajorVersion;
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
|
|
|
|
|
ctx_attribs[pos++] = dri2_ctx->base.ClientMinorVersion;
|
|
|
|
|
|
|
|
|
|
if (dri2_ctx->base.Flags != 0) {
|
|
|
|
|
/* If the implementation doesn't support the __DRI2_ROBUSTNESS
|
|
|
|
|
* extension, don't even try to send it the robust-access flag.
|
|
|
|
|
* It may explode. Instead, generate the required EGL error here.
|
|
|
|
|
*/
|
|
|
|
|
if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0
|
|
|
|
|
&& !dri2_dpy->robustness) {
|
|
|
|
|
_eglError(EGL_BAD_MATCH, "eglCreateContext");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_ATTRIB_FLAGS;
|
|
|
|
|
ctx_attribs[pos++] = dri2_ctx->base.Flags;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) {
|
|
|
|
|
/* If the implementation doesn't support the __DRI2_ROBUSTNESS
|
|
|
|
|
* extension, don't even try to send it a reset strategy. It may
|
|
|
|
|
* explode. Instead, generate the required EGL error here.
|
|
|
|
|
*/
|
|
|
|
|
if (!dri2_dpy->robustness) {
|
|
|
|
|
_eglError(EGL_BAD_CONFIG, "eglCreateContext");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_RESET_LOSE_CONTEXT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*num_attribs = pos;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglCreateContext(), drv->API.CreateContext().
|
|
|
|
|
*/
|
|
|
|
|
static _EGLContext *
|
|
|
|
|
dri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
_EGLContext *share_list, const EGLint *attrib_list)
|
2010-02-03 15:18:28 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_context *dri2_ctx;
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
|
2012-07-18 22:37:28 +01:00
|
|
|
|
__DRIcontext *shared =
|
|
|
|
|
dri2_ctx_shared ? dri2_ctx_shared->dri_context : NULL;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
|
2010-07-27 23:25:54 +01:00
|
|
|
|
const __DRIconfig *dri_config;
|
2010-04-27 16:38:46 +01:00
|
|
|
|
int api;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) drv;
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
dri2_ctx = malloc(sizeof *dri2_ctx);
|
|
|
|
|
if (!dri2_ctx) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "eglCreateContext");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-05 15:49:33 +00:00
|
|
|
|
if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
|
|
|
|
|
goto cleanup;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2017-03-01 01:20:52 +00:00
|
|
|
|
/* The EGL_EXT_create_context_robustness spec says:
|
|
|
|
|
*
|
|
|
|
|
* "Add to the eglCreateContext context creation errors: [...]
|
|
|
|
|
*
|
|
|
|
|
* * If the reset notification behavior of <share_context> and the
|
|
|
|
|
* newly created context are different then an EGL_BAD_MATCH error is
|
|
|
|
|
* generated."
|
|
|
|
|
*/
|
|
|
|
|
if (share_list && share_list->ResetNotificationStrategy !=
|
|
|
|
|
dri2_ctx->base.ResetNotificationStrategy) {
|
|
|
|
|
_eglError(EGL_BAD_MATCH, "eglCreateContext");
|
|
|
|
|
goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-27 16:38:46 +01:00
|
|
|
|
switch (dri2_ctx->base.ClientAPI) {
|
|
|
|
|
case EGL_OPENGL_ES_API:
|
2012-07-18 23:59:15 +01:00
|
|
|
|
switch (dri2_ctx->base.ClientMajorVersion) {
|
2010-04-27 16:38:46 +01:00
|
|
|
|
case 1:
|
|
|
|
|
api = __DRI_API_GLES;
|
|
|
|
|
break;
|
|
|
|
|
case 2:
|
2013-01-15 22:17:46 +00:00
|
|
|
|
api = __DRI_API_GLES2;
|
egl/dri2: Add plumbing for EGL_OPENGL_ES3_BIT_KHR
Fixes error EGL_BAD_ATTRIBUTE in the tests below on Intel Sandybridge:
* piglit egl-create-context-verify-gl-flavor, testcase OpenGL ES 3.0
* gles3conform, revision 19700, when runnning GL3Tests with -fbo
This plumbing is added in order to comply with the EGL_KHR_create_context
spec. According to the EGL_KHR_create_context spec, it is illegal to call
eglCreateContext(EGL_CONTEXT_MAJOR_VERSION_KHR=3) with a config whose
EGL_RENDERABLE_TYPE does not contain the EGL_OPENGL_ES3_BIT_KHR. The
pertinent
portion of the spec is quoted below; the key word is "respectively".
* If <config> is not a valid EGLConfig, or does not support the
requested client API, then an EGL_BAD_CONFIG error is generated
(this includes requesting creation of an OpenGL ES 1.x, 2.0, or
3.0 context when the EGL_RENDERABLE_TYPE attribute of <config>
does not contain EGL_OPENGL_ES_BIT, EGL_OPENGL_ES2_BIT, or
EGL_OPENGL_ES3_BIT_KHR respectively).
To create this patch, I searched for all the ES2 bit plumbing by calling
`git grep "ES2_BIT\|DRI_API_GLES2" src/egl`, and then at each location
added a case for ES3.
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-11-20 21:43:11 +00:00
|
|
|
|
break;
|
2012-07-20 00:12:13 +01:00
|
|
|
|
case 3:
|
egl/dri2: Add plumbing for EGL_OPENGL_ES3_BIT_KHR
Fixes error EGL_BAD_ATTRIBUTE in the tests below on Intel Sandybridge:
* piglit egl-create-context-verify-gl-flavor, testcase OpenGL ES 3.0
* gles3conform, revision 19700, when runnning GL3Tests with -fbo
This plumbing is added in order to comply with the EGL_KHR_create_context
spec. According to the EGL_KHR_create_context spec, it is illegal to call
eglCreateContext(EGL_CONTEXT_MAJOR_VERSION_KHR=3) with a config whose
EGL_RENDERABLE_TYPE does not contain the EGL_OPENGL_ES3_BIT_KHR. The
pertinent
portion of the spec is quoted below; the key word is "respectively".
* If <config> is not a valid EGLConfig, or does not support the
requested client API, then an EGL_BAD_CONFIG error is generated
(this includes requesting creation of an OpenGL ES 1.x, 2.0, or
3.0 context when the EGL_RENDERABLE_TYPE attribute of <config>
does not contain EGL_OPENGL_ES_BIT, EGL_OPENGL_ES2_BIT, or
EGL_OPENGL_ES3_BIT_KHR respectively).
To create this patch, I searched for all the ES2 bit plumbing by calling
`git grep "ES2_BIT\|DRI_API_GLES2" src/egl`, and then at each location
added a case for ES3.
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
2012-11-20 21:43:11 +00:00
|
|
|
|
api = __DRI_API_GLES3;
|
2010-04-27 16:38:46 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2014-05-08 16:49:45 +01:00
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "eglCreateContext");
|
|
|
|
|
free(dri2_ctx);
|
|
|
|
|
return NULL;
|
2010-04-27 16:38:46 +01:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case EGL_OPENGL_API:
|
2012-07-20 00:04:01 +01:00
|
|
|
|
if ((dri2_ctx->base.ClientMajorVersion >= 4
|
|
|
|
|
|| (dri2_ctx->base.ClientMajorVersion == 3
|
|
|
|
|
&& dri2_ctx->base.ClientMinorVersion >= 2))
|
|
|
|
|
&& dri2_ctx->base.Profile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR)
|
|
|
|
|
api = __DRI_API_OPENGL_CORE;
|
|
|
|
|
else
|
|
|
|
|
api = __DRI_API_OPENGL;
|
2010-04-27 16:38:46 +01:00
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "eglCreateContext");
|
2013-02-01 07:41:14 +00:00
|
|
|
|
free(dri2_ctx);
|
2010-04-27 16:38:46 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-09 14:30:20 +00:00
|
|
|
|
if (conf != NULL) {
|
|
|
|
|
/* The config chosen here isn't necessarily
|
|
|
|
|
* used for surfaces later.
|
|
|
|
|
* A pixmap surface will use the single config.
|
|
|
|
|
* This opportunity depends on disabling the
|
|
|
|
|
* doubleBufferMode check in
|
|
|
|
|
* src/mesa/main/context.c:check_compatible()
|
|
|
|
|
*/
|
2015-10-07 19:43:58 +01:00
|
|
|
|
if (dri2_config->dri_double_config[0])
|
|
|
|
|
dri_config = dri2_config->dri_double_config[0];
|
2011-02-09 14:30:20 +00:00
|
|
|
|
else
|
2015-10-07 19:43:58 +01:00
|
|
|
|
dri_config = dri2_config->dri_single_config[0];
|
2011-08-26 18:42:16 +01:00
|
|
|
|
|
|
|
|
|
/* EGL_WINDOW_BIT is set only when there is a dri_double_config. This
|
|
|
|
|
* makes sure the back buffer will always be used.
|
|
|
|
|
*/
|
|
|
|
|
if (conf->SurfaceType & EGL_WINDOW_BIT)
|
|
|
|
|
dri2_ctx->base.WindowRenderBuffer = EGL_BACK_BUFFER;
|
2011-02-09 14:30:20 +00:00
|
|
|
|
}
|
2010-07-27 23:25:54 +01:00
|
|
|
|
else
|
|
|
|
|
dri_config = NULL;
|
|
|
|
|
|
2015-07-21 16:44:00 +01:00
|
|
|
|
if (dri2_dpy->image_driver) {
|
|
|
|
|
unsigned error;
|
|
|
|
|
unsigned num_attribs = 8;
|
|
|
|
|
uint32_t ctx_attribs[8];
|
|
|
|
|
|
|
|
|
|
if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,
|
|
|
|
|
&num_attribs))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
dri2_ctx->dri_context =
|
|
|
|
|
dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen,
|
|
|
|
|
api,
|
|
|
|
|
dri_config,
|
|
|
|
|
shared,
|
|
|
|
|
num_attribs / 2,
|
|
|
|
|
ctx_attribs,
|
|
|
|
|
& error,
|
|
|
|
|
dri2_ctx);
|
|
|
|
|
dri2_create_context_attribs_error(error);
|
|
|
|
|
} else if (dri2_dpy->dri2) {
|
2012-07-18 22:41:28 +01:00
|
|
|
|
if (dri2_dpy->dri2->base.version >= 3) {
|
|
|
|
|
unsigned error;
|
2015-07-21 16:43:56 +01:00
|
|
|
|
unsigned num_attribs = 8;
|
2012-07-20 00:04:01 +01:00
|
|
|
|
uint32_t ctx_attribs[8];
|
|
|
|
|
|
2015-07-21 16:43:56 +01:00
|
|
|
|
if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,
|
|
|
|
|
&num_attribs))
|
|
|
|
|
goto cleanup;
|
2012-07-18 22:41:28 +01:00
|
|
|
|
|
2016-08-25 00:12:13 +01:00
|
|
|
|
dri2_ctx->dri_context =
|
|
|
|
|
dri2_dpy->dri2->createContextAttribs(dri2_dpy->dri_screen,
|
2012-07-18 22:41:28 +01:00
|
|
|
|
api,
|
|
|
|
|
dri_config,
|
|
|
|
|
shared,
|
2012-07-20 00:04:01 +01:00
|
|
|
|
num_attribs / 2,
|
2012-07-18 22:41:28 +01:00
|
|
|
|
ctx_attribs,
|
|
|
|
|
& error,
|
|
|
|
|
dri2_ctx);
|
2016-08-25 00:12:13 +01:00
|
|
|
|
dri2_create_context_attribs_error(error);
|
2012-07-18 22:41:28 +01:00
|
|
|
|
} else {
|
2016-08-25 00:12:13 +01:00
|
|
|
|
dri2_ctx->dri_context =
|
|
|
|
|
dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
|
|
|
|
|
api,
|
|
|
|
|
dri_config,
|
2012-07-18 22:37:28 +01:00
|
|
|
|
shared,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
dri2_ctx);
|
2011-02-17 04:05:15 +00:00
|
|
|
|
}
|
2010-04-27 16:38:46 +01:00
|
|
|
|
} else {
|
2011-02-17 04:05:15 +00:00
|
|
|
|
assert(dri2_dpy->swrast);
|
2015-07-21 16:43:57 +01:00
|
|
|
|
if (dri2_dpy->swrast->base.version >= 3) {
|
|
|
|
|
unsigned error;
|
|
|
|
|
unsigned num_attribs = 8;
|
|
|
|
|
uint32_t ctx_attribs[8];
|
|
|
|
|
|
|
|
|
|
if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,
|
|
|
|
|
&num_attribs))
|
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
|
|
dri2_ctx->dri_context =
|
|
|
|
|
dri2_dpy->swrast->createContextAttribs(dri2_dpy->dri_screen,
|
|
|
|
|
api,
|
|
|
|
|
dri_config,
|
|
|
|
|
shared,
|
|
|
|
|
num_attribs / 2,
|
|
|
|
|
ctx_attribs,
|
|
|
|
|
& error,
|
|
|
|
|
dri2_ctx);
|
|
|
|
|
dri2_create_context_attribs_error(error);
|
|
|
|
|
} else {
|
|
|
|
|
dri2_ctx->dri_context =
|
|
|
|
|
dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen,
|
|
|
|
|
api,
|
|
|
|
|
dri_config,
|
|
|
|
|
shared,
|
|
|
|
|
dri2_ctx);
|
|
|
|
|
}
|
2010-04-27 16:38:46 +01:00
|
|
|
|
}
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2010-02-05 15:49:33 +00:00
|
|
|
|
if (!dri2_ctx->dri_context)
|
|
|
|
|
goto cleanup;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
|
|
|
|
return &dri2_ctx->base;
|
2010-02-05 15:49:33 +00:00
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
free(dri2_ctx);
|
|
|
|
|
return NULL;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-08-14 08:14:17 +01:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglDestroyContext(), drv->API.DestroyContext().
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_destroy_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
|
|
|
|
|
if (_eglPutContext(ctx)) {
|
|
|
|
|
dri2_dpy->core->destroyContext(dri2_ctx->dri_context);
|
|
|
|
|
free(dri2_ctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-18 16:33:39 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
|
|
|
|
|
if (!_eglPutSurface(surf))
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
|
|
|
|
|
return dri2_dpy->vtbl->destroy_surface(drv, dpy, surf);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* Called via eglMakeCurrent(), drv->API.MakeCurrent().
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
_EGLSurface *rsurf, _EGLContext *ctx)
|
2010-02-03 15:18:28 +00:00
|
|
|
|
{
|
2010-04-06 12:52:39 +01:00
|
|
|
|
struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
2010-10-23 05:52:26 +01:00
|
|
|
|
_EGLContext *old_ctx;
|
|
|
|
|
_EGLSurface *old_dsurf, *old_rsurf;
|
2015-07-21 16:43:59 +01:00
|
|
|
|
_EGLSurface *tmp_dsurf, *tmp_rsurf;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
__DRIdrawable *ddraw, *rdraw;
|
|
|
|
|
__DRIcontext *cctx;
|
2016-10-14 16:07:33 +01:00
|
|
|
|
EGLBoolean unbind;
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
|
|
|
|
|
if (!dri2_dpy)
|
|
|
|
|
return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent");
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2010-10-23 05:52:26 +01:00
|
|
|
|
/* make new bindings */
|
2016-07-15 09:24:20 +01:00
|
|
|
|
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) {
|
|
|
|
|
/* _eglBindContext already sets the EGL error (in _eglCheckMakeCurrent) */
|
2010-02-03 15:18:28 +00:00
|
|
|
|
return EGL_FALSE;
|
2016-07-15 09:24:20 +01:00
|
|
|
|
}
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2016-10-14 16:07:33 +01:00
|
|
|
|
/* flush before context switch */
|
|
|
|
|
if (old_ctx)
|
|
|
|
|
dri2_drv->glFlush();
|
|
|
|
|
|
2015-07-21 16:43:59 +01:00
|
|
|
|
ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL;
|
|
|
|
|
rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
|
|
|
|
|
|
2011-02-09 20:19:45 +00:00
|
|
|
|
if (old_ctx) {
|
|
|
|
|
__DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
|
2016-08-16 13:47:25 +01:00
|
|
|
|
dri2_dpy->core->unbindContext(old_cctx);
|
|
|
|
|
}
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2016-10-14 16:07:33 +01:00
|
|
|
|
unbind = (cctx == NULL && ddraw == NULL && rdraw == NULL);
|
egl/dri2: Add reference count for dri2_egl_display
android.opengl.cts.WrapperTest#testGetIntegerv1 CTS test calls
eglTerminate, followed by eglReleaseThread. A similar case is
observed in this bug: https://bugs.freedesktop.org/show_bug.cgi?id=69622,
where the test calls eglTerminate, then eglMakeCurrent(dpy, NULL, NULL, NULL).
With the current code, dri2_dpy structure is freed on eglTerminate
call, so the display is not initialized when eglReleaseThread calls
MakeCurrent with NULL parameters, to unbind the context, which
causes a a segfault in drv->API.MakeCurrent (dri2_make_current),
either in glFlush or in a latter call.
eglTerminate specifies that "If contexts or surfaces associated
with display is current to any thread, they are not released until
they are no longer current as a result of eglMakeCurrent."
However, to properly free the current context/surface (i.e., call
glFlush, unbindContext, driDestroyContext), we still need the
display vtbl (and possibly an active dri dpy connection). Therefore,
we add some reference counter to dri2_egl_display, to make sure
the structure is kept allocated as long as it is required.
One drawback of this is that eglInitialize may not completely reinitialize
the display (if eglTerminate was called with a current context), however,
this seems to meet the EGL spec quite well, and does not permanently
leak any context/display even for incorrectly written apps.
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
Signed-off-by: Nicolas Boichat <drinkcat@chromium.org>
Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
2016-07-22 04:27:41 +01:00
|
|
|
|
|
2016-10-14 16:07:33 +01:00
|
|
|
|
if (unbind || dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
|
|
|
|
|
dri2_destroy_surface(drv, disp, old_dsurf);
|
|
|
|
|
dri2_destroy_surface(drv, disp, old_rsurf);
|
2016-08-16 13:47:25 +01:00
|
|
|
|
|
2016-10-14 16:07:33 +01:00
|
|
|
|
if (!unbind)
|
|
|
|
|
dri2_dpy->ref_count++;
|
|
|
|
|
if (old_ctx) {
|
|
|
|
|
EGLDisplay old_disp = _eglGetDisplayHandle(old_ctx->Resource.Display);
|
|
|
|
|
dri2_destroy_context(drv, disp, old_ctx);
|
|
|
|
|
dri2_display_release(old_disp);
|
|
|
|
|
}
|
2016-08-16 13:47:25 +01:00
|
|
|
|
|
2016-10-14 16:07:33 +01:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
} else {
|
|
|
|
|
/* undo the previous _eglBindContext */
|
|
|
|
|
_eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf);
|
|
|
|
|
assert(&dri2_ctx->base == ctx &&
|
|
|
|
|
tmp_dsurf == dsurf &&
|
|
|
|
|
tmp_rsurf == rsurf);
|
|
|
|
|
|
|
|
|
|
_eglPutSurface(dsurf);
|
|
|
|
|
_eglPutSurface(rsurf);
|
|
|
|
|
_eglPutContext(ctx);
|
|
|
|
|
|
|
|
|
|
_eglPutSurface(old_dsurf);
|
|
|
|
|
_eglPutSurface(old_rsurf);
|
|
|
|
|
_eglPutContext(old_ctx);
|
|
|
|
|
|
|
|
|
|
/* dri2_dpy->core->bindContext failed. We cannot tell for sure why, but
|
|
|
|
|
* setting the error to EGL_BAD_MATCH is surely better than leaving it
|
|
|
|
|
* as EGL_SUCCESS.
|
|
|
|
|
*/
|
|
|
|
|
return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
|
|
|
|
|
}
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-21 16:43:59 +01:00
|
|
|
|
__DRIdrawable *
|
|
|
|
|
dri2_surface_get_dri_drawable(_EGLSurface *surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
|
|
|
|
|
|
|
|
|
|
return dri2_surf->dri_drawable;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Called from eglGetProcAddress() via drv->API.GetProcAddress().
|
|
|
|
|
*/
|
|
|
|
|
static _EGLProc
|
|
|
|
|
dri2_get_proc_address(_EGLDriver *drv, const char *procname)
|
|
|
|
|
{
|
2011-01-07 07:02:41 +00:00
|
|
|
|
struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2011-01-07 07:02:41 +00:00
|
|
|
|
return dri2_drv->get_proc_address(procname);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:39:09 +00:00
|
|
|
|
static _EGLSurface*
|
|
|
|
|
dri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *dpy,
|
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-29 00:39:09 +00:00
|
|
|
|
const EGLint *attrib_list)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
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
|
|
|
|
return dri2_dpy->vtbl->create_window_surface(drv, dpy, conf, native_window,
|
2014-01-29 00:39:09 +00:00
|
|
|
|
attrib_list);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:45:07 +00:00
|
|
|
|
static _EGLSurface*
|
|
|
|
|
dri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *dpy,
|
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_pixmap,
|
2014-01-29 00:45:07 +00:00
|
|
|
|
const EGLint *attrib_list)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
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
|
|
|
|
return dri2_dpy->vtbl->create_pixmap_surface(drv, dpy, conf, native_pixmap,
|
2014-01-29 00:45:07 +00:00
|
|
|
|
attrib_list);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static _EGLSurface*
|
|
|
|
|
dri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
|
|
|
_EGLConfig *conf, const EGLint *attrib_list)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->create_pbuffer_surface(drv, dpy, conf, attrib_list);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-28 20:34:19 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_swap_interval(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
|
|
|
|
EGLint interval)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->swap_interval(drv, dpy, surf, interval);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-21 19:51:33 +00:00
|
|
|
|
/**
|
|
|
|
|
* Asks the client API to flush any rendering to the drawable so that we can
|
|
|
|
|
* do our swapbuffers.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
dri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2015-07-21 16:43:59 +01:00
|
|
|
|
__DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(draw);
|
2014-12-21 19:51:33 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->flush) {
|
|
|
|
|
if (dri2_dpy->flush->base.version >= 4) {
|
|
|
|
|
/* We know there's a current context because:
|
|
|
|
|
*
|
|
|
|
|
* "If surface is not bound to the calling thread’s current
|
|
|
|
|
* context, an EGL_BAD_SURFACE error is generated."
|
|
|
|
|
*/
|
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
|
|
|
|
|
/* From the EGL 1.4 spec (page 52):
|
|
|
|
|
*
|
|
|
|
|
* "The contents of ancillary buffers are always undefined
|
|
|
|
|
* after calling eglSwapBuffers."
|
|
|
|
|
*/
|
|
|
|
|
dri2_dpy->flush->flush_with_flags(dri2_ctx->dri_context,
|
2015-07-21 16:43:59 +01:00
|
|
|
|
dri_drawable,
|
2014-12-21 19:51:33 +00:00
|
|
|
|
__DRI2_FLUSH_DRAWABLE |
|
|
|
|
|
__DRI2_FLUSH_INVALIDATE_ANCILLARY,
|
|
|
|
|
__DRI2_THROTTLE_SWAPBUFFER);
|
|
|
|
|
} else {
|
2015-07-21 16:43:59 +01:00
|
|
|
|
dri2_dpy->flush->flush(dri_drawable);
|
2014-12-21 19:51:33 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:21:21 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->swap_buffers(drv, dpy, surf);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:26:44 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_swap_buffers_with_damage(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
|
|
|
_EGLSurface *surf,
|
|
|
|
|
const EGLint *rects, EGLint n_rects)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->swap_buffers_with_damage(drv, dpy, surf,
|
|
|
|
|
rects, n_rects);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
|
|
|
|
EGLint numRects, const EGLint *rects)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->swap_buffers_region(drv, dpy, surf, numRects, rects);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
|
|
|
|
EGLint x, EGLint y, EGLint width, EGLint height)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->post_sub_buffer(drv, dpy, surf, x, y, width, height);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
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
|
|
|
|
void *native_pixmap_target)
|
2014-01-29 01:03:03 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
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
|
|
|
|
return dri2_dpy->vtbl->copy_buffers(drv, dpy, surf, native_pixmap_target);
|
2014-01-29 01:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLint
|
|
|
|
|
dri2_query_buffer_age(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->query_buffer_age(drv, dpy, surf);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
static EGLBoolean
|
2010-02-05 02:49:44 +00:00
|
|
|
|
dri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
|
2010-02-03 15:18:28 +00:00
|
|
|
|
{
|
2010-02-05 02:49:44 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2015-07-21 16:43:59 +01:00
|
|
|
|
_EGLSurface *surf = ctx->DrawSurface;
|
|
|
|
|
__DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
|
2010-02-05 02:49:44 +00:00
|
|
|
|
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) drv;
|
|
|
|
|
|
2010-02-05 02:49:44 +00:00
|
|
|
|
/* FIXME: If EGL allows frontbuffer rendering for window surfaces,
|
|
|
|
|
* we need to copy fake to real here.*/
|
|
|
|
|
|
2013-02-05 13:43:01 +00:00
|
|
|
|
if (dri2_dpy->flush != NULL)
|
2015-07-21 16:43:59 +01:00
|
|
|
|
dri2_dpy->flush->flush(dri_drawable);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
2010-02-05 02:49:44 +00:00
|
|
|
|
dri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine)
|
2010-02-03 15:18:28 +00:00
|
|
|
|
{
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) drv;
|
|
|
|
|
(void) disp;
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
if (engine != EGL_CORE_NATIVE_ENGINE)
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
|
|
|
|
|
/* glXWaitX(); */
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-09 20:49:28 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_bind_tex_image(_EGLDriver *drv,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
_EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
|
2010-02-09 20:49:28 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx;
|
|
|
|
|
_EGLContext *ctx;
|
|
|
|
|
GLint format, target;
|
2015-07-21 16:43:59 +01:00
|
|
|
|
__DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
|
2010-02-09 20:49:28 +00:00
|
|
|
|
|
|
|
|
|
ctx = _eglGetCurrentContext();
|
|
|
|
|
dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
|
2010-05-07 03:40:25 +01:00
|
|
|
|
if (!_eglBindTexImage(drv, disp, surf, buffer))
|
2010-02-09 20:49:28 +00:00
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2015-07-21 16:43:59 +01:00
|
|
|
|
switch (surf->TextureFormat) {
|
2010-02-09 20:49:28 +00:00
|
|
|
|
case EGL_TEXTURE_RGB:
|
|
|
|
|
format = __DRI_TEXTURE_FORMAT_RGB;
|
|
|
|
|
break;
|
|
|
|
|
case EGL_TEXTURE_RGBA:
|
|
|
|
|
format = __DRI_TEXTURE_FORMAT_RGBA;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2015-05-29 23:01:37 +01:00
|
|
|
|
assert(!"Unexpected texture format in dri2_bind_tex_image()");
|
|
|
|
|
format = __DRI_TEXTURE_FORMAT_RGBA;
|
2010-02-09 20:49:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-07-21 16:43:59 +01:00
|
|
|
|
switch (surf->TextureTarget) {
|
2010-02-09 20:49:28 +00:00
|
|
|
|
case EGL_TEXTURE_2D:
|
|
|
|
|
target = GL_TEXTURE_2D;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2015-05-29 23:01:37 +01:00
|
|
|
|
target = GL_TEXTURE_2D;
|
|
|
|
|
assert(!"Unexpected texture target in dri2_bind_tex_image()");
|
2010-02-09 20:49:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-11-25 05:27:02 +00:00
|
|
|
|
dri2_dpy->tex_buffer->setTexBuffer2(dri2_ctx->dri_context,
|
|
|
|
|
target, format,
|
|
|
|
|
dri_drawable);
|
2010-02-09 20:49:28 +00:00
|
|
|
|
|
2010-05-07 03:40:25 +01:00
|
|
|
|
return EGL_TRUE;
|
2010-02-09 20:49:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_release_tex_image(_EGLDriver *drv,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
_EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
|
2010-02-09 20:49:28 +00:00
|
|
|
|
{
|
2011-01-09 17:03:02 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx;
|
|
|
|
|
_EGLContext *ctx;
|
|
|
|
|
GLint target;
|
2015-07-21 16:43:59 +01:00
|
|
|
|
__DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
|
2011-01-09 17:03:02 +00:00
|
|
|
|
|
|
|
|
|
ctx = _eglGetCurrentContext();
|
|
|
|
|
dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
|
|
|
|
|
if (!_eglReleaseTexImage(drv, disp, surf, buffer))
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2015-07-21 16:43:59 +01:00
|
|
|
|
switch (surf->TextureTarget) {
|
2011-01-09 17:03:02 +00:00
|
|
|
|
case EGL_TEXTURE_2D:
|
|
|
|
|
target = GL_TEXTURE_2D;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
}
|
2014-02-18 03:04:03 +00:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->tex_buffer->base.version >= 3 &&
|
|
|
|
|
dri2_dpy->tex_buffer->releaseTexBuffer != NULL) {
|
2015-11-25 05:27:02 +00:00
|
|
|
|
dri2_dpy->tex_buffer->releaseTexBuffer(dri2_ctx->dri_context,
|
|
|
|
|
target, dri_drawable);
|
2014-02-18 03:04:03 +00:00
|
|
|
|
}
|
2010-09-23 17:39:42 +01:00
|
|
|
|
|
2010-02-09 20:49:28 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static _EGLImage*
|
|
|
|
|
dri2_create_image(_EGLDriver *drv, _EGLDisplay *dpy, _EGLContext *ctx,
|
|
|
|
|
EGLenum target, EGLClientBuffer buffer,
|
|
|
|
|
const EGLint *attr_list)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->create_image(drv, dpy, ctx, target, buffer,
|
|
|
|
|
attr_list);
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-26 19:51:11 +00:00
|
|
|
|
static _EGLImage *
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_create_image_from_dri(_EGLDisplay *disp, __DRIimage *dri_image)
|
2010-02-26 19:51:11 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_image *dri2_img;
|
|
|
|
|
|
2012-07-05 05:39:25 +01:00
|
|
|
|
if (dri_image == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_image");
|
|
|
|
|
return NULL;
|
2010-02-12 00:28:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-02-26 19:51:11 +00:00
|
|
|
|
dri2_img = malloc(sizeof *dri2_img);
|
|
|
|
|
if (!dri2_img) {
|
2012-07-05 05:39:25 +01:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_image");
|
|
|
|
|
return NULL;
|
2010-02-26 19:51:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-07-06 15:10:20 +01:00
|
|
|
|
if (!_eglInitImage(&dri2_img->base, disp)) {
|
|
|
|
|
free(dri2_img);
|
2012-07-05 05:39:25 +01:00
|
|
|
|
return NULL;
|
2011-07-06 15:10:20 +01:00
|
|
|
|
}
|
2010-02-26 19:51:11 +00:00
|
|
|
|
|
2012-07-05 05:39:25 +01:00
|
|
|
|
dri2_img->dri_image = dri_image;
|
2010-02-12 00:28:26 +00:00
|
|
|
|
|
|
|
|
|
return &dri2_img->base;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-04 02:36:40 +01:00
|
|
|
|
static _EGLImage *
|
2012-07-05 05:39:25 +01:00
|
|
|
|
dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
EGLClientBuffer buffer,
|
|
|
|
|
const EGLint *attr_list)
|
2010-06-04 02:36:40 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2012-07-05 05:39:25 +01:00
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
GLuint renderbuffer = (GLuint) (uintptr_t) buffer;
|
|
|
|
|
__DRIimage *dri_image;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
2012-07-05 05:39:25 +01:00
|
|
|
|
if (renderbuffer == 0) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-05 05:39:25 +01:00
|
|
|
|
dri_image =
|
|
|
|
|
dri2_dpy->image->createImageFromRenderbuffer(dri2_ctx->dri_context,
|
|
|
|
|
renderbuffer, NULL);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
return dri2_create_image_from_dri(disp, dri_image);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2012-01-10 22:16:26 +00:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
2012-07-05 21:43:04 +01:00
|
|
|
|
|
|
|
|
|
/* This structure describes how a wl_buffer maps to one or more
|
|
|
|
|
* __DRIimages. A wl_drm_buffer stores the wl_drm format code and the
|
|
|
|
|
* offsets and strides of the planes in the buffer. This table maps a
|
|
|
|
|
* wl_drm format code to a description of the planes in the buffer
|
|
|
|
|
* that lets us create a __DRIimage for each of the planes. */
|
|
|
|
|
|
2012-08-31 18:48:26 +01:00
|
|
|
|
static const struct wl_drm_components_descriptor {
|
|
|
|
|
uint32_t dri_components;
|
2012-07-05 21:43:04 +01:00
|
|
|
|
EGLint components;
|
|
|
|
|
int nplanes;
|
2012-08-31 18:48:26 +01:00
|
|
|
|
} wl_drm_components[] = {
|
|
|
|
|
{ __DRI_IMAGE_COMPONENTS_RGB, EGL_TEXTURE_RGB, 1 },
|
|
|
|
|
{ __DRI_IMAGE_COMPONENTS_RGBA, EGL_TEXTURE_RGBA, 1 },
|
|
|
|
|
{ __DRI_IMAGE_COMPONENTS_Y_U_V, EGL_TEXTURE_Y_U_V_WL, 3 },
|
|
|
|
|
{ __DRI_IMAGE_COMPONENTS_Y_UV, EGL_TEXTURE_Y_UV_WL, 2 },
|
|
|
|
|
{ __DRI_IMAGE_COMPONENTS_Y_XUXV, EGL_TEXTURE_Y_XUXV_WL, 2 },
|
2012-07-05 21:43:04 +01:00
|
|
|
|
};
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
static _EGLImage *
|
|
|
|
|
dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
EGLClientBuffer _buffer,
|
|
|
|
|
const EGLint *attr_list)
|
2011-02-21 15:22:34 +00:00
|
|
|
|
{
|
2013-07-18 13:11:25 +01:00
|
|
|
|
struct wl_drm_buffer *buffer;
|
2012-01-10 22:16:26 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2012-08-31 18:48:26 +01:00
|
|
|
|
const struct wl_drm_components_descriptor *f;
|
2012-07-05 21:43:04 +01:00
|
|
|
|
__DRIimage *dri_image;
|
|
|
|
|
_EGLImageAttribs attrs;
|
|
|
|
|
EGLint err;
|
2012-08-31 18:48:26 +01:00
|
|
|
|
int32_t plane;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2013-09-26 20:25:11 +01:00
|
|
|
|
buffer = wayland_drm_buffer_get(dri2_dpy->wl_server_drm,
|
|
|
|
|
(struct wl_resource *) _buffer);
|
2013-07-18 13:11:25 +01:00
|
|
|
|
if (!buffer)
|
2011-04-30 10:17:01 +01:00
|
|
|
|
return NULL;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2012-07-05 21:43:04 +01:00
|
|
|
|
err = _eglParseImageAttribList(&attrs, disp, attr_list);
|
|
|
|
|
plane = attrs.PlaneWL;
|
|
|
|
|
if (err != EGL_SUCCESS) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f = buffer->driver_format;
|
|
|
|
|
if (plane < 0 || plane >= f->nplanes) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER,
|
|
|
|
|
"dri2_create_image_wayland_wl_buffer (plane out of bounds)");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-31 18:48:26 +01:00
|
|
|
|
dri_image = dri2_dpy->image->fromPlanar(buffer->driver_buffer, plane, NULL);
|
2012-07-05 21:43:04 +01:00
|
|
|
|
|
2012-08-31 18:48:26 +01:00
|
|
|
|
if (dri_image == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2012-01-10 22:16:26 +00:00
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
return dri2_create_image_from_dri(disp, dri_image);
|
2011-02-21 15:22:34 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2014-05-06 20:10:57 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_get_sync_values_chromium(_EGLDisplay *dpy, _EGLSurface *surf,
|
|
|
|
|
EGLuint64KHR *ust, EGLuint64KHR *msc,
|
|
|
|
|
EGLuint64KHR *sbc)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->get_sync_values(dpy, surf, ust, msc, sbc);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-27 13:19:54 +00:00
|
|
|
|
/**
|
|
|
|
|
* Set the error code after a call to
|
|
|
|
|
* dri2_egl_image::dri_image::createImageFromTexture.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
|
|
|
|
dri2_create_image_khr_texture_error(int dri_error)
|
|
|
|
|
{
|
|
|
|
|
EGLint egl_error;
|
|
|
|
|
|
|
|
|
|
switch (dri_error) {
|
|
|
|
|
case __DRI_IMAGE_ERROR_SUCCESS:
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_ALLOC:
|
|
|
|
|
egl_error = EGL_BAD_ALLOC;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_MATCH:
|
|
|
|
|
egl_error = EGL_BAD_MATCH;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_PARAMETER:
|
|
|
|
|
egl_error = EGL_BAD_PARAMETER;
|
|
|
|
|
break;
|
|
|
|
|
|
2015-07-31 09:11:46 +01:00
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_ACCESS:
|
|
|
|
|
egl_error = EGL_BAD_ACCESS;
|
|
|
|
|
break;
|
|
|
|
|
|
2012-11-27 13:19:54 +00:00
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
egl_error = EGL_BAD_MATCH;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_eglError(egl_error, "dri2_create_image_khr_texture");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static _EGLImage *
|
|
|
|
|
dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
EGLenum target,
|
|
|
|
|
EGLClientBuffer buffer,
|
|
|
|
|
const EGLint *attr_list)
|
2012-11-27 13:19:54 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
struct dri2_egl_image *dri2_img;
|
|
|
|
|
GLuint texture = (GLuint) (uintptr_t) buffer;
|
|
|
|
|
_EGLImageAttribs attrs;
|
|
|
|
|
GLuint depth;
|
|
|
|
|
GLenum gl_target;
|
|
|
|
|
unsigned error;
|
|
|
|
|
|
|
|
|
|
if (texture == 0) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_eglParseImageAttribList(&attrs, disp, attr_list) != EGL_SUCCESS)
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
|
|
|
|
|
switch (target) {
|
|
|
|
|
case EGL_GL_TEXTURE_2D_KHR:
|
|
|
|
|
depth = 0;
|
|
|
|
|
gl_target = GL_TEXTURE_2D;
|
|
|
|
|
break;
|
|
|
|
|
case EGL_GL_TEXTURE_3D_KHR:
|
2015-06-10 13:42:31 +01:00
|
|
|
|
if (disp->Extensions.KHR_gl_texture_3D_image) {
|
|
|
|
|
depth = attrs.GLTextureZOffset;
|
|
|
|
|
gl_target = GL_TEXTURE_3D;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
2012-11-27 13:19:54 +00:00
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
|
|
|
|
|
depth = target - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR;
|
|
|
|
|
gl_target = GL_TEXTURE_CUBE_MAP;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_img = malloc(sizeof *dri2_img);
|
|
|
|
|
if (!dri2_img) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!_eglInitImage(&dri2_img->base, disp)) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
|
|
|
|
|
free(dri2_img);
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_img->dri_image =
|
|
|
|
|
dri2_dpy->image->createImageFromTexture(dri2_ctx->dri_context,
|
|
|
|
|
gl_target,
|
|
|
|
|
texture,
|
|
|
|
|
depth,
|
|
|
|
|
attrs.GLTextureLevel,
|
|
|
|
|
&error,
|
|
|
|
|
dri2_img);
|
|
|
|
|
dri2_create_image_khr_texture_error(error);
|
|
|
|
|
|
|
|
|
|
if (!dri2_img->dri_image) {
|
|
|
|
|
free(dri2_img);
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
return &dri2_img->base;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-28 18:51:12 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_query_surface(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSurface *surf,
|
|
|
|
|
EGLint attribute, EGLint *value)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
if (!dri2_dpy->vtbl->query_surface)
|
|
|
|
|
return _eglQuerySurface(drv, dpy, surf, attribute, value);
|
|
|
|
|
return dri2_dpy->vtbl->query_surface(drv, dpy, surf, attribute, value);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static struct wl_buffer*
|
|
|
|
|
dri2_create_wayland_buffer_from_image(_EGLDriver *drv, _EGLDisplay *dpy,
|
|
|
|
|
_EGLImage *img)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
return dri2_dpy->vtbl->create_wayland_buffer_from_image(drv, dpy, img);
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-14 19:36:04 +00:00
|
|
|
|
#ifdef HAVE_LIBDRM
|
2015-07-10 11:01:35 +01:00
|
|
|
|
static _EGLImage *
|
|
|
|
|
dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
EGLClientBuffer buffer, const EGLint *attr_list)
|
2015-07-10 11:01:35 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
EGLint format, name, pitch, err;
|
|
|
|
|
_EGLImageAttribs attrs;
|
|
|
|
|
__DRIimage *dri_image;
|
|
|
|
|
|
|
|
|
|
name = (EGLint) (uintptr_t) buffer;
|
|
|
|
|
|
|
|
|
|
err = _eglParseImageAttribList(&attrs, disp, attr_list);
|
|
|
|
|
if (err != EGL_SUCCESS)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (attrs.Width <= 0 || attrs.Height <= 0 ||
|
|
|
|
|
attrs.DRMBufferStrideMESA <= 0) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
"bad width, height or stride");
|
2015-07-10 11:01:35 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (attrs.DRMBufferFormatMESA) {
|
|
|
|
|
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
|
|
|
|
|
format = __DRI_IMAGE_FORMAT_ARGB8888;
|
|
|
|
|
pitch = attrs.DRMBufferStrideMESA;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
"dri2_create_image_khr: unsupported pixmap depth");
|
2015-07-10 11:01:35 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri_image =
|
|
|
|
|
dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
attrs.Width,
|
|
|
|
|
attrs.Height,
|
|
|
|
|
format,
|
|
|
|
|
name,
|
|
|
|
|
pitch,
|
|
|
|
|
NULL);
|
2015-07-10 11:01:35 +01:00
|
|
|
|
|
|
|
|
|
return dri2_create_image_from_dri(disp, dri_image);
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_check_dma_buf_attribs(const _EGLImageAttribs *attrs)
|
|
|
|
|
{
|
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The spec says:
|
|
|
|
|
*
|
|
|
|
|
* "Required attributes and their values are as follows:
|
|
|
|
|
*
|
|
|
|
|
* * EGL_WIDTH & EGL_HEIGHT: The logical dimensions of the buffer in pixels
|
|
|
|
|
*
|
|
|
|
|
* * EGL_LINUX_DRM_FOURCC_EXT: The pixel format of the buffer, as specified
|
|
|
|
|
* by drm_fourcc.h and used as the pixel_format parameter of the
|
|
|
|
|
* drm_mode_fb_cmd2 ioctl."
|
|
|
|
|
*
|
|
|
|
|
* and
|
|
|
|
|
*
|
|
|
|
|
* "* If <target> is EGL_LINUX_DMA_BUF_EXT, and the list of attributes is
|
|
|
|
|
* incomplete, EGL_BAD_PARAMETER is generated."
|
|
|
|
|
*/
|
|
|
|
|
if (attrs->Width <= 0 || attrs->Height <= 0 ||
|
|
|
|
|
!attrs->DMABufFourCC.IsPresent) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "attribute(s) missing");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Also:
|
|
|
|
|
*
|
|
|
|
|
* "If <target> is EGL_LINUX_DMA_BUF_EXT and one or more of the values
|
|
|
|
|
* specified for a plane's pitch or offset isn't supported by EGL,
|
|
|
|
|
* EGL_BAD_ACCESS is generated."
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(attrs->DMABufPlanePitches); ++i) {
|
|
|
|
|
if (attrs->DMABufPlanePitches[i].IsPresent &&
|
|
|
|
|
attrs->DMABufPlanePitches[i].Value <= 0) {
|
|
|
|
|
_eglError(EGL_BAD_ACCESS, "invalid pitch");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:37 +01:00
|
|
|
|
/**
|
|
|
|
|
* If <target> is EGL_LINUX_DMA_BUF_EXT, both or neither of the following
|
|
|
|
|
* attribute values may be given.
|
|
|
|
|
*
|
|
|
|
|
* This is referring to EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT and
|
|
|
|
|
* EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, and the same for other planes.
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < DMA_BUF_MAX_PLANES; ++i) {
|
|
|
|
|
if (attrs->DMABufPlaneModifiersLo[i].IsPresent !=
|
|
|
|
|
attrs->DMABufPlaneModifiersHi[i].IsPresent) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "modifier attribute lo or hi missing");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Although the EGL_EXT_image_dma_buf_import_modifiers spec doesn't
|
|
|
|
|
* mandate it, we only accept the same modifier across all planes. */
|
|
|
|
|
for (i = 1; i < DMA_BUF_MAX_PLANES; ++i) {
|
|
|
|
|
if (attrs->DMABufPlaneFds[i].IsPresent) {
|
|
|
|
|
if ((attrs->DMABufPlaneModifiersLo[0].IsPresent !=
|
|
|
|
|
attrs->DMABufPlaneModifiersLo[i].IsPresent) ||
|
|
|
|
|
(attrs->DMABufPlaneModifiersLo[0].Value !=
|
|
|
|
|
attrs->DMABufPlaneModifiersLo[i].Value) ||
|
|
|
|
|
(attrs->DMABufPlaneModifiersHi[0].Value !=
|
|
|
|
|
attrs->DMABufPlaneModifiersHi[i].Value)) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "modifier attributes not equal");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Returns the total number of file descriptors. Zero indicates an error. */
|
|
|
|
|
static unsigned
|
|
|
|
|
dri2_check_dma_buf_format(const _EGLImageAttribs *attrs)
|
|
|
|
|
{
|
|
|
|
|
unsigned i, plane_n;
|
|
|
|
|
|
|
|
|
|
switch (attrs->DMABufFourCC.Value) {
|
2015-06-23 23:48:17 +01:00
|
|
|
|
case DRM_FORMAT_R8:
|
|
|
|
|
case DRM_FORMAT_RG88:
|
|
|
|
|
case DRM_FORMAT_GR88:
|
2017-01-05 15:58:56 +00:00
|
|
|
|
case DRM_FORMAT_R16:
|
|
|
|
|
case DRM_FORMAT_GR1616:
|
2013-03-22 13:58:05 +00:00
|
|
|
|
case DRM_FORMAT_RGB332:
|
|
|
|
|
case DRM_FORMAT_BGR233:
|
|
|
|
|
case DRM_FORMAT_XRGB4444:
|
|
|
|
|
case DRM_FORMAT_XBGR4444:
|
|
|
|
|
case DRM_FORMAT_RGBX4444:
|
|
|
|
|
case DRM_FORMAT_BGRX4444:
|
|
|
|
|
case DRM_FORMAT_ARGB4444:
|
|
|
|
|
case DRM_FORMAT_ABGR4444:
|
|
|
|
|
case DRM_FORMAT_RGBA4444:
|
|
|
|
|
case DRM_FORMAT_BGRA4444:
|
|
|
|
|
case DRM_FORMAT_XRGB1555:
|
|
|
|
|
case DRM_FORMAT_XBGR1555:
|
|
|
|
|
case DRM_FORMAT_RGBX5551:
|
|
|
|
|
case DRM_FORMAT_BGRX5551:
|
|
|
|
|
case DRM_FORMAT_ARGB1555:
|
|
|
|
|
case DRM_FORMAT_ABGR1555:
|
|
|
|
|
case DRM_FORMAT_RGBA5551:
|
|
|
|
|
case DRM_FORMAT_BGRA5551:
|
|
|
|
|
case DRM_FORMAT_RGB565:
|
|
|
|
|
case DRM_FORMAT_BGR565:
|
|
|
|
|
case DRM_FORMAT_RGB888:
|
|
|
|
|
case DRM_FORMAT_BGR888:
|
|
|
|
|
case DRM_FORMAT_XRGB8888:
|
|
|
|
|
case DRM_FORMAT_XBGR8888:
|
|
|
|
|
case DRM_FORMAT_RGBX8888:
|
|
|
|
|
case DRM_FORMAT_BGRX8888:
|
|
|
|
|
case DRM_FORMAT_ARGB8888:
|
|
|
|
|
case DRM_FORMAT_ABGR8888:
|
|
|
|
|
case DRM_FORMAT_RGBA8888:
|
|
|
|
|
case DRM_FORMAT_BGRA8888:
|
|
|
|
|
case DRM_FORMAT_XRGB2101010:
|
|
|
|
|
case DRM_FORMAT_XBGR2101010:
|
|
|
|
|
case DRM_FORMAT_RGBX1010102:
|
|
|
|
|
case DRM_FORMAT_BGRX1010102:
|
|
|
|
|
case DRM_FORMAT_ARGB2101010:
|
|
|
|
|
case DRM_FORMAT_ABGR2101010:
|
|
|
|
|
case DRM_FORMAT_RGBA1010102:
|
|
|
|
|
case DRM_FORMAT_BGRA1010102:
|
|
|
|
|
case DRM_FORMAT_YUYV:
|
|
|
|
|
case DRM_FORMAT_YVYU:
|
|
|
|
|
case DRM_FORMAT_UYVY:
|
|
|
|
|
case DRM_FORMAT_VYUY:
|
|
|
|
|
plane_n = 1;
|
|
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_NV12:
|
|
|
|
|
case DRM_FORMAT_NV21:
|
|
|
|
|
case DRM_FORMAT_NV16:
|
|
|
|
|
case DRM_FORMAT_NV61:
|
|
|
|
|
plane_n = 2;
|
|
|
|
|
break;
|
|
|
|
|
case DRM_FORMAT_YUV410:
|
|
|
|
|
case DRM_FORMAT_YVU410:
|
|
|
|
|
case DRM_FORMAT_YUV411:
|
|
|
|
|
case DRM_FORMAT_YVU411:
|
|
|
|
|
case DRM_FORMAT_YUV420:
|
|
|
|
|
case DRM_FORMAT_YVU420:
|
|
|
|
|
case DRM_FORMAT_YUV422:
|
|
|
|
|
case DRM_FORMAT_YVU422:
|
|
|
|
|
case DRM_FORMAT_YUV444:
|
|
|
|
|
case DRM_FORMAT_YVU444:
|
|
|
|
|
plane_n = 3;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_eglError(EGL_BAD_ATTRIBUTE, "invalid format");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The spec says:
|
|
|
|
|
*
|
|
|
|
|
* "* If <target> is EGL_LINUX_DMA_BUF_EXT, and the list of attributes is
|
|
|
|
|
* incomplete, EGL_BAD_PARAMETER is generated."
|
|
|
|
|
*/
|
|
|
|
|
for (i = 0; i < plane_n; ++i) {
|
|
|
|
|
if (!attrs->DMABufPlaneFds[i].IsPresent ||
|
|
|
|
|
!attrs->DMABufPlaneOffsets[i].IsPresent ||
|
|
|
|
|
!attrs->DMABufPlanePitches[i].IsPresent) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "plane attribute(s) missing");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The spec also says:
|
|
|
|
|
*
|
|
|
|
|
* "If <target> is EGL_LINUX_DMA_BUF_EXT, and the EGL_LINUX_DRM_FOURCC_EXT
|
|
|
|
|
* attribute indicates a single-plane format, EGL_BAD_ATTRIBUTE is
|
|
|
|
|
* generated if any of the EGL_DMA_BUF_PLANE1_* or EGL_DMA_BUF_PLANE2_*
|
2017-05-30 12:53:35 +01:00
|
|
|
|
* or EGL_DMA_BUF_PLANE3_* attributes are specified."
|
2013-03-22 13:58:05 +00:00
|
|
|
|
*/
|
2017-05-30 12:53:34 +01:00
|
|
|
|
for (i = plane_n; i < DMA_BUF_MAX_PLANES; ++i) {
|
2013-03-22 13:58:05 +00:00
|
|
|
|
if (attrs->DMABufPlaneFds[i].IsPresent ||
|
|
|
|
|
attrs->DMABufPlaneOffsets[i].IsPresent ||
|
2017-05-30 12:53:37 +01:00
|
|
|
|
attrs->DMABufPlanePitches[i].IsPresent ||
|
|
|
|
|
attrs->DMABufPlaneModifiersLo[i].IsPresent ||
|
|
|
|
|
attrs->DMABufPlaneModifiersHi[i].IsPresent) {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The modifiers extension spec says:
|
|
|
|
|
*
|
|
|
|
|
* "Modifiers may modify any attribute of a buffer import, including
|
|
|
|
|
* but not limited to adding extra planes to a format which
|
|
|
|
|
* otherwise does not have those planes. As an example, a modifier
|
|
|
|
|
* may add a plane for an external compression buffer to a
|
|
|
|
|
* single-plane format. The exact meaning and effect of any
|
|
|
|
|
* modifier is canonically defined by drm_fourcc.h, not as part of
|
|
|
|
|
* this extension."
|
|
|
|
|
*/
|
|
|
|
|
if (attrs->DMABufPlaneModifiersLo[i].IsPresent &&
|
|
|
|
|
attrs->DMABufPlaneModifiersHi[i].IsPresent)
|
|
|
|
|
continue;
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
_eglError(EGL_BAD_ATTRIBUTE, "too many plane attributes");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return plane_n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The spec says:
|
|
|
|
|
*
|
2014-08-08 14:26:28 +01:00
|
|
|
|
* "If eglCreateImageKHR is successful for a EGL_LINUX_DMA_BUF_EXT target, the
|
|
|
|
|
* EGL will take a reference to the dma_buf(s) which it will release at any
|
|
|
|
|
* time while the EGLDisplay is initialized. It is the responsibility of the
|
|
|
|
|
* application to close the dma_buf file descriptors."
|
|
|
|
|
*
|
|
|
|
|
* Therefore we must never close or otherwise modify the file descriptors.
|
2013-03-22 13:58:05 +00:00
|
|
|
|
*/
|
2016-05-01 12:42:53 +01:00
|
|
|
|
_EGLImage *
|
2013-03-22 13:58:05 +00:00
|
|
|
|
dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
EGLClientBuffer buffer, const EGLint *attr_list)
|
2013-03-22 13:58:05 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
_EGLImage *res;
|
|
|
|
|
EGLint err;
|
|
|
|
|
_EGLImageAttribs attrs;
|
|
|
|
|
__DRIimage *dri_image;
|
|
|
|
|
unsigned num_fds;
|
|
|
|
|
unsigned i;
|
2017-05-30 12:53:34 +01:00
|
|
|
|
int fds[DMA_BUF_MAX_PLANES];
|
|
|
|
|
int pitches[DMA_BUF_MAX_PLANES];
|
|
|
|
|
int offsets[DMA_BUF_MAX_PLANES];
|
2017-05-30 12:53:37 +01:00
|
|
|
|
uint64_t modifier;
|
|
|
|
|
bool has_modifier = false;
|
2013-03-22 13:58:05 +00:00
|
|
|
|
unsigned error;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The spec says:
|
|
|
|
|
*
|
|
|
|
|
* ""* If <target> is EGL_LINUX_DMA_BUF_EXT and <buffer> is not NULL, the
|
|
|
|
|
* error EGL_BAD_PARAMETER is generated."
|
|
|
|
|
*/
|
|
|
|
|
if (buffer != NULL) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "buffer not NULL");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err = _eglParseImageAttribList(&attrs, disp, attr_list);
|
|
|
|
|
if (err != EGL_SUCCESS) {
|
|
|
|
|
_eglError(err, "bad attribute");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!dri2_check_dma_buf_attribs(&attrs))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
num_fds = dri2_check_dma_buf_format(&attrs);
|
|
|
|
|
if (!num_fds)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < num_fds; ++i) {
|
|
|
|
|
fds[i] = attrs.DMABufPlaneFds[i].Value;
|
|
|
|
|
pitches[i] = attrs.DMABufPlanePitches[i].Value;
|
|
|
|
|
offsets[i] = attrs.DMABufPlaneOffsets[i].Value;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:37 +01:00
|
|
|
|
/* dri2_check_dma_buf_attribs ensures that the modifier, if available,
|
|
|
|
|
* will be present in attrs.DMABufPlaneModifiersLo[0] and
|
|
|
|
|
* attrs.DMABufPlaneModifiersHi[0] */
|
|
|
|
|
if (attrs.DMABufPlaneModifiersLo[0].IsPresent) {
|
|
|
|
|
modifier =
|
|
|
|
|
((uint64_t) attrs.DMABufPlaneModifiersHi[0].Value << 32) |
|
|
|
|
|
attrs.DMABufPlaneModifiersLo[0].Value;
|
|
|
|
|
has_modifier = true;
|
|
|
|
|
} else {
|
|
|
|
|
modifier = DRM_FORMAT_MOD_INVALID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (has_modifier) {
|
|
|
|
|
if (dri2_dpy->image->base.version < 15 ||
|
|
|
|
|
dri2_dpy->image->createImageFromDmaBufs2 == NULL) {
|
|
|
|
|
_eglError(EGL_BAD_MATCH, "unsupported dma_buf format modifier");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
dri_image =
|
|
|
|
|
dri2_dpy->image->createImageFromDmaBufs2(dri2_dpy->dri_screen,
|
|
|
|
|
attrs.Width, attrs.Height, attrs.DMABufFourCC.Value,
|
|
|
|
|
modifier, fds, num_fds, pitches, offsets,
|
|
|
|
|
attrs.DMABufYuvColorSpaceHint.Value,
|
|
|
|
|
attrs.DMABufSampleRangeHint.Value,
|
|
|
|
|
attrs.DMABufChromaHorizontalSiting.Value,
|
|
|
|
|
attrs.DMABufChromaVerticalSiting.Value,
|
|
|
|
|
&error,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
dri_image =
|
|
|
|
|
dri2_dpy->image->createImageFromDmaBufs(dri2_dpy->dri_screen,
|
|
|
|
|
attrs.Width, attrs.Height, attrs.DMABufFourCC.Value,
|
|
|
|
|
fds, num_fds, pitches, offsets,
|
|
|
|
|
attrs.DMABufYuvColorSpaceHint.Value,
|
|
|
|
|
attrs.DMABufSampleRangeHint.Value,
|
|
|
|
|
attrs.DMABufChromaHorizontalSiting.Value,
|
|
|
|
|
attrs.DMABufChromaVerticalSiting.Value,
|
|
|
|
|
&error,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
2013-03-22 13:58:05 +00:00
|
|
|
|
dri2_create_image_khr_texture_error(error);
|
|
|
|
|
|
|
|
|
|
if (!dri_image)
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
res = dri2_create_image_from_dri(disp, dri_image);
|
2013-03-22 13:58:05 +00:00
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
2010-06-04 02:36:40 +01:00
|
|
|
|
static _EGLImage *
|
|
|
|
|
dri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
const EGLint *attr_list)
|
2010-06-04 02:36:40 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img;
|
2010-10-22 10:09:40 +01:00
|
|
|
|
_EGLImageAttribs attrs;
|
|
|
|
|
unsigned int dri_use, valid_mask;
|
|
|
|
|
int format;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
EGLint err = EGL_SUCCESS;
|
|
|
|
|
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) drv;
|
|
|
|
|
|
2010-06-04 02:36:40 +01:00
|
|
|
|
dri2_img = malloc(sizeof *dri2_img);
|
|
|
|
|
if (!dri2_img) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!attr_list) {
|
|
|
|
|
err = EGL_BAD_PARAMETER;
|
|
|
|
|
goto cleanup_img;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-22 09:36:47 +01:00
|
|
|
|
if (!_eglInitImage(&dri2_img->base, disp)) {
|
2010-06-04 02:36:40 +01:00
|
|
|
|
err = EGL_BAD_PARAMETER;
|
|
|
|
|
goto cleanup_img;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-22 10:09:40 +01:00
|
|
|
|
err = _eglParseImageAttribList(&attrs, disp, attr_list);
|
|
|
|
|
if (err != EGL_SUCCESS)
|
|
|
|
|
goto cleanup_img;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
2010-10-22 10:09:40 +01:00
|
|
|
|
if (attrs.Width <= 0 || attrs.Height <= 0) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "bad width or height (%dx%d)",
|
|
|
|
|
attrs.Width, attrs.Height);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
goto cleanup_img;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-22 10:09:40 +01:00
|
|
|
|
switch (attrs.DRMBufferFormatMESA) {
|
2010-06-04 02:36:40 +01:00
|
|
|
|
case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
|
|
|
|
|
format = __DRI_IMAGE_FORMAT_ARGB8888;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2010-10-22 10:09:40 +01:00
|
|
|
|
_eglLog(_EGL_WARNING, "bad image format value 0x%04x",
|
|
|
|
|
attrs.DRMBufferFormatMESA);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
goto cleanup_img;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
valid_mask =
|
|
|
|
|
EGL_DRM_BUFFER_USE_SCANOUT_MESA |
|
2011-05-06 15:31:18 +01:00
|
|
|
|
EGL_DRM_BUFFER_USE_SHARE_MESA |
|
|
|
|
|
EGL_DRM_BUFFER_USE_CURSOR_MESA;
|
2010-10-22 10:09:40 +01:00
|
|
|
|
if (attrs.DRMBufferUseMESA & ~valid_mask) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "bad image use bit 0x%04x",
|
|
|
|
|
attrs.DRMBufferUseMESA & ~valid_mask);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
goto cleanup_img;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri_use = 0;
|
2010-10-22 10:09:40 +01:00
|
|
|
|
if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA)
|
2010-06-04 02:36:40 +01:00
|
|
|
|
dri_use |= __DRI_IMAGE_USE_SHARE;
|
2010-10-22 10:09:40 +01:00
|
|
|
|
if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
|
2010-06-04 02:36:40 +01:00
|
|
|
|
dri_use |= __DRI_IMAGE_USE_SCANOUT;
|
2011-05-06 15:31:18 +01:00
|
|
|
|
if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_CURSOR_MESA)
|
|
|
|
|
dri_use |= __DRI_IMAGE_USE_CURSOR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
2015-06-13 08:36:27 +01:00
|
|
|
|
dri2_img->dri_image =
|
2010-06-04 02:36:40 +01:00
|
|
|
|
dri2_dpy->image->createImage(dri2_dpy->dri_screen,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
attrs.Width, attrs.Height,
|
2010-10-22 10:09:40 +01:00
|
|
|
|
format, dri_use, dri2_img);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
if (dri2_img->dri_image == NULL) {
|
|
|
|
|
err = EGL_BAD_ALLOC;
|
|
|
|
|
goto cleanup_img;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &dri2_img->base;
|
|
|
|
|
|
|
|
|
|
cleanup_img:
|
|
|
|
|
free(dri2_img);
|
|
|
|
|
_eglError(err, "dri2_create_drm_image_mesa");
|
|
|
|
|
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
EGLint *name, EGLint *handle, EGLint *stride)
|
2010-06-04 02:36:40 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
|
|
|
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) drv;
|
|
|
|
|
|
2010-06-04 02:36:40 +01:00
|
|
|
|
if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_NAME, name)) {
|
2010-06-04 02:36:40 +01:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (handle)
|
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_HANDLE, handle);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
|
|
|
|
if (stride)
|
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_STRIDE, stride);
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp,
|
|
|
|
|
_EGLImage *img,
|
|
|
|
|
EGLint *fourcc, EGLint *nplanes,
|
2015-05-05 00:10:34 +01:00
|
|
|
|
EGLuint64KHR *modifiers)
|
2014-03-03 03:57:16 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nplanes)
|
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_NUM_PLANES, nplanes);
|
2014-03-03 03:57:16 +00:00
|
|
|
|
if (fourcc)
|
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_FOURCC, fourcc);
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
if (modifiers)
|
|
|
|
|
*modifiers = 0;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
|
|
|
|
|
int *fds, EGLint *strides, EGLint *offsets)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
/* rework later to provide multiple fds/strides/offsets */
|
|
|
|
|
if (fds)
|
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_FD, fds);
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
if (strides)
|
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_STRIDE, strides);
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
2016-09-13 18:07:10 +01:00
|
|
|
|
if (offsets) {
|
|
|
|
|
int img_offset;
|
|
|
|
|
bool ret = dri2_dpy->image->queryImage(dri2_img->dri_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_OFFSET, &img_offset);
|
|
|
|
|
if (ret)
|
|
|
|
|
offsets[0] = img_offset;
|
|
|
|
|
else
|
|
|
|
|
offsets[0] = 0;
|
|
|
|
|
}
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
2015-07-10 11:01:35 +01:00
|
|
|
|
|
2013-11-10 18:32:01 +00:00
|
|
|
|
#endif
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
2015-07-10 11:01:35 +01:00
|
|
|
|
_EGLImage *
|
|
|
|
|
dri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
_EGLContext *ctx, EGLenum target,
|
|
|
|
|
EGLClientBuffer buffer, const EGLint *attr_list)
|
2015-07-10 11:01:35 +01:00
|
|
|
|
{
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
switch (target) {
|
|
|
|
|
case EGL_GL_TEXTURE_2D_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
|
|
|
|
|
case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
|
|
|
|
|
return dri2_create_image_khr_texture(disp, ctx, target, buffer, attr_list);
|
|
|
|
|
case EGL_GL_TEXTURE_3D_KHR:
|
|
|
|
|
if (disp->Extensions.KHR_gl_texture_3D_image) {
|
|
|
|
|
return dri2_create_image_khr_texture(disp, ctx, target, buffer, attr_list);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
case EGL_GL_RENDERBUFFER_KHR:
|
|
|
|
|
return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list);
|
|
|
|
|
#ifdef HAVE_LIBDRM
|
|
|
|
|
case EGL_DRM_BUFFER_MESA:
|
|
|
|
|
return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list);
|
|
|
|
|
case EGL_LINUX_DMA_BUF_EXT:
|
|
|
|
|
return dri2_create_image_dma_buf(disp, ctx, buffer, attr_list);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
|
|
|
|
case EGL_WAYLAND_BUFFER_WL:
|
|
|
|
|
return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list);
|
|
|
|
|
#endif
|
|
|
|
|
default:
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(image);
|
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->image->destroyImage(dri2_img->dri_image);
|
|
|
|
|
free(dri2_img);
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
2011-04-30 10:17:01 +01:00
|
|
|
|
|
2012-07-05 19:19:48 +01:00
|
|
|
|
static void
|
2013-02-02 17:26:12 +00:00
|
|
|
|
dri2_wl_reference_buffer(void *user_data, uint32_t name, int fd,
|
2012-07-05 19:19:48 +01:00
|
|
|
|
struct wl_drm_buffer *buffer)
|
2011-04-30 10:17:01 +01:00
|
|
|
|
{
|
|
|
|
|
_EGLDisplay *disp = user_data;
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2012-08-31 18:48:26 +01:00
|
|
|
|
__DRIimage *img;
|
|
|
|
|
int i, dri_components = 0;
|
|
|
|
|
|
2013-02-02 17:26:12 +00:00
|
|
|
|
if (fd == -1)
|
|
|
|
|
img = dri2_dpy->image->createImageFromNames(dri2_dpy->dri_screen,
|
2013-07-18 13:11:25 +01:00
|
|
|
|
buffer->width,
|
|
|
|
|
buffer->height,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
buffer->format,
|
|
|
|
|
(int*)&name, 1,
|
|
|
|
|
buffer->stride,
|
|
|
|
|
buffer->offset,
|
|
|
|
|
NULL);
|
|
|
|
|
else
|
|
|
|
|
img = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen,
|
2013-07-18 13:11:25 +01:00
|
|
|
|
buffer->width,
|
|
|
|
|
buffer->height,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
buffer->format,
|
|
|
|
|
&fd, 1,
|
|
|
|
|
buffer->stride,
|
|
|
|
|
buffer->offset,
|
|
|
|
|
NULL);
|
2012-08-31 18:48:26 +01:00
|
|
|
|
|
|
|
|
|
if (img == NULL)
|
|
|
|
|
return;
|
2011-08-31 21:45:04 +01:00
|
|
|
|
|
2012-08-31 18:48:26 +01:00
|
|
|
|
dri2_dpy->image->queryImage(img, __DRI_IMAGE_ATTRIB_COMPONENTS, &dri_components);
|
2012-07-05 21:43:04 +01:00
|
|
|
|
|
2012-08-31 18:48:26 +01:00
|
|
|
|
buffer->driver_format = NULL;
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(wl_drm_components); i++)
|
|
|
|
|
if (wl_drm_components[i].dri_components == dri_components)
|
|
|
|
|
buffer->driver_format = &wl_drm_components[i];
|
2011-04-30 10:17:01 +01:00
|
|
|
|
|
2012-08-31 18:48:26 +01:00
|
|
|
|
if (buffer->driver_format == NULL)
|
|
|
|
|
dri2_dpy->image->destroyImage(img);
|
|
|
|
|
else
|
|
|
|
|
buffer->driver_buffer = img;
|
2011-04-30 10:17:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2012-07-05 19:19:48 +01:00
|
|
|
|
dri2_wl_release_buffer(void *user_data, struct wl_drm_buffer *buffer)
|
2011-04-30 10:17:01 +01:00
|
|
|
|
{
|
|
|
|
|
_EGLDisplay *disp = user_data;
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
|
2012-07-05 19:19:48 +01:00
|
|
|
|
dri2_dpy->image->destroyImage(buffer->driver_buffer);
|
2011-04-30 10:17:01 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct wayland_drm_callbacks wl_drm_callbacks = {
|
2016-08-25 00:12:13 +01:00
|
|
|
|
.authenticate = NULL,
|
|
|
|
|
.reference_buffer = dri2_wl_reference_buffer,
|
|
|
|
|
.release_buffer = dri2_wl_release_buffer
|
2011-04-30 10:17:01 +01:00
|
|
|
|
};
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
struct wl_display *wl_dpy)
|
2011-02-21 15:22:34 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2014-05-28 14:36:46 +01:00
|
|
|
|
int flags = 0;
|
2013-02-02 17:26:12 +00:00
|
|
|
|
uint64_t cap;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->wl_server_drm)
|
2016-08-25 00:12:13 +01:00
|
|
|
|
return EGL_FALSE;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2011-04-30 10:17:01 +01:00
|
|
|
|
wl_drm_callbacks.authenticate =
|
2014-01-28 19:41:46 +00:00
|
|
|
|
(int(*)(void *, uint32_t)) dri2_dpy->vtbl->authenticate;
|
2011-04-30 10:17:01 +01:00
|
|
|
|
|
2014-05-28 14:36:46 +01:00
|
|
|
|
if (drmGetCap(dri2_dpy->fd, DRM_CAP_PRIME, &cap) == 0 &&
|
|
|
|
|
cap == (DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT) &&
|
2013-03-19 17:20:36 +00:00
|
|
|
|
dri2_dpy->image->base.version >= 7 &&
|
|
|
|
|
dri2_dpy->image->createImageFromFds != NULL)
|
2013-02-02 17:26:12 +00:00
|
|
|
|
flags |= WAYLAND_DRM_PRIME;
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
dri2_dpy->wl_server_drm =
|
2016-08-25 00:12:13 +01:00
|
|
|
|
wayland_drm_init(wl_dpy, dri2_dpy->device_name,
|
2013-02-02 17:26:12 +00:00
|
|
|
|
&wl_drm_callbacks, disp, flags);
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
|
|
|
|
if (!dri2_dpy->wl_server_drm)
|
2016-08-25 00:12:13 +01:00
|
|
|
|
return EGL_FALSE;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2014-04-08 21:28:42 +01:00
|
|
|
|
#ifdef HAVE_DRM_PLATFORM
|
2013-09-26 20:25:11 +01:00
|
|
|
|
/* We have to share the wl_drm instance with gbm, so gbm can convert
|
|
|
|
|
* wl_buffers to gbm bos. */
|
2013-10-11 23:30:09 +01:00
|
|
|
|
if (dri2_dpy->gbm_dri)
|
|
|
|
|
dri2_dpy->gbm_dri->wl_drm = dri2_dpy->wl_server_drm;
|
2014-04-08 21:28:42 +01:00
|
|
|
|
#endif
|
2013-09-26 20:25:11 +01:00
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
|
2016-08-25 00:12:13 +01:00
|
|
|
|
struct wl_display *wl_dpy)
|
2011-02-21 15:22:34 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
|
|
|
|
if (!dri2_dpy->wl_server_drm)
|
2016-08-25 00:12:13 +01:00
|
|
|
|
return EGL_FALSE;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
|
2011-04-30 10:17:01 +01:00
|
|
|
|
wayland_drm_uninit(dri2_dpy->wl_server_drm);
|
2011-02-21 15:22:34 +00:00
|
|
|
|
dri2_dpy->wl_server_drm = NULL;
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
2012-07-05 21:43:04 +01:00
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp,
|
2013-07-18 13:11:25 +01:00
|
|
|
|
struct wl_resource *buffer_resource,
|
2012-07-05 21:43:04 +01:00
|
|
|
|
EGLint attribute, EGLint *value)
|
|
|
|
|
{
|
2013-09-26 20:25:11 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2013-07-18 13:11:25 +01:00
|
|
|
|
struct wl_drm_buffer *buffer;
|
2012-08-31 18:48:26 +01:00
|
|
|
|
const struct wl_drm_components_descriptor *format;
|
2012-07-05 21:43:04 +01:00
|
|
|
|
|
2013-09-26 20:25:11 +01:00
|
|
|
|
buffer = wayland_drm_buffer_get(dri2_dpy->wl_server_drm, buffer_resource);
|
2013-07-18 13:11:25 +01:00
|
|
|
|
if (!buffer)
|
2012-07-05 21:43:04 +01:00
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
format = buffer->driver_format;
|
2012-07-19 14:02:25 +01:00
|
|
|
|
switch (attribute) {
|
|
|
|
|
case EGL_TEXTURE_FORMAT:
|
2012-07-05 21:43:04 +01:00
|
|
|
|
*value = format->components;
|
|
|
|
|
return EGL_TRUE;
|
2012-07-19 14:02:25 +01:00
|
|
|
|
case EGL_WIDTH:
|
2013-07-18 13:11:25 +01:00
|
|
|
|
*value = buffer->width;
|
2013-04-10 11:36:24 +01:00
|
|
|
|
return EGL_TRUE;
|
2012-07-19 14:02:25 +01:00
|
|
|
|
case EGL_HEIGHT:
|
2013-07-18 13:11:25 +01:00
|
|
|
|
*value = buffer->height;
|
2013-04-10 11:36:24 +01:00
|
|
|
|
return EGL_TRUE;
|
2012-07-05 21:43:04 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2015-04-10 09:56:02 +01:00
|
|
|
|
static void
|
|
|
|
|
dri2_egl_ref_sync(struct dri2_egl_sync *sync)
|
|
|
|
|
{
|
|
|
|
|
p_atomic_inc(&sync->refcount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy,
|
|
|
|
|
struct dri2_egl_sync *dri2_sync)
|
|
|
|
|
{
|
|
|
|
|
if (p_atomic_dec_zero(&dri2_sync->refcount)) {
|
2016-11-18 13:39:33 +00:00
|
|
|
|
switch (dri2_sync->base.Type) {
|
|
|
|
|
case EGL_SYNC_REUSABLE_KHR:
|
2016-04-05 01:14:10 +01:00
|
|
|
|
cnd_destroy(&dri2_sync->cond);
|
2016-11-18 13:39:33 +00:00
|
|
|
|
break;
|
|
|
|
|
case EGL_SYNC_NATIVE_FENCE_ANDROID:
|
|
|
|
|
if (dri2_sync->base.SyncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID)
|
|
|
|
|
close(dri2_sync->base.SyncFd);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
|
|
|
|
if (dri2_sync->fence)
|
|
|
|
|
dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence);
|
|
|
|
|
|
2015-04-10 09:56:02 +01:00
|
|
|
|
free(dri2_sync);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static _EGLSync *
|
|
|
|
|
dri2_create_sync(_EGLDriver *drv, _EGLDisplay *dpy,
|
egl: Unify the EGLint/EGLAttrib paths in eglCreateSync* (v3)
Pre-patch, there were two code paths for parsing EGLSync attribute
lists: one path for old-style EGLint lists, used by eglCreateSyncKHR,
and another for new-style EGLAttrib lists, used by eglCreateSync (1.5)
and eglCreateSync64 (EGL_KHR_cl_event2).
There were two attrib_list parsing functions,
_eglParseSyncAttribList(_EGLSync *sync, const EGLint *attrib_list)
_eglParseSyncAttribList64(_EGLSync *sync, const EGLattrib *attrib_list)
This patch unifies the two attrib_list parsing functions into one,
_eglParseSyncAttribList(_EGLSync *sync, const EGLattrib *attrib_list)
Many internal EGLSync function signatures had *two* attrib_list
parameters to accomodate both code paths: one parameter was an EGLint
list and other an EGLAttrib list. At most one of the parameters was
allowed to be non-null. This patch removes the `EGLint *attrib_list`
parameter, leaving only the `EGLAttrib *attrib_list` parameter, for all
internal EGLSync functions.
v2:
- Consistently use condition (sizeof(int_list[0]) ==
sizeof(attrib_list[0])). [for emil]
v3:
- Don't double-unlock the display in eglCreateSyncKHR.
Reviewed-by: Emil Velikov <emil.velikov@collabora.com> (v2)
2016-09-27 21:27:21 +01:00
|
|
|
|
EGLenum type, const EGLAttrib *attrib_list)
|
2015-04-10 09:56:02 +01:00
|
|
|
|
{
|
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
struct dri2_egl_sync *dri2_sync;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
EGLint ret;
|
|
|
|
|
pthread_condattr_t attr;
|
2015-04-10 09:56:02 +01:00
|
|
|
|
|
|
|
|
|
dri2_sync = calloc(1, sizeof(struct dri2_egl_sync));
|
|
|
|
|
if (!dri2_sync) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
egl: Unify the EGLint/EGLAttrib paths in eglCreateSync* (v3)
Pre-patch, there were two code paths for parsing EGLSync attribute
lists: one path for old-style EGLint lists, used by eglCreateSyncKHR,
and another for new-style EGLAttrib lists, used by eglCreateSync (1.5)
and eglCreateSync64 (EGL_KHR_cl_event2).
There were two attrib_list parsing functions,
_eglParseSyncAttribList(_EGLSync *sync, const EGLint *attrib_list)
_eglParseSyncAttribList64(_EGLSync *sync, const EGLattrib *attrib_list)
This patch unifies the two attrib_list parsing functions into one,
_eglParseSyncAttribList(_EGLSync *sync, const EGLattrib *attrib_list)
Many internal EGLSync function signatures had *two* attrib_list
parameters to accomodate both code paths: one parameter was an EGLint
list and other an EGLAttrib list. At most one of the parameters was
allowed to be non-null. This patch removes the `EGLint *attrib_list`
parameter, leaving only the `EGLAttrib *attrib_list` parameter, for all
internal EGLSync functions.
v2:
- Consistently use condition (sizeof(int_list[0]) ==
sizeof(attrib_list[0])). [for emil]
v3:
- Don't double-unlock the display in eglCreateSyncKHR.
Reviewed-by: Emil Velikov <emil.velikov@collabora.com> (v2)
2016-09-27 21:27:21 +01:00
|
|
|
|
if (!_eglInitSync(&dri2_sync->base, dpy, type, attrib_list)) {
|
2015-04-10 09:56:02 +01:00
|
|
|
|
free(dri2_sync);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case EGL_SYNC_FENCE_KHR:
|
|
|
|
|
dri2_sync->fence = dri2_dpy->fence->create_fence(dri2_ctx->dri_context);
|
2015-05-06 03:05:20 +01:00
|
|
|
|
if (!dri2_sync->fence) {
|
|
|
|
|
/* Why did it fail? DRI doesn't return an error code, so we emit
|
2015-05-07 16:09:07 +01:00
|
|
|
|
* a generic EGL error that doesn't communicate user error.
|
|
|
|
|
*/
|
2015-05-06 03:05:20 +01:00
|
|
|
|
_eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
|
|
|
|
|
free(dri2_sync);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2015-04-10 09:56:02 +01:00
|
|
|
|
break;
|
2015-04-10 12:16:30 +01:00
|
|
|
|
|
|
|
|
|
case EGL_SYNC_CL_EVENT_KHR:
|
|
|
|
|
dri2_sync->fence = dri2_dpy->fence->get_fence_from_cl_event(
|
|
|
|
|
dri2_dpy->dri_screen,
|
|
|
|
|
dri2_sync->base.CLEvent);
|
|
|
|
|
/* this can only happen if the cl_event passed in is invalid. */
|
|
|
|
|
if (!dri2_sync->fence) {
|
|
|
|
|
_eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
|
|
|
|
|
free(dri2_sync);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* the initial status must be "signaled" if the cl_event is signaled */
|
|
|
|
|
if (dri2_dpy->fence->client_wait_sync(dri2_ctx->dri_context,
|
|
|
|
|
dri2_sync->fence, 0, 0))
|
|
|
|
|
dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
|
|
|
|
|
break;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
|
|
|
|
case EGL_SYNC_REUSABLE_KHR:
|
|
|
|
|
/* intialize attr */
|
|
|
|
|
ret = pthread_condattr_init(&attr);
|
|
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
_eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR");
|
|
|
|
|
free(dri2_sync);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* change clock attribute to CLOCK_MONOTONIC */
|
|
|
|
|
ret = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
|
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
_eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR");
|
|
|
|
|
free(dri2_sync);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = pthread_cond_init(&dri2_sync->cond, &attr);
|
|
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
_eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR");
|
|
|
|
|
free(dri2_sync);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* initial status of reusable sync must be "unsignaled" */
|
|
|
|
|
dri2_sync->base.SyncStatus = EGL_UNSIGNALED_KHR;
|
|
|
|
|
break;
|
2016-11-18 13:39:33 +00:00
|
|
|
|
|
|
|
|
|
case EGL_SYNC_NATIVE_FENCE_ANDROID:
|
|
|
|
|
if (dri2_dpy->fence->create_fence_fd) {
|
|
|
|
|
dri2_sync->fence = dri2_dpy->fence->create_fence_fd(
|
|
|
|
|
dri2_ctx->dri_context,
|
|
|
|
|
dri2_sync->base.SyncFd);
|
|
|
|
|
}
|
|
|
|
|
if (!dri2_sync->fence) {
|
|
|
|
|
_eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
|
|
|
|
|
free(dri2_sync);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2015-04-10 09:56:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
p_atomic_set(&dri2_sync->refcount, 1);
|
|
|
|
|
return &dri2_sync->base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
|
2016-04-05 01:14:10 +01:00
|
|
|
|
EGLint ret = EGL_TRUE;
|
|
|
|
|
EGLint err;
|
|
|
|
|
|
|
|
|
|
/* if type of sync is EGL_SYNC_REUSABLE_KHR and it is not signaled yet,
|
|
|
|
|
* then unlock all threads possibly blocked by the reusable sync before
|
|
|
|
|
* destroying it.
|
|
|
|
|
*/
|
|
|
|
|
if (dri2_sync->base.Type == EGL_SYNC_REUSABLE_KHR &&
|
|
|
|
|
dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR) {
|
|
|
|
|
dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
|
|
|
|
|
/* unblock all threads currently blocked by sync */
|
|
|
|
|
err = cnd_broadcast(&dri2_sync->cond);
|
2015-04-10 09:56:02 +01:00
|
|
|
|
|
2016-04-05 01:14:10 +01:00
|
|
|
|
if (err) {
|
|
|
|
|
_eglError(EGL_BAD_ACCESS, "eglDestroySyncKHR");
|
|
|
|
|
ret = EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-11-18 13:39:33 +00:00
|
|
|
|
|
2015-04-10 09:56:02 +01:00
|
|
|
|
dri2_egl_unref_sync(dri2_dpy, dri2_sync);
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
|
|
|
|
return ret;
|
2015-04-10 09:56:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-11-18 13:39:33 +00:00
|
|
|
|
static EGLint
|
|
|
|
|
dri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
|
|
|
|
|
|
|
|
|
|
assert(sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID);
|
|
|
|
|
|
|
|
|
|
if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
|
|
|
|
|
/* try to retrieve the actual native fence fd.. if rendering is
|
|
|
|
|
* not flushed this will just return -1, aka NO_NATIVE_FENCE_FD:
|
|
|
|
|
*/
|
|
|
|
|
sync->SyncFd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_sync->fence);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
|
|
|
|
|
/* if native fence fd still not created, return an error: */
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "eglDupNativeFenceFDANDROID");
|
|
|
|
|
return EGL_NO_NATIVE_FENCE_FD_ANDROID;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dup(sync->SyncFd);
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-10 09:56:02 +01:00
|
|
|
|
static EGLint
|
|
|
|
|
dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
2015-05-12 16:34:57 +01:00
|
|
|
|
EGLint flags, EGLTime timeout)
|
2015-04-10 09:56:02 +01:00
|
|
|
|
{
|
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
2016-04-05 01:14:10 +01:00
|
|
|
|
struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
|
2015-04-10 09:56:02 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
|
|
|
|
|
unsigned wait_flags = 0;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
|
|
|
|
/* timespecs for cnd_timedwait */
|
|
|
|
|
struct timespec current;
|
|
|
|
|
xtime expire;
|
|
|
|
|
|
2015-04-10 09:56:02 +01:00
|
|
|
|
EGLint ret = EGL_CONDITION_SATISFIED_KHR;
|
|
|
|
|
|
2015-09-25 21:48:00 +01:00
|
|
|
|
/* The EGL_KHR_fence_sync spec states:
|
|
|
|
|
*
|
|
|
|
|
* "If no context is current for the bound API,
|
|
|
|
|
* the EGL_SYNC_FLUSH_COMMANDS_BIT_KHR bit is ignored.
|
|
|
|
|
*/
|
|
|
|
|
if (dri2_ctx && flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)
|
2015-04-10 09:56:02 +01:00
|
|
|
|
wait_flags |= __DRI2_FENCE_FLAG_FLUSH_COMMANDS;
|
|
|
|
|
|
|
|
|
|
/* the sync object should take a reference while waiting */
|
|
|
|
|
dri2_egl_ref_sync(dri2_sync);
|
|
|
|
|
|
2016-04-05 01:14:10 +01:00
|
|
|
|
switch (sync->Type) {
|
|
|
|
|
case EGL_SYNC_FENCE_KHR:
|
2016-11-18 13:39:33 +00:00
|
|
|
|
case EGL_SYNC_NATIVE_FENCE_ANDROID:
|
2016-04-05 01:14:10 +01:00
|
|
|
|
case EGL_SYNC_CL_EVENT_KHR:
|
|
|
|
|
if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL,
|
2015-04-10 09:56:02 +01:00
|
|
|
|
dri2_sync->fence, wait_flags,
|
|
|
|
|
timeout))
|
2016-04-05 01:14:10 +01:00
|
|
|
|
dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
|
|
|
|
|
else
|
|
|
|
|
ret = EGL_TIMEOUT_EXPIRED_KHR;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EGL_SYNC_REUSABLE_KHR:
|
|
|
|
|
if (dri2_ctx && dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR &&
|
|
|
|
|
(flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)) {
|
|
|
|
|
/* flush context if EGL_SYNC_FLUSH_COMMANDS_BIT_KHR is set */
|
2016-08-16 14:25:19 +01:00
|
|
|
|
dri2_drv->glFlush();
|
2016-04-05 01:14:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* if timeout is EGL_FOREVER_KHR, it should wait without any timeout.*/
|
|
|
|
|
if (timeout == EGL_FOREVER_KHR) {
|
2016-08-15 23:12:03 +01:00
|
|
|
|
mtx_lock(&dri2_sync->mutex);
|
|
|
|
|
cnd_wait(&dri2_sync->cond, &dri2_sync->mutex);
|
2016-05-16 22:43:26 +01:00
|
|
|
|
mtx_unlock(&dri2_sync->mutex);
|
2016-04-05 01:14:10 +01:00
|
|
|
|
} else {
|
|
|
|
|
/* if reusable sync has not been yet signaled */
|
|
|
|
|
if (dri2_sync->base.SyncStatus != EGL_SIGNALED_KHR) {
|
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, ¤t);
|
|
|
|
|
|
|
|
|
|
/* calculating when to expire */
|
|
|
|
|
expire.nsec = timeout % 1000000000L;
|
|
|
|
|
expire.sec = timeout / 1000000000L;
|
|
|
|
|
|
|
|
|
|
expire.nsec += current.tv_nsec;
|
|
|
|
|
expire.sec += current.tv_sec;
|
|
|
|
|
|
|
|
|
|
/* expire.nsec now is a number between 0 and 1999999998 */
|
|
|
|
|
if (expire.nsec > 999999999L) {
|
|
|
|
|
expire.sec++;
|
|
|
|
|
expire.nsec -= 1000000000L;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-15 23:12:03 +01:00
|
|
|
|
mtx_lock(&dri2_sync->mutex);
|
2016-04-05 01:14:10 +01:00
|
|
|
|
ret = cnd_timedwait(&dri2_sync->cond, &dri2_sync->mutex, &expire);
|
2016-05-16 22:43:26 +01:00
|
|
|
|
mtx_unlock(&dri2_sync->mutex);
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
2016-08-15 23:12:03 +01:00
|
|
|
|
if (ret == thrd_busy) {
|
|
|
|
|
if (dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR) {
|
|
|
|
|
ret = EGL_TIMEOUT_EXPIRED_KHR;
|
|
|
|
|
} else {
|
|
|
|
|
_eglError(EGL_BAD_ACCESS, "eglClientWaitSyncKHR");
|
|
|
|
|
ret = EGL_FALSE;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
}
|
2016-08-15 23:12:03 +01:00
|
|
|
|
}
|
2016-04-05 01:14:10 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-08-15 23:12:03 +01:00
|
|
|
|
dri2_egl_unref_sync(dri2_dpy, dri2_sync);
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
2016-08-15 23:12:03 +01:00
|
|
|
|
return ret;
|
2015-04-10 09:56:02 +01:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-05 01:14:10 +01:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_signal_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
|
|
|
|
EGLenum mode)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
|
|
|
|
|
EGLint ret;
|
|
|
|
|
|
|
|
|
|
if (sync->Type != EGL_SYNC_REUSABLE_KHR) {
|
|
|
|
|
_eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mode != EGL_SIGNALED_KHR && mode != EGL_UNSIGNALED_KHR) {
|
|
|
|
|
_eglError(EGL_BAD_ATTRIBUTE, "eglSignalSyncKHR");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_sync->base.SyncStatus = mode;
|
|
|
|
|
|
|
|
|
|
if (mode == EGL_SIGNALED_KHR) {
|
|
|
|
|
ret = cnd_broadcast(&dri2_sync->cond);
|
|
|
|
|
|
|
|
|
|
/* fail to broadcast */
|
|
|
|
|
if (ret) {
|
|
|
|
|
_eglError(EGL_BAD_ACCESS, "eglSignalSyncKHR");
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-10 11:04:18 +01:00
|
|
|
|
static EGLint
|
|
|
|
|
dri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
|
|
|
|
|
{
|
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
|
|
|
|
|
|
|
|
|
|
dri2_dpy->fence->server_wait_sync(dri2_ctx->dri_context,
|
|
|
|
|
dri2_sync->fence, 0);
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-03 14:59:48 +00:00
|
|
|
|
static int
|
|
|
|
|
dri2_interop_query_device_info(_EGLDisplay *dpy, _EGLContext *ctx,
|
2016-05-30 10:56:33 +01:00
|
|
|
|
struct mesa_glinterop_device_info *out)
|
2016-03-03 14:59:48 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
|
|
|
|
|
if (!dri2_dpy->interop)
|
|
|
|
|
return MESA_GLINTEROP_UNSUPPORTED;
|
|
|
|
|
|
|
|
|
|
return dri2_dpy->interop->query_device_info(dri2_ctx->dri_context, out);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
dri2_interop_export_object(_EGLDisplay *dpy, _EGLContext *ctx,
|
2016-05-30 10:56:33 +01:00
|
|
|
|
struct mesa_glinterop_export_in *in,
|
|
|
|
|
struct mesa_glinterop_export_out *out)
|
2016-03-03 14:59:48 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
|
|
|
|
|
|
|
|
|
if (!dri2_dpy->interop)
|
|
|
|
|
return MESA_GLINTEROP_UNSUPPORTED;
|
|
|
|
|
|
|
|
|
|
return dri2_dpy->interop->export_object(dri2_ctx->dri_context, in, out);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-07 07:02:41 +00:00
|
|
|
|
static void
|
|
|
|
|
dri2_unload(_EGLDriver *drv)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
|
2011-01-29 21:09:06 +00:00
|
|
|
|
|
2016-08-16 16:33:49 +01:00
|
|
|
|
dlclose(dri2_drv->handle);
|
2011-01-07 07:02:41 +00:00
|
|
|
|
free(dri2_drv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_load(_EGLDriver *drv)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
|
2011-08-05 06:39:18 +01:00
|
|
|
|
#ifdef HAVE_ANDROID_PLATFORM
|
|
|
|
|
const char *libname = "libglapi.so";
|
2015-06-18 06:53:52 +01:00
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
|
const char *libname = "libglapi.0.dylib";
|
2016-06-11 15:53:50 +01:00
|
|
|
|
#elif defined(__CYGWIN__)
|
|
|
|
|
const char *libname = "cygglapi-0.dll";
|
2016-08-16 16:33:49 +01:00
|
|
|
|
#else
|
2016-10-19 15:09:26 +01:00
|
|
|
|
const char *libname = "libglapi.so.0";
|
2011-01-29 21:09:06 +00:00
|
|
|
|
#endif
|
2011-01-07 07:02:41 +00:00
|
|
|
|
void *handle;
|
|
|
|
|
|
2011-01-29 21:09:06 +00:00
|
|
|
|
/* RTLD_GLOBAL to make sure glapi symbols are visible to DRI drivers */
|
|
|
|
|
handle = dlopen(libname, RTLD_LAZY | RTLD_GLOBAL);
|
2016-08-16 16:33:49 +01:00
|
|
|
|
if (!handle) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "DRI2: failed to open glapi provider");
|
|
|
|
|
goto no_handle;
|
2011-01-07 07:02:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 16:33:49 +01:00
|
|
|
|
dri2_drv->get_proc_address = (_EGLProc (*)(const char *))
|
|
|
|
|
dlsym(handle, "_glapi_get_proc_address");
|
|
|
|
|
|
2011-01-29 21:09:06 +00:00
|
|
|
|
/* if glapi is not available, loading DRI drivers will fail */
|
2011-01-07 07:02:41 +00:00
|
|
|
|
if (!dri2_drv->get_proc_address) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "DRI2: failed to find _glapi_get_proc_address");
|
2016-08-16 16:33:49 +01:00
|
|
|
|
goto no_symbol;
|
2011-01-07 07:02:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dri2_drv->glFlush = (void (*)(void))
|
|
|
|
|
dri2_drv->get_proc_address("glFlush");
|
|
|
|
|
|
2016-08-16 14:25:19 +01:00
|
|
|
|
/* if glFlush is not available things are horribly broken */
|
|
|
|
|
if (!dri2_drv->glFlush) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "DRI2: failed to find glFlush entry point");
|
2016-08-16 16:33:49 +01:00
|
|
|
|
goto no_symbol;
|
2016-08-16 14:25:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
2011-01-29 21:09:06 +00:00
|
|
|
|
dri2_drv->handle = handle;
|
2011-01-07 07:02:41 +00:00
|
|
|
|
return EGL_TRUE;
|
2016-08-16 16:33:49 +01:00
|
|
|
|
|
|
|
|
|
no_symbol:
|
|
|
|
|
dlclose(handle);
|
|
|
|
|
no_handle:
|
|
|
|
|
return EGL_FALSE;
|
2011-01-07 07:02:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
/**
|
|
|
|
|
* This is the main entrypoint into the driver, called by libEGL.
|
|
|
|
|
* Create a new _EGLDriver object and init its dispatch table.
|
|
|
|
|
*/
|
|
|
|
|
_EGLDriver *
|
2012-02-05 06:01:17 +00:00
|
|
|
|
_eglBuiltInDriverDRI2(const char *args)
|
2010-02-03 15:18:28 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_driver *dri2_drv;
|
|
|
|
|
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) args;
|
|
|
|
|
|
2012-09-05 07:09:22 +01:00
|
|
|
|
dri2_drv = calloc(1, sizeof *dri2_drv);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
if (!dri2_drv)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2011-07-06 15:10:20 +01:00
|
|
|
|
if (!dri2_load(&dri2_drv->base)) {
|
|
|
|
|
free(dri2_drv);
|
2011-01-07 07:02:41 +00:00
|
|
|
|
return NULL;
|
2011-07-06 15:10:20 +01:00
|
|
|
|
}
|
2011-01-07 07:02:41 +00:00
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
_eglInitDriverFallbacks(&dri2_drv->base);
|
|
|
|
|
dri2_drv->base.API.Initialize = dri2_initialize;
|
|
|
|
|
dri2_drv->base.API.Terminate = dri2_terminate;
|
|
|
|
|
dri2_drv->base.API.CreateContext = dri2_create_context;
|
2011-08-14 08:14:17 +01:00
|
|
|
|
dri2_drv->base.API.DestroyContext = dri2_destroy_context;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
dri2_drv->base.API.MakeCurrent = dri2_make_current;
|
2014-01-29 00:39:09 +00:00
|
|
|
|
dri2_drv->base.API.CreateWindowSurface = dri2_create_window_surface;
|
2014-01-29 00:45:07 +00:00
|
|
|
|
dri2_drv->base.API.CreatePixmapSurface = dri2_create_pixmap_surface;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.CreatePbufferSurface = dri2_create_pbuffer_surface;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.DestroySurface = dri2_destroy_surface;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
dri2_drv->base.API.GetProcAddress = dri2_get_proc_address;
|
|
|
|
|
dri2_drv->base.API.WaitClient = dri2_wait_client;
|
|
|
|
|
dri2_drv->base.API.WaitNative = dri2_wait_native;
|
2010-02-09 20:49:28 +00:00
|
|
|
|
dri2_drv->base.API.BindTexImage = dri2_bind_tex_image;
|
|
|
|
|
dri2_drv->base.API.ReleaseTexImage = dri2_release_tex_image;
|
2014-01-28 20:34:19 +00:00
|
|
|
|
dri2_drv->base.API.SwapInterval = dri2_swap_interval;
|
2014-01-29 00:21:21 +00:00
|
|
|
|
dri2_drv->base.API.SwapBuffers = dri2_swap_buffers;
|
2014-01-29 00:26:44 +00:00
|
|
|
|
dri2_drv->base.API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.SwapBuffersRegionNOK = dri2_swap_buffers_region;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.PostSubBufferNV = dri2_post_sub_buffer;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.CopyBuffers = dri2_copy_buffers,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.QueryBufferAge = dri2_query_buffer_age;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.CreateImageKHR = dri2_create_image;
|
2010-02-12 00:28:26 +00:00
|
|
|
|
dri2_drv->base.API.DestroyImageKHR = dri2_destroy_image_khr;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
dri2_drv->base.API.CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image;
|
2016-07-28 18:51:12 +01:00
|
|
|
|
dri2_drv->base.API.QuerySurface = dri2_query_surface;
|
2015-01-14 19:36:04 +00:00
|
|
|
|
#ifdef HAVE_LIBDRM
|
2010-06-04 02:36:40 +01:00
|
|
|
|
dri2_drv->base.API.CreateDRMImageMESA = dri2_create_drm_image_mesa;
|
|
|
|
|
dri2_drv->base.API.ExportDRMImageMESA = dri2_export_drm_image_mesa;
|
2014-03-03 03:57:16 +00:00
|
|
|
|
dri2_drv->base.API.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa;
|
|
|
|
|
dri2_drv->base.API.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa;
|
2013-11-10 18:32:01 +00:00
|
|
|
|
#endif
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
|
|
|
|
dri2_drv->base.API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;
|
|
|
|
|
dri2_drv->base.API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl;
|
2012-07-05 21:43:04 +01:00
|
|
|
|
dri2_drv->base.API.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl;
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#endif
|
2014-05-06 20:10:57 +01:00
|
|
|
|
dri2_drv->base.API.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium;
|
2015-04-10 09:56:02 +01:00
|
|
|
|
dri2_drv->base.API.CreateSyncKHR = dri2_create_sync;
|
|
|
|
|
dri2_drv->base.API.ClientWaitSyncKHR = dri2_client_wait_sync;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
dri2_drv->base.API.SignalSyncKHR = dri2_signal_sync;
|
2015-04-10 11:04:18 +01:00
|
|
|
|
dri2_drv->base.API.WaitSyncKHR = dri2_server_wait_sync;
|
2015-04-10 09:56:02 +01:00
|
|
|
|
dri2_drv->base.API.DestroySyncKHR = dri2_destroy_sync;
|
2016-03-03 14:59:48 +00:00
|
|
|
|
dri2_drv->base.API.GLInteropQueryDeviceInfo = dri2_interop_query_device_info;
|
|
|
|
|
dri2_drv->base.API.GLInteropExportObject = dri2_interop_export_object;
|
2016-11-18 13:39:33 +00:00
|
|
|
|
dri2_drv->base.API.DupNativeFenceFDANDROID = dri2_dup_native_fence_fd;
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
|
|
|
|
dri2_drv->base.Name = "DRI2";
|
|
|
|
|
dri2_drv->base.Unload = dri2_unload;
|
|
|
|
|
|
|
|
|
|
return &dri2_drv->base;
|
|
|
|
|
}
|