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>
|
|
|
|
|
*/
|
|
|
|
|
|
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>
|
2019-02-12 18:18:03 +00:00
|
|
|
|
#include "drm-uapi/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>
|
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
|
2018-03-14 17:31:27 +00:00
|
|
|
|
#include <wayland-client.h>
|
2013-07-18 13:11:25 +01:00
|
|
|
|
#include "wayland-drm.h"
|
2014-01-29 02:53:56 +00:00
|
|
|
|
#include "wayland-drm-client-protocol.h"
|
2017-06-16 18:01:23 +01:00
|
|
|
|
#include "linux-dmabuf-unstable-v1-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
|
|
|
|
|
|
2018-05-16 14:17:30 +01:00
|
|
|
|
#include "egldefines.h"
|
2014-01-29 02:53:56 +00:00
|
|
|
|
#include "egl_dri2.h"
|
2017-07-07 02:40:53 +01:00
|
|
|
|
#include "GL/mesa_glinterop.h"
|
2016-11-09 14:50:06 +00:00
|
|
|
|
#include "loader/loader.h"
|
2020-06-05 09:22:22 +01:00
|
|
|
|
#include "util/os_file.h"
|
2015-08-07 18:55:40 +01:00
|
|
|
|
#include "util/u_atomic.h"
|
2017-06-16 18:01:23 +01:00
|
|
|
|
#include "util/u_vector.h"
|
2017-09-27 17:36:29 +01:00
|
|
|
|
#include "mapi/glapi/glapi.h"
|
2019-09-12 17:38:24 +01:00
|
|
|
|
#include "util/bitscan.h"
|
2019-12-13 16:09:56 +00:00
|
|
|
|
#include "util/u_math.h"
|
2014-01-29 02:53:56 +00:00
|
|
|
|
|
2019-02-11 08:01:35 +00:00
|
|
|
|
/* Additional definitions not yet in the drm_fourcc.h.
|
|
|
|
|
*/
|
|
|
|
|
#ifndef DRM_FORMAT_P010
|
|
|
|
|
#define DRM_FORMAT_P010 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cb:Cr plane 10 bits per channel */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef DRM_FORMAT_P012
|
|
|
|
|
#define DRM_FORMAT_P012 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cb:Cr plane 12 bits per channel */
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef DRM_FORMAT_P016
|
|
|
|
|
#define DRM_FORMAT_P016 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cb:Cr plane 16 bits per channel */
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-09-22 08:47:55 +01:00
|
|
|
|
#define NUM_ATTRIBS 12
|
2016-10-27 19:54:49 +01:00
|
|
|
|
|
2020-02-09 18:01:53 +00:00
|
|
|
|
static const struct dri2_pbuffer_visual {
|
2020-02-16 10:13:43 +00:00
|
|
|
|
const char *format_name;
|
2020-02-09 18:01:53 +00:00
|
|
|
|
unsigned int dri_image_format;
|
|
|
|
|
int rgba_shifts[4];
|
|
|
|
|
unsigned int rgba_sizes[4];
|
|
|
|
|
} dri2_pbuffer_visuals[] = {
|
|
|
|
|
{
|
2020-02-16 10:13:43 +00:00
|
|
|
|
"ABGR16F",
|
2020-02-09 18:01:53 +00:00
|
|
|
|
__DRI_IMAGE_FORMAT_ABGR16161616F,
|
|
|
|
|
{ 0, 16, 32, 48 },
|
|
|
|
|
{ 16, 16, 16, 16 }
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-16 10:13:43 +00:00
|
|
|
|
"XBGR16F",
|
2020-02-09 18:01:53 +00:00
|
|
|
|
__DRI_IMAGE_FORMAT_XBGR16161616F,
|
|
|
|
|
{ 0, 16, 32, -1 },
|
|
|
|
|
{ 16, 16, 16, 0 }
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-16 10:13:43 +00:00
|
|
|
|
"A2RGB10",
|
2020-02-09 18:01:53 +00:00
|
|
|
|
__DRI_IMAGE_FORMAT_ARGB2101010,
|
|
|
|
|
{ 20, 10, 0, 30 },
|
|
|
|
|
{ 10, 10, 10, 2 }
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-16 10:13:43 +00:00
|
|
|
|
"X2RGB10",
|
2020-02-09 18:01:53 +00:00
|
|
|
|
__DRI_IMAGE_FORMAT_XRGB2101010,
|
|
|
|
|
{ 20, 10, 0, -1 },
|
|
|
|
|
{ 10, 10, 10, 0 }
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-16 10:13:43 +00:00
|
|
|
|
"ARGB8888",
|
2020-02-09 18:01:53 +00:00
|
|
|
|
__DRI_IMAGE_FORMAT_ARGB8888,
|
|
|
|
|
{ 16, 8, 0, 24 },
|
|
|
|
|
{ 8, 8, 8, 8 }
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-16 10:13:43 +00:00
|
|
|
|
"RGB888",
|
2020-02-09 18:01:53 +00:00
|
|
|
|
__DRI_IMAGE_FORMAT_XRGB8888,
|
|
|
|
|
{ 16, 8, 0, -1 },
|
|
|
|
|
{ 8, 8, 8, 0 }
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-16 10:13:43 +00:00
|
|
|
|
"RGB565",
|
2020-02-09 18:01:53 +00:00
|
|
|
|
__DRI_IMAGE_FORMAT_RGB565,
|
|
|
|
|
{ 11, 5, 0, -1 },
|
|
|
|
|
{ 5, 6, 5, 0 }
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
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-09-26 12:16:33 +01:00
|
|
|
|
static void
|
|
|
|
|
dri2_gl_flush()
|
|
|
|
|
{
|
|
|
|
|
static void (*glFlush)(void);
|
|
|
|
|
static mtx_t glFlushMutex = _MTX_INITIALIZER_NP;
|
|
|
|
|
|
|
|
|
|
mtx_lock(&glFlushMutex);
|
|
|
|
|
if (!glFlush)
|
|
|
|
|
glFlush = _glapi_get_proc_address("glFlush");
|
|
|
|
|
mtx_unlock(&glFlushMutex);
|
|
|
|
|
|
|
|
|
|
/* if glFlush is not available things are horribly broken */
|
|
|
|
|
if (!glFlush) {
|
|
|
|
|
_eglLog(_EGL_WARNING, "DRI2: failed to find glFlush entry point");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glFlush();
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-29 12:18:27 +01:00
|
|
|
|
static GLboolean
|
|
|
|
|
dri_is_thread_safe(void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
2019-06-22 14:27:29 +01:00
|
|
|
|
UNUSED _EGLDisplay *display = dri2_surf->base.Resource.Display;
|
2017-05-29 12:18:27 +01:00
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
};
|
|
|
|
|
|
2019-07-23 21:18:21 +01:00
|
|
|
|
static void
|
|
|
|
|
dri2_get_pbuffer_drawable_info(__DRIdrawable * draw,
|
|
|
|
|
int *x, int *y, int *w, int *h,
|
|
|
|
|
void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
|
|
|
|
|
*x = *y = 0;
|
|
|
|
|
*w = dri2_surf->base.Width;
|
|
|
|
|
*h = dri2_surf->base.Height;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-13 16:09:56 +00:00
|
|
|
|
static int
|
|
|
|
|
dri2_get_bytes_per_pixel(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
const int depth = dri2_surf->base.Config->BufferSize;
|
|
|
|
|
return depth ? util_next_power_of_two(depth / 8) : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_put_image(__DRIdrawable * draw, int op,
|
|
|
|
|
int x, int y, int w, int h,
|
|
|
|
|
char *data, void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
const int bpp = dri2_get_bytes_per_pixel(dri2_surf);
|
|
|
|
|
const int width = dri2_surf->base.Width;
|
|
|
|
|
const int height = dri2_surf->base.Height;
|
|
|
|
|
const int dst_stride = width*bpp;
|
|
|
|
|
const int src_stride = w*bpp;
|
|
|
|
|
const int x_offset = x*bpp;
|
|
|
|
|
int copy_width = src_stride;
|
|
|
|
|
|
|
|
|
|
if (!dri2_surf->swrast_device_buffer)
|
|
|
|
|
dri2_surf->swrast_device_buffer = malloc(height*dst_stride);
|
|
|
|
|
|
|
|
|
|
if (dri2_surf->swrast_device_buffer) {
|
|
|
|
|
const char *src = data;
|
|
|
|
|
char *dst = dri2_surf->swrast_device_buffer;
|
|
|
|
|
|
|
|
|
|
dst += x_offset;
|
|
|
|
|
dst += y*dst_stride;
|
|
|
|
|
|
|
|
|
|
/* Drivers are allowed to submit OOB PutImage requests, so clip here. */
|
|
|
|
|
if (copy_width > dst_stride - x_offset)
|
|
|
|
|
copy_width = dst_stride - x_offset;
|
|
|
|
|
if (h > height - y)
|
|
|
|
|
h = height - y;
|
|
|
|
|
|
|
|
|
|
for (; 0 < h; --h) {
|
|
|
|
|
memcpy(dst, src, copy_width);
|
|
|
|
|
dst += dst_stride;
|
|
|
|
|
src += src_stride;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_get_image(__DRIdrawable * read,
|
|
|
|
|
int x, int y, int w, int h,
|
|
|
|
|
char *data, void *loaderPrivate)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = loaderPrivate;
|
|
|
|
|
const int bpp = dri2_get_bytes_per_pixel(dri2_surf);
|
|
|
|
|
const int width = dri2_surf->base.Width;
|
|
|
|
|
const int height = dri2_surf->base.Height;
|
|
|
|
|
const int src_stride = width*bpp;
|
|
|
|
|
const int dst_stride = w*bpp;
|
|
|
|
|
const int x_offset = x*bpp;
|
|
|
|
|
int copy_width = dst_stride;
|
|
|
|
|
const char *src = dri2_surf->swrast_device_buffer;
|
|
|
|
|
char *dst = data;
|
|
|
|
|
|
|
|
|
|
if (!src) {
|
|
|
|
|
memset(data, 0, copy_width * h);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
src += x_offset;
|
|
|
|
|
src += y*src_stride;
|
|
|
|
|
|
|
|
|
|
/* Drivers are allowed to submit OOB GetImage requests, so clip here. */
|
|
|
|
|
if (copy_width > src_stride - x_offset)
|
|
|
|
|
copy_width = src_stride - x_offset;
|
|
|
|
|
if (h > height - y)
|
|
|
|
|
h = height - y;
|
|
|
|
|
|
|
|
|
|
for (; 0 < h; --h) {
|
|
|
|
|
memcpy(dst, src, copy_width);
|
|
|
|
|
src += src_stride;
|
|
|
|
|
dst += dst_stride;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* HACK: technically we should have swrast_null, instead of these.
|
2019-07-23 21:18:21 +01:00
|
|
|
|
*/
|
|
|
|
|
const __DRIswrastLoaderExtension swrast_pbuffer_loader_extension = {
|
|
|
|
|
.base = { __DRI_SWRAST_LOADER, 1 },
|
|
|
|
|
.getDrawableInfo = dri2_get_pbuffer_drawable_info,
|
2019-12-13 16:09:56 +00:00
|
|
|
|
.putImage = dri2_put_image,
|
|
|
|
|
.getImage = dri2_get_image,
|
2019-07-23 21:18:21 +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_LUMINANCE_SIZE] = EGL_LUMINANCE_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)
|
|
|
|
|
{
|
2017-06-21 10:40:31 +01:00
|
|
|
|
const bool double_buffer = surface_type == EGL_WINDOW_BIT;
|
2015-09-13 12:25:27 +01:00
|
|
|
|
const bool srgb = colorspace == EGL_GL_COLORSPACE_SRGB_KHR;
|
|
|
|
|
|
2017-06-21 10:40:31 +01:00
|
|
|
|
return conf->dri_config[double_buffer][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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-25 00:32:48 +00:00
|
|
|
|
void
|
|
|
|
|
dri2_get_shifts_and_sizes(const __DRIcoreExtension *core,
|
|
|
|
|
const __DRIconfig *config, int *shifts,
|
|
|
|
|
unsigned int *sizes)
|
|
|
|
|
{
|
|
|
|
|
unsigned int mask;
|
|
|
|
|
|
|
|
|
|
if (core->getConfigAttrib(config, __DRI_ATTRIB_RED_SHIFT, (unsigned int *)&shifts[0])) {
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_GREEN_SHIFT, (unsigned int *)&shifts[1]);
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_BLUE_SHIFT, (unsigned int *)&shifts[2]);
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_ALPHA_SHIFT, (unsigned int *)&shifts[3]);
|
|
|
|
|
} else {
|
|
|
|
|
/* Driver isn't exposing shifts, so convert masks to shifts */
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_RED_MASK, &mask);
|
|
|
|
|
shifts[0] = ffs(mask) - 1;
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_GREEN_MASK, &mask);
|
|
|
|
|
shifts[1] = ffs(mask) - 1;
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_BLUE_MASK, &mask);
|
|
|
|
|
shifts[2] = ffs(mask) - 1;
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_ALPHA_MASK, &mask);
|
|
|
|
|
shifts[3] = ffs(mask) - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_RED_SIZE, &sizes[0]);
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_GREEN_SIZE, &sizes[1]);
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_BLUE_SIZE, &sizes[2]);
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_ALPHA_SIZE, &sizes[3]);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-25 00:55:33 +00:00
|
|
|
|
void
|
|
|
|
|
dri2_get_render_type_float(const __DRIcoreExtension *core,
|
|
|
|
|
const __DRIconfig *config,
|
|
|
|
|
bool *is_float)
|
|
|
|
|
{
|
|
|
|
|
unsigned int render_type;
|
|
|
|
|
|
|
|
|
|
core->getConfigAttrib(config, __DRI_ATTRIB_RENDER_TYPE, &render_type);
|
|
|
|
|
*is_float = (render_type & __DRI_ATTRIB_FLOAT_BIT) ? true : false;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-09 18:01:53 +00:00
|
|
|
|
unsigned int
|
|
|
|
|
dri2_image_format_for_pbuffer_config(struct dri2_egl_display *dri2_dpy,
|
|
|
|
|
const __DRIconfig *config)
|
|
|
|
|
{
|
|
|
|
|
int shifts[4];
|
|
|
|
|
unsigned int sizes[4];
|
|
|
|
|
|
|
|
|
|
dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(dri2_pbuffer_visuals); ++i) {
|
|
|
|
|
const struct dri2_pbuffer_visual *visual = &dri2_pbuffer_visuals[i];
|
|
|
|
|
|
|
|
|
|
if (shifts[0] == visual->rgba_shifts[0] &&
|
|
|
|
|
shifts[1] == visual->rgba_shifts[1] &&
|
|
|
|
|
shifts[2] == visual->rgba_shifts[2] &&
|
|
|
|
|
shifts[3] == visual->rgba_shifts[3] &&
|
|
|
|
|
sizes[0] == visual->rgba_sizes[0] &&
|
|
|
|
|
sizes[1] == visual->rgba_sizes[1] &&
|
|
|
|
|
sizes[2] == visual->rgba_sizes[2] &&
|
|
|
|
|
sizes[3] == visual->rgba_sizes[3]) {
|
|
|
|
|
return visual->dri_image_format;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return __DRI_IMAGE_FORMAT_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
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,
|
2019-01-25 00:32:48 +00:00
|
|
|
|
const int *rgba_shifts, const unsigned int *rgba_sizes)
|
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;
|
2019-01-25 00:32:48 +00:00
|
|
|
|
int dri_shifts[4] = { -1, -1, -1, -1 };
|
|
|
|
|
unsigned int dri_sizes[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
|
|
|
|
|
2010-02-10 02:01:04 +00:00
|
|
|
|
_eglInitConfig(&base, disp, id);
|
2015-06-13 08:36:27 +01:00
|
|
|
|
|
2010-07-27 23:25:54 +01:00
|
|
|
|
double_buffer = 0;
|
|
|
|
|
bind_to_texture_rgb = 0;
|
|
|
|
|
bind_to_texture_rgba = 0;
|
|
|
|
|
|
2019-01-28 18:42:44 +00:00
|
|
|
|
for (int i = 0; i < __DRI_ATTRIB_MAX; ++i) {
|
|
|
|
|
if (!dri2_dpy->core->indexConfigAttrib(dri_config, i, &attrib, &value))
|
|
|
|
|
break;
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
switch (attrib) {
|
|
|
|
|
case __DRI_ATTRIB_RENDER_TYPE:
|
2019-01-25 00:55:33 +00:00
|
|
|
|
if (value & __DRI_ATTRIB_FLOAT_BIT)
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.ComponentType = EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT;
|
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;
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.ColorBufferType = value;
|
2016-08-25 00:12:13 +01:00
|
|
|
|
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;
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.ConfigCaveat = 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
|
|
|
|
|
2019-01-25 00:32:48 +00:00
|
|
|
|
case __DRI_ATTRIB_RED_SIZE:
|
|
|
|
|
dri_sizes[0] = value;
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.RedSize = value;
|
2019-01-25 00:32:48 +00:00
|
|
|
|
break;
|
|
|
|
|
|
2011-08-05 06:36:14 +01:00
|
|
|
|
case __DRI_ATTRIB_RED_MASK:
|
2019-01-25 00:32:48 +00:00
|
|
|
|
dri_shifts[0] = ffs(value) - 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_RED_SHIFT:
|
|
|
|
|
dri_shifts[0] = value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_GREEN_SIZE:
|
|
|
|
|
dri_sizes[1] = value;
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.GreenSize = value;
|
2011-08-05 06:36:14 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_GREEN_MASK:
|
2019-01-25 00:32:48 +00:00
|
|
|
|
dri_shifts[1] = ffs(value) - 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_GREEN_SHIFT:
|
|
|
|
|
dri_shifts[1] = value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_BLUE_SIZE:
|
|
|
|
|
dri_sizes[2] = value;
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.BlueSize = value;
|
2011-08-05 06:36:14 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_BLUE_MASK:
|
2019-01-25 00:32:48 +00:00
|
|
|
|
dri_shifts[2] = ffs(value) - 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_BLUE_SHIFT:
|
|
|
|
|
dri_shifts[2] = value;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_ALPHA_SIZE:
|
|
|
|
|
dri_sizes[3] = value;
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.AlphaSize = value;
|
2011-08-05 06:36:14 +01:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_ALPHA_MASK:
|
2019-01-25 00:32:48 +00:00
|
|
|
|
dri_shifts[3] = ffs(value) - 1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case __DRI_ATTRIB_ALPHA_SHIFT:
|
|
|
|
|
dri_shifts[3] = value;
|
2011-08-05 06:36:14 +01:00
|
|
|
|
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:
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH;
|
2016-10-20 08:33:33 +01:00
|
|
|
|
break;
|
|
|
|
|
case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT:
|
2020-02-13 15:53:03 +00:00
|
|
|
|
base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT;
|
2016-10-20 08:33:33 +01:00
|
|
|
|
break;
|
2018-05-01 06:35:17 +01:00
|
|
|
|
case __DRI_ATTRIB_MUTABLE_RENDER_BUFFER:
|
|
|
|
|
if (disp->Extensions.KHR_mutable_render_buffer)
|
|
|
|
|
surface_type |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR;
|
|
|
|
|
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)
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; attr_list[i] != EGL_NONE; i += 2)
|
2011-02-09 14:30:20 +00:00
|
|
|
|
_eglSetConfigKey(&base, attr_list[i], attr_list[i+1]);
|
2010-02-10 01:49:40 +00:00
|
|
|
|
|
2019-01-25 00:32:48 +00:00
|
|
|
|
if (rgba_shifts && memcmp(rgba_shifts, dri_shifts, sizeof(dri_shifts)))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (rgba_sizes && memcmp(rgba_sizes, dri_sizes, sizeof(dri_sizes)))
|
2011-08-05 06:36:14 +01:00
|
|
|
|
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
|
|
|
|
|
2019-10-18 08:03:30 +01:00
|
|
|
|
if (double_buffer) {
|
|
|
|
|
surface_type &= ~EGL_PIXMAP_BIT;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-10 17:07:07 +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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-18 08:03:30 +01:00
|
|
|
|
if (!surface_type)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
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;
|
|
|
|
|
|
2017-06-21 10:40:31 +01:00
|
|
|
|
if (!conf->dri_config[double_buffer][srgb])
|
|
|
|
|
conf->dri_config[double_buffer][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;
|
|
|
|
|
|
2017-06-21 10:40:31 +01:00
|
|
|
|
conf->dri_config[double_buffer][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 {
|
2018-10-28 18:20:20 +00:00
|
|
|
|
unreachable("duplicates should not be possible");
|
2011-05-12 15:23:48 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-07-27 23:25:54 +01:00
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2020-02-16 10:13:43 +00:00
|
|
|
|
EGLBoolean
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_add_pbuffer_configs_for_visuals(_EGLDisplay *disp)
|
2020-02-16 10:13:43 +00:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
unsigned int format_count[ARRAY_SIZE(dri2_pbuffer_visuals)] = { 0 };
|
|
|
|
|
unsigned int config_count = 0;
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; dri2_dpy->driver_configs[i] != NULL; i++) {
|
|
|
|
|
for (unsigned j = 0; j < ARRAY_SIZE(dri2_pbuffer_visuals); j++) {
|
|
|
|
|
struct dri2_egl_config *dri2_conf;
|
|
|
|
|
|
|
|
|
|
dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],
|
|
|
|
|
config_count + 1, EGL_PBUFFER_BIT, NULL,
|
|
|
|
|
dri2_pbuffer_visuals[j].rgba_shifts, dri2_pbuffer_visuals[j].rgba_sizes);
|
|
|
|
|
|
|
|
|
|
if (dri2_conf) {
|
|
|
|
|
if (dri2_conf->base.ConfigID == config_count + 1)
|
|
|
|
|
config_count++;
|
|
|
|
|
format_count[j]++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {
|
|
|
|
|
if (!format_count[i]) {
|
|
|
|
|
_eglLog(_EGL_DEBUG, "No DRI config supports native format %s",
|
|
|
|
|
dri2_pbuffer_visuals[i].format_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (config_count != 0);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
2019-01-23 17:15:42 +00:00
|
|
|
|
static const struct dri2_extension_match optional_driver_extensions[] = {
|
|
|
|
|
{ __DRI_CONFIG_OPTIONS, 1, offsetof(struct dri2_egl_display, configOptions) },
|
|
|
|
|
{ NULL, 0, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
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) },
|
2017-06-29 01:44:03 +01:00
|
|
|
|
{ __DRI2_NO_ERROR, 1, offsetof(struct dri2_egl_display, no_error) },
|
2016-08-25 00:51:05 +01:00
|
|
|
|
{ __DRI2_CONFIG_QUERY, 1, offsetof(struct dri2_egl_display, config) },
|
|
|
|
|
{ __DRI2_FENCE, 1, offsetof(struct dri2_egl_display, fence) },
|
2019-08-12 11:07:06 +01:00
|
|
|
|
{ __DRI2_BUFFER_DAMAGE, 1, offsetof(struct dri2_egl_display, buffer_damage) },
|
2016-08-25 00:51:05 +01:00
|
|
|
|
{ __DRI2_RENDERER_QUERY, 1, offsetof(struct dri2_egl_display, rendererQuery) },
|
|
|
|
|
{ __DRI2_INTEROP, 1, offsetof(struct dri2_egl_display, interop) },
|
2017-08-01 22:51:40 +01:00
|
|
|
|
{ __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
|
2016-09-22 08:47:55 +01:00
|
|
|
|
{ __DRI2_FLUSH_CONTROL, 1, offsetof(struct dri2_egl_display, flush_control) },
|
2017-12-28 08:51:11 +00:00
|
|
|
|
{ __DRI2_BLOB, 1, offsetof(struct dri2_egl_display, blob) },
|
2018-05-01 06:35:17 +01:00
|
|
|
|
{ __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1, offsetof(struct dri2_egl_display, mutable_render_buffer) },
|
2016-08-25 00:51:05 +01:00
|
|
|
|
{ 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
|
|
|
|
{
|
2017-06-22 19:00:40 +01:00
|
|
|
|
int ret = EGL_TRUE;
|
2010-02-09 15:57:43 +00:00
|
|
|
|
void *field;
|
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; extensions[i]; i++) {
|
2015-10-30 15:16:35 +00:00
|
|
|
|
_eglLog(_EGL_DEBUG, "found extension `%s'", extensions[i]->name);
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int 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
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int j = 0; matches[j].name; j++) {
|
2010-02-09 15:57:43 +00:00
|
|
|
|
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);
|
2018-11-15 21:54:49 +00:00
|
|
|
|
static const char *search_path_vars[] = {
|
|
|
|
|
"LIBGL_DRIVERS_PATH",
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return loader_open_driver(dri2_dpy->driver_name,
|
|
|
|
|
&dri2_dpy->driver,
|
|
|
|
|
search_path_vars);
|
2011-06-08 09:33:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
2019-02-05 15:19:46 +00:00
|
|
|
|
static EGLBoolean
|
|
|
|
|
dri2_load_driver_common(_EGLDisplay *disp,
|
|
|
|
|
const struct dri2_extension_match *driver_extensions)
|
2015-07-21 16:44:00 +01:00
|
|
|
|
{
|
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;
|
|
|
|
|
|
2020-03-05 13:05:36 +00:00
|
|
|
|
if (!dri2_bind_extensions(dri2_dpy, driver_extensions, extensions, false)) {
|
|
|
|
|
dlclose(dri2_dpy->driver);
|
|
|
|
|
dri2_dpy->driver = NULL;
|
2015-07-21 16:44:00 +01:00
|
|
|
|
return EGL_FALSE;
|
2020-03-05 13:05:36 +00:00
|
|
|
|
}
|
2015-07-21 16:44:00 +01:00
|
|
|
|
dri2_dpy->driver_extensions = extensions;
|
|
|
|
|
|
2019-01-23 17:15:42 +00:00
|
|
|
|
dri2_bind_extensions(dri2_dpy, optional_driver_extensions, extensions, true);
|
|
|
|
|
|
2015-07-21 16:44:00 +01:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-08 09:33:55 +01:00
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_load_driver(_EGLDisplay *disp)
|
|
|
|
|
{
|
2019-02-05 15:19:46 +00:00
|
|
|
|
return dri2_load_driver_common(disp, dri2_driver_extensions);
|
|
|
|
|
}
|
2019-01-23 17:15:42 +00:00
|
|
|
|
|
2019-02-05 15:19:46 +00:00
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_load_driver_dri3(_EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
return dri2_load_driver_common(disp, dri3_driver_extensions);
|
2011-06-08 09:33:55 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_load_driver_swrast(_EGLDisplay *disp)
|
|
|
|
|
{
|
2019-02-05 15:19:46 +00:00
|
|
|
|
return dri2_load_driver_common(disp, swrast_driver_extensions);
|
2010-05-28 21:16:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-23 17:15:42 +00:00
|
|
|
|
static const char *
|
|
|
|
|
dri2_query_driver_name(_EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
return dri2_dpy->driver_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
|
|
|
|
dri2_query_driver_config(_EGLDisplay *disp)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
const __DRIconfigOptionsExtension *ext = dri2_dpy->configOptions;
|
|
|
|
|
|
|
|
|
|
if (ext->base.version >= 2)
|
|
|
|
|
return ext->getXml(dri2_dpy->driver_name);
|
|
|
|
|
|
|
|
|
|
return strdup(ext->xml);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
egl/dri2: Implement swapInterval fallback in a conformant way (v2)
dri2_fallback_swap_interval() currently used to stub out swap interval
support in Android backend does nothing besides returning EGL_FALSE.
This causes at least one known application (Android Snapchat) to fail
due to an unexpected error and my loose interpretation of the EGL 1.5
specification justifies it. Relevant quote below:
The function
EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval);
specifies the minimum number of video frame periods per buffer swap
for the draw surface of the current context, for the current rendering
API. [...]
The parameter interval specifies the minimum number of video frames
that are displayed before a buffer swap will occur. The interval
specified by the function applies to the draw surface bound to the
context that is current on the calling thread. [...] interval is
silently clamped to minimum and maximum implementation dependent
values before being stored; these values are defined by EGLConfig
attributes EGL_MIN_SWAP_INTERVAL and EGL_MAX_SWAP_INTERVAL
respectively.
The default swap interval is 1.
Even though it does not specify the exact behavior if the platform does
not support changing the swap interval, the default assumed state is the
swap interval of 1, which I interpret as a value that eglSwapInterval()
should succeed if called with, even if there is no ability to change the
interval (but there is no change requested). Moreover, since the
behavior is defined to clamp the requested value to minimum and maximum
and at least the default value of 1 must be present in the range, the
implementation might be expected to have a valid range, which in case of
the feature being unsupported, would correspond to {1} and any request
might be expected to be clamped to this value.
Fix this by defaulting dri2_dpy's min_swap_interval, max_swap_interval
and default_swap_interval to 1 in dri2_setup_screen() and let platforms,
which support this functionality set their own values after this
function returns. Thanks to patches merged earlier, we can also remove
the dri2_fallback_swap_interval() completely, as with a singular range
it would not be called anyway.
v2: Remove dri2_fallback_swap_interval() completely thanks to higher
layer already clamping the requested interval and not calling the
driver layer if the clamped value is the same as current.
Signed-off-by: Tomasz Figa <tfiga@chromium.org>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Reviewed-by: Chad Versace <chadversary@chromium.org>
Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
2017-08-10 14:59:45 +01:00
|
|
|
|
/*
|
|
|
|
|
* EGL 1.5 specification defines the default value to 1. Moreover,
|
|
|
|
|
* eglSwapInterval() is required to clamp requested value to the supported
|
|
|
|
|
* range. Since the default value is implicitly assumed to be supported,
|
|
|
|
|
* use it as both minimum and maximum for the platforms that do not allow
|
|
|
|
|
* changing the interval. Platforms, which allow it (e.g. x11, wayland)
|
|
|
|
|
* override these values already.
|
|
|
|
|
*/
|
|
|
|
|
dri2_dpy->min_swap_interval = 1;
|
|
|
|
|
dri2_dpy->max_swap_interval = 1;
|
|
|
|
|
dri2_dpy->default_swap_interval = 1;
|
|
|
|
|
|
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
|
|
|
|
|
2019-01-23 17:15:42 +00:00
|
|
|
|
if (dri2_dpy->configOptions) {
|
|
|
|
|
disp->Extensions.MESA_query_driver = EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 19:34:46 +01:00
|
|
|
|
/* Report back to EGL the bitmask of priorities supported */
|
|
|
|
|
disp->Extensions.IMG_context_priority =
|
|
|
|
|
dri2_renderer_query_integer(dri2_dpy,
|
|
|
|
|
__DRI2_RENDERER_HAS_CONTEXT_PRIORITY);
|
|
|
|
|
|
2017-10-31 08:57:42 +00:00
|
|
|
|
disp->Extensions.EXT_pixel_format_float = EGL_TRUE;
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-29 01:44:03 +01:00
|
|
|
|
if (dri2_dpy->no_error)
|
|
|
|
|
disp->Extensions.KHR_create_context_no_error = 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;
|
2017-08-07 17:23:19 +01:00
|
|
|
|
if (dri2_dpy->fence->base.version >= 2 &&
|
|
|
|
|
dri2_dpy->fence->get_capabilities) {
|
2016-11-18 13:39:33 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2017-12-28 08:51:11 +00:00
|
|
|
|
if (dri2_dpy->blob)
|
|
|
|
|
disp->Extensions.ANDROID_blob_cache = EGL_TRUE;
|
|
|
|
|
|
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;
|
2017-06-28 16:41:30 +01:00
|
|
|
|
|
|
|
|
|
if (dri2_renderer_query_integer(dri2_dpy,
|
|
|
|
|
__DRI2_RENDERER_HAS_TEXTURE_3D))
|
|
|
|
|
disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE;
|
2012-11-27 13:19:54 +00:00
|
|
|
|
}
|
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;
|
2017-05-30 12:53:40 +01:00
|
|
|
|
disp->Extensions.EXT_image_dma_buf_import_modifiers = EGL_TRUE;
|
|
|
|
|
}
|
2013-11-10 18:32:01 +00:00
|
|
|
|
#endif
|
2011-03-08 01:18:29 +00:00
|
|
|
|
}
|
2016-09-22 08:47:55 +01:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->flush_control)
|
|
|
|
|
disp->Extensions.KHR_context_flush_control = EGL_TRUE;
|
2019-08-12 11:07:06 +01:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->buffer_damage && dri2_dpy->buffer_damage->set_damage_region)
|
|
|
|
|
disp->Extensions.KHR_partial_update = EGL_TRUE;
|
2011-05-30 09:50:52 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-05 00:25:46 +01:00
|
|
|
|
void
|
|
|
|
|
dri2_setup_swap_interval(_EGLDisplay *disp, int max_swap_interval)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
|
|
|
|
|
|
|
|
|
|
/* Allow driconf to override applications.*/
|
|
|
|
|
if (dri2_dpy->config)
|
|
|
|
|
dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
|
|
|
|
|
"vblank_mode", &vblank_mode);
|
|
|
|
|
switch (vblank_mode) {
|
|
|
|
|
case DRI_CONF_VBLANK_NEVER:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = 0;
|
|
|
|
|
dri2_dpy->default_swap_interval = 0;
|
|
|
|
|
break;
|
|
|
|
|
case DRI_CONF_VBLANK_ALWAYS_SYNC:
|
|
|
|
|
dri2_dpy->min_swap_interval = 1;
|
|
|
|
|
dri2_dpy->max_swap_interval = max_swap_interval;
|
|
|
|
|
dri2_dpy->default_swap_interval = 1;
|
|
|
|
|
break;
|
|
|
|
|
case DRI_CONF_VBLANK_DEF_INTERVAL_0:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = max_swap_interval;
|
|
|
|
|
dri2_dpy->default_swap_interval = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
case DRI_CONF_VBLANK_DEF_INTERVAL_1:
|
|
|
|
|
dri2_dpy->min_swap_interval = 0;
|
|
|
|
|
dri2_dpy->max_swap_interval = max_swap_interval;
|
|
|
|
|
dri2_dpy->default_swap_interval = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-19 00:16:21 +01:00
|
|
|
|
dri2_dpy->own_dri_screen = true;
|
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
|
|
|
|
|
2018-03-19 15:03:22 +00:00
|
|
|
|
#ifdef HAVE_DRI3_MODIFIERS
|
2017-07-07 07:54:26 +01:00
|
|
|
|
dri2_dpy->multibuffers_available =
|
|
|
|
|
(dri2_dpy->dri3_major_version > 1 || (dri2_dpy->dri3_major_version == 1 &&
|
|
|
|
|
dri2_dpy->dri3_minor_version >= 2)) &&
|
2017-10-06 06:26:51 +01:00
|
|
|
|
(dri2_dpy->present_major_version > 1 || (dri2_dpy->present_major_version == 1 &&
|
|
|
|
|
dri2_dpy->present_minor_version >= 2)) &&
|
2017-07-07 07:54:26 +01:00
|
|
|
|
(dri2_dpy->image && dri2_dpy->image->base.version >= 15);
|
|
|
|
|
#endif
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglInitialize(), drv->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
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_initialize(_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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-15 22:47:30 +00:00
|
|
|
|
loader_set_logger(_eglLog);
|
|
|
|
|
|
2010-06-03 03:48:06 +01:00
|
|
|
|
switch (disp->Platform) {
|
2015-06-12 18:10:58 +01:00
|
|
|
|
case _EGL_PLATFORM_SURFACELESS:
|
2018-04-22 15:48:15 +01:00
|
|
|
|
ret = dri2_initialize_surfaceless(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;
|
2019-05-16 18:01:40 +01:00
|
|
|
|
case _EGL_PLATFORM_DEVICE:
|
2018-04-22 15:48:15 +01:00
|
|
|
|
ret = dri2_initialize_device(disp);
|
2019-05-16 18:01:40 +01:00
|
|
|
|
break;
|
2010-06-03 03:48:06 +01:00
|
|
|
|
case _EGL_PLATFORM_X11:
|
2018-04-22 15:48:15 +01:00
|
|
|
|
ret = dri2_initialize_x11(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
|
|
|
|
case _EGL_PLATFORM_DRM:
|
2018-04-22 15:48:15 +01:00
|
|
|
|
ret = dri2_initialize_drm(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
|
|
|
|
case _EGL_PLATFORM_WAYLAND:
|
2018-04-22 15:48:15 +01:00
|
|
|
|
ret = dri2_initialize_wayland(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-08-05 06:39:18 +01:00
|
|
|
|
case _EGL_PLATFORM_ANDROID:
|
2018-04-22 15:48:15 +01:00
|
|
|
|
ret = dri2_initialize_android(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
|
|
|
|
default:
|
2017-11-09 17:55:19 +00:00
|
|
|
|
unreachable("Callers ensure we cannot get here.");
|
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
|
|
|
|
|
2017-08-27 11:20:26 +01:00
|
|
|
|
if (!ret)
|
|
|
|
|
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
|
|
|
|
|
2017-08-27 11:20:26 +01:00
|
|
|
|
dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
dri2_dpy->ref_count++;
|
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
|
|
|
|
|
2017-08-27 11:20:26 +01:00
|
|
|
|
return EGL_TRUE;
|
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);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2017-08-10 14:35:39 +01:00
|
|
|
|
if (dri2_dpy->own_dri_screen) {
|
2018-02-22 13:37:54 +00:00
|
|
|
|
if (dri2_dpy->vtbl && dri2_dpy->vtbl->close_screen_notify)
|
2017-08-10 14:35:39 +01:00
|
|
|
|
dri2_dpy->vtbl->close_screen_notify(disp);
|
2011-06-27 09:23:34 +01:00
|
|
|
|
dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
|
2017-08-10 14:35:39 +01:00
|
|
|
|
}
|
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) {
|
|
|
|
|
case _EGL_PLATFORM_X11:
|
2017-11-09 18:58:52 +00:00
|
|
|
|
dri2_teardown_x11(dri2_dpy);
|
2014-01-29 02:53:56 +00:00
|
|
|
|
break;
|
|
|
|
|
case _EGL_PLATFORM_DRM:
|
2017-11-16 18:33:22 +00:00
|
|
|
|
dri2_teardown_drm(dri2_dpy);
|
2014-01-29 02:53:56 +00:00
|
|
|
|
break;
|
|
|
|
|
case _EGL_PLATFORM_WAYLAND:
|
2017-11-16 18:33:22 +00:00
|
|
|
|
dri2_teardown_wayland(dri2_dpy);
|
2014-01-29 02:53:56 +00:00
|
|
|
|
break;
|
|
|
|
|
default:
|
2017-11-13 14:02:56 +00:00
|
|
|
|
/* TODO: add teardown for other platforms */
|
2014-01-29 02:53:56 +00:00
|
|
|
|
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) {
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++)
|
2014-11-07 03:33:56 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2017-08-04 16:16:11 +01:00
|
|
|
|
__DRIbuffer *
|
|
|
|
|
dri2_egl_surface_alloc_local_buffer(struct dri2_egl_surface *dri2_surf,
|
|
|
|
|
unsigned int att, unsigned int format)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
|
|
|
|
|
if (att >= ARRAY_SIZE(dri2_surf->local_buffers))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (!dri2_surf->local_buffers[att]) {
|
|
|
|
|
dri2_surf->local_buffers[att] =
|
|
|
|
|
dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format,
|
|
|
|
|
dri2_surf->base.Width, dri2_surf->base.Height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return dri2_surf->local_buffers[att];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dri2_egl_surface_free_local_buffers(struct dri2_egl_surface *dri2_surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy =
|
|
|
|
|
dri2_egl_display(dri2_surf->base.Resource.Display);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) {
|
|
|
|
|
if (dri2_surf->local_buffers[i]) {
|
|
|
|
|
dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
|
|
|
|
|
dri2_surf->local_buffers[i]);
|
|
|
|
|
dri2_surf->local_buffers[i] = 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
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglTerminate(), drv->Terminate().
|
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 eglTerminate is
|
|
|
|
|
* called many times (without a eglInitialize in between).
|
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2018-04-22 15:48:15 +01:00
|
|
|
|
dri2_terminate(_EGLDisplay *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
|
|
|
|
{
|
|
|
|
|
/* Release all non-current Context/Surfaces. */
|
2018-04-22 15:48:15 +01:00
|
|
|
|
_eglReleaseDisplayResources(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
|
|
|
|
|
|
|
|
|
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:
|
2018-10-28 18:20:20 +00:00
|
|
|
|
assert(!"unknown dri_error code");
|
2012-11-09 22:06:41 +00:00
|
|
|
|
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;
|
|
|
|
|
|
2016-10-27 19:54:49 +01:00
|
|
|
|
assert(*num_attribs >= NUM_ATTRIBS);
|
2015-07-21 16:43:56 +01:00
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2017-06-29 01:44:03 +01:00
|
|
|
|
if (dri2_ctx->base.Flags != 0 || dri2_ctx->base.NoError) {
|
2015-07-21 16:43:56 +01:00
|
|
|
|
/* 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;
|
2017-06-29 01:44:03 +01:00
|
|
|
|
ctx_attribs[pos++] = dri2_ctx->base.Flags |
|
2017-07-14 22:26:42 +01:00
|
|
|
|
(dri2_ctx->base.NoError ? __DRI_CTX_FLAG_NO_ERROR : 0);
|
2015-07-21 16:43:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 19:54:49 +01:00
|
|
|
|
if (dri2_ctx->base.ContextPriority != EGL_CONTEXT_PRIORITY_MEDIUM_IMG) {
|
|
|
|
|
unsigned val;
|
|
|
|
|
|
|
|
|
|
switch (dri2_ctx->base.ContextPriority) {
|
|
|
|
|
case EGL_CONTEXT_PRIORITY_HIGH_IMG:
|
|
|
|
|
val = __DRI_CTX_PRIORITY_HIGH;
|
|
|
|
|
break;
|
|
|
|
|
case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
|
|
|
|
|
val = __DRI_CTX_PRIORITY_MEDIUM;
|
|
|
|
|
break;
|
|
|
|
|
case EGL_CONTEXT_PRIORITY_LOW_IMG:
|
|
|
|
|
val = __DRI_CTX_PRIORITY_LOW;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
_eglError(EGL_BAD_CONFIG, "eglCreateContext");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_ATTRIB_PRIORITY;
|
|
|
|
|
ctx_attribs[pos++] = val;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-22 08:47:55 +01:00
|
|
|
|
if (dri2_ctx->base.ReleaseBehavior == EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR) {
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
|
|
|
|
|
ctx_attribs[pos++] = __DRI_CTX_RELEASE_BEHAVIOR_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-21 16:43:56 +01:00
|
|
|
|
*num_attribs = pos;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglCreateContext(), drv->CreateContext().
|
2010-02-03 15:18:28 +00:00
|
|
|
|
*/
|
|
|
|
|
static _EGLContext *
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_context(const _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;
|
2016-09-22 08:38:01 +01:00
|
|
|
|
unsigned error;
|
|
|
|
|
unsigned num_attribs = NUM_ATTRIBS;
|
|
|
|
|
uint32_t ctx_attribs[NUM_ATTRIBS];
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-29 01:44:03 +01:00
|
|
|
|
/* The EGL_KHR_create_context_no_error spec says:
|
|
|
|
|
*
|
|
|
|
|
* "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
|
|
|
|
|
* used to create <share_context> does not match the value of
|
|
|
|
|
* EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created."
|
|
|
|
|
*/
|
|
|
|
|
if (share_list && share_list->NoError != dri2_ctx->base.NoError) {
|
|
|
|
|
_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;
|
2019-08-02 02:38:45 +01:00
|
|
|
|
else if (dri2_ctx->base.ClientMajorVersion == 3 &&
|
|
|
|
|
dri2_ctx->base.ClientMinorVersion == 1)
|
|
|
|
|
api = __DRI_API_OPENGL_CORE;
|
2012-07-20 00:04:01 +01:00
|
|
|
|
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()
|
|
|
|
|
*/
|
2017-06-21 10:40:31 +01:00
|
|
|
|
if (dri2_config->dri_config[1][0])
|
|
|
|
|
dri_config = dri2_config->dri_config[1][0];
|
2011-02-09 14:30:20 +00:00
|
|
|
|
else
|
2017-06-21 10:40:31 +01:00
|
|
|
|
dri_config = dri2_config->dri_config[0][0];
|
2011-02-09 14:30:20 +00:00
|
|
|
|
}
|
2010-07-27 23:25:54 +01:00
|
|
|
|
else
|
|
|
|
|
dri_config = NULL;
|
|
|
|
|
|
2016-09-22 08:38:01 +01:00
|
|
|
|
if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,
|
|
|
|
|
&num_attribs))
|
|
|
|
|
goto cleanup;
|
2015-07-21 16:44:00 +01:00
|
|
|
|
|
2016-09-22 08:38:01 +01:00
|
|
|
|
if (dri2_dpy->image_driver) {
|
2015-07-21 16:44:00 +01:00
|
|
|
|
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) {
|
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) {
|
|
|
|
|
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
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglDestroyContext(), drv->DestroyContext().
|
2011-08-14 08:14:17 +01:00
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_destroy_context(const _EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
|
2011-08-14 08:14:17 +01:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-15 18:32:42 +01:00
|
|
|
|
EGLBoolean
|
2019-02-02 11:38:45 +00:00
|
|
|
|
dri2_init_surface(_EGLSurface *surf, _EGLDisplay *disp, EGLint type,
|
2019-05-01 23:42:26 +01:00
|
|
|
|
_EGLConfig *conf, const EGLint *attrib_list,
|
|
|
|
|
EGLBoolean enable_out_fence, void *native_surface)
|
2017-09-15 18:32:42 +01:00
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2017-09-15 18:32:42 +01:00
|
|
|
|
|
|
|
|
|
dri2_surf->out_fence_fd = -1;
|
|
|
|
|
dri2_surf->enable_out_fence = false;
|
|
|
|
|
if (dri2_dpy->fence && dri2_dpy->fence->base.version >= 2 &&
|
|
|
|
|
dri2_dpy->fence->get_capabilities &&
|
|
|
|
|
(dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen) &
|
|
|
|
|
__DRI_FENCE_CAP_NATIVE_FD)) {
|
|
|
|
|
dri2_surf->enable_out_fence = enable_out_fence;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 23:42:26 +01:00
|
|
|
|
return _eglInitSurface(surf, disp, type, conf, attrib_list, native_surface);
|
2017-09-15 18:32:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dri2_surface_set_out_fence_fd( _EGLSurface *surf, int fence_fd)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
|
|
|
|
|
|
|
|
|
|
if (dri2_surf->out_fence_fd >= 0)
|
|
|
|
|
close(dri2_surf->out_fence_fd);
|
|
|
|
|
|
|
|
|
|
dri2_surf->out_fence_fd = fence_fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
dri2_fini_surface(_EGLSurface *surf)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
|
|
|
|
|
|
|
|
|
|
dri2_surface_set_out_fence_fd(surf, -1);
|
|
|
|
|
dri2_surf->enable_out_fence = false;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-18 16:33:39 +01:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_destroy_surface(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
|
2016-08-18 16:33:39 +01:00
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2016-08-18 16:33:39 +01:00
|
|
|
|
|
|
|
|
|
if (!_eglPutSurface(surf))
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->destroy_surface(drv, disp, surf);
|
2016-08-18 16:33:39 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-15 18:32:42 +01:00
|
|
|
|
static void
|
|
|
|
|
dri2_surf_update_fence_fd(_EGLContext *ctx,
|
2019-02-02 11:38:45 +00:00
|
|
|
|
_EGLDisplay *disp, _EGLSurface *surf)
|
2017-09-15 18:32:42 +01:00
|
|
|
|
{
|
|
|
|
|
__DRIcontext *dri_ctx = dri2_egl_context(ctx)->dri_context;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2017-09-15 18:32:42 +01:00
|
|
|
|
struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
|
|
|
|
|
int fence_fd = -1;
|
|
|
|
|
void *fence;
|
|
|
|
|
|
|
|
|
|
if (!dri2_surf->enable_out_fence)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fence = dri2_dpy->fence->create_fence_fd(dri_ctx, -1);
|
|
|
|
|
if (fence) {
|
|
|
|
|
fence_fd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen,
|
|
|
|
|
fence);
|
|
|
|
|
dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, fence);
|
|
|
|
|
}
|
|
|
|
|
dri2_surface_set_out_fence_fd(surf, fence_fd);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-16 18:01:38 +01:00
|
|
|
|
EGLBoolean
|
|
|
|
|
dri2_create_drawable(struct dri2_egl_display *dri2_dpy,
|
|
|
|
|
const __DRIconfig *config,
|
2019-06-07 06:12:42 +01:00
|
|
|
|
struct dri2_egl_surface *dri2_surf,
|
|
|
|
|
void *loaderPrivate)
|
2019-05-16 18:01:38 +01:00
|
|
|
|
{
|
|
|
|
|
__DRIcreateNewDrawableFunc createNewDrawable;
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->image_driver)
|
|
|
|
|
createNewDrawable = dri2_dpy->image_driver->createNewDrawable;
|
|
|
|
|
else if (dri2_dpy->dri2)
|
|
|
|
|
createNewDrawable = dri2_dpy->dri2->createNewDrawable;
|
|
|
|
|
else if (dri2_dpy->swrast)
|
|
|
|
|
createNewDrawable = dri2_dpy->swrast->createNewDrawable;
|
|
|
|
|
else
|
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "no createNewDrawable");
|
|
|
|
|
|
2018-11-27 12:48:42 +00:00
|
|
|
|
dri2_surf->dri_drawable = createNewDrawable(dri2_dpy->dri_screen,
|
|
|
|
|
config, loaderPrivate);
|
2019-05-16 18:01:38 +01:00
|
|
|
|
if (dri2_surf->dri_drawable == NULL)
|
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "createNewDrawable");
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
/**
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called via eglMakeCurrent(), drv->MakeCurrent().
|
2010-02-03 15:18:28 +00:00
|
|
|
|
*/
|
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_make_current(const _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
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
|
2018-05-01 06:35:17 +01:00
|
|
|
|
_EGLDisplay *old_disp = NULL;
|
|
|
|
|
struct dri2_egl_display *old_dri2_dpy = NULL;
|
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;
|
egl/dri2: try to bind old context if bindContext failed
This change mostly touches error handling code paths, where a
bug was found when the DRI driver failed to bind a new DRI
context. Specifically, the reason for it to fail was the window
system unable (for whatever reason) to provide the DRI drawable
with a buffer. In this instance, Mesa un-does the EGL bindings,
but doesn't restore the old DRI context, hence remaining in a
funny state. It's worth mentioning that despite trying, there
is no guarantee that the old DRI context can be restored,
depending on the runtime.
Before this change, if bindContext() failed then
dri2_make_current() would rebind the old EGL context and
surfaces and return EGL_BAD_MATCH. However, it wouldn't rebind
the DRI context and surfaces, thus leaving it in an
inconsistent and unrecoverable state.
After this change, dri2_make_current() tries to bind the old
DRI context and surfaces when bindContext() failed. If unable
to do so, it leaves EGL and the DRI driver in a consistent
state, it reports an error and returns EGL_BAD_MATCH.
Fixes: 4e8f95f64d004aa1 ("egl_dri2: Always unbind old contexts")
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5707>
2020-06-30 14:59:45 +01:00
|
|
|
|
EGLint egl_error = EGL_SUCCESS;
|
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
|
|
|
|
|
2020-06-30 10:14:08 +01:00
|
|
|
|
/* make new bindings, set the EGL error otherwise */
|
|
|
|
|
if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf))
|
2010-02-03 15:18:28 +00:00
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2018-05-01 06:35:17 +01:00
|
|
|
|
if (old_ctx) {
|
2020-06-30 10:14:08 +01:00
|
|
|
|
__DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
|
2018-05-01 06:35:17 +01:00
|
|
|
|
old_disp = old_ctx->Resource.Display;
|
|
|
|
|
old_dri2_dpy = dri2_egl_display(old_disp);
|
|
|
|
|
|
2020-06-30 10:14:08 +01:00
|
|
|
|
/* flush before context switch */
|
2017-09-26 12:16:33 +01:00
|
|
|
|
dri2_gl_flush();
|
2016-10-14 16:07:33 +01:00
|
|
|
|
|
2017-09-15 18:32:42 +01:00
|
|
|
|
if (old_dsurf)
|
|
|
|
|
dri2_surf_update_fence_fd(old_ctx, disp, old_dsurf);
|
2018-05-01 06:35:17 +01:00
|
|
|
|
|
|
|
|
|
/* Disable shared buffer mode */
|
|
|
|
|
if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
|
|
|
|
|
old_dri2_dpy->vtbl->set_shared_buffer_mode) {
|
|
|
|
|
old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-16 13:47:25 +01:00
|
|
|
|
dri2_dpy->core->unbindContext(old_cctx);
|
|
|
|
|
}
|
2010-02-03 15:18:28 +00:00
|
|
|
|
|
2020-06-30 10:14:08 +01:00
|
|
|
|
ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL;
|
|
|
|
|
rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL;
|
|
|
|
|
cctx = (dri2_ctx) ? dri2_ctx->dri_context : 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
|
|
|
|
|
2020-06-30 11:32:49 +01:00
|
|
|
|
if (cctx || ddraw || rdraw) {
|
|
|
|
|
if (!dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
|
egl/dri2: try to bind old context if bindContext failed
This change mostly touches error handling code paths, where a
bug was found when the DRI driver failed to bind a new DRI
context. Specifically, the reason for it to fail was the window
system unable (for whatever reason) to provide the DRI drawable
with a buffer. In this instance, Mesa un-does the EGL bindings,
but doesn't restore the old DRI context, hence remaining in a
funny state. It's worth mentioning that despite trying, there
is no guarantee that the old DRI context can be restored,
depending on the runtime.
Before this change, if bindContext() failed then
dri2_make_current() would rebind the old EGL context and
surfaces and return EGL_BAD_MATCH. However, it wouldn't rebind
the DRI context and surfaces, thus leaving it in an
inconsistent and unrecoverable state.
After this change, dri2_make_current() tries to bind the old
DRI context and surfaces when bindContext() failed. If unable
to do so, it leaves EGL and the DRI driver in a consistent
state, it reports an error and returns EGL_BAD_MATCH.
Fixes: 4e8f95f64d004aa1 ("egl_dri2: Always unbind old contexts")
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5707>
2020-06-30 14:59:45 +01:00
|
|
|
|
_EGLContext *tmp_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.
|
|
|
|
|
*/
|
|
|
|
|
egl_error = EGL_BAD_MATCH;
|
|
|
|
|
|
2020-06-30 11:32:49 +01:00
|
|
|
|
/* 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);
|
2018-05-01 06:35:17 +01:00
|
|
|
|
|
2020-06-30 11:32:49 +01:00
|
|
|
|
_eglPutSurface(old_dsurf);
|
|
|
|
|
_eglPutSurface(old_rsurf);
|
|
|
|
|
_eglPutContext(old_ctx);
|
2016-10-14 16:07:33 +01:00
|
|
|
|
|
egl/dri2: try to bind old context if bindContext failed
This change mostly touches error handling code paths, where a
bug was found when the DRI driver failed to bind a new DRI
context. Specifically, the reason for it to fail was the window
system unable (for whatever reason) to provide the DRI drawable
with a buffer. In this instance, Mesa un-does the EGL bindings,
but doesn't restore the old DRI context, hence remaining in a
funny state. It's worth mentioning that despite trying, there
is no guarantee that the old DRI context can be restored,
depending on the runtime.
Before this change, if bindContext() failed then
dri2_make_current() would rebind the old EGL context and
surfaces and return EGL_BAD_MATCH. However, it wouldn't rebind
the DRI context and surfaces, thus leaving it in an
inconsistent and unrecoverable state.
After this change, dri2_make_current() tries to bind the old
DRI context and surfaces when bindContext() failed. If unable
to do so, it leaves EGL and the DRI driver in a consistent
state, it reports an error and returns EGL_BAD_MATCH.
Fixes: 4e8f95f64d004aa1 ("egl_dri2: Always unbind old contexts")
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5707>
2020-06-30 14:59:45 +01:00
|
|
|
|
ddraw = (old_dsurf) ? dri2_dpy->vtbl->get_dri_drawable(old_dsurf) : NULL;
|
|
|
|
|
rdraw = (old_rsurf) ? dri2_dpy->vtbl->get_dri_drawable(old_rsurf) : NULL;
|
|
|
|
|
cctx = (old_ctx) ? dri2_egl_context(old_ctx)->dri_context : NULL;
|
|
|
|
|
|
|
|
|
|
/* undo the previous dri2_dpy->core->unbindContext */
|
|
|
|
|
if (dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
|
|
|
|
|
if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
|
|
|
|
|
old_dri2_dpy->vtbl->set_shared_buffer_mode) {
|
|
|
|
|
old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return _eglError(egl_error, "eglMakeCurrent");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We cannot restore the same state as it was before calling
|
|
|
|
|
* eglMakeCurrent() and the spec isn't clear about what to do. We
|
|
|
|
|
* can prevent EGL from calling into the DRI driver with no DRI
|
|
|
|
|
* context bound.
|
2020-06-30 11:32:49 +01:00
|
|
|
|
*/
|
egl/dri2: try to bind old context if bindContext failed
This change mostly touches error handling code paths, where a
bug was found when the DRI driver failed to bind a new DRI
context. Specifically, the reason for it to fail was the window
system unable (for whatever reason) to provide the DRI drawable
with a buffer. In this instance, Mesa un-does the EGL bindings,
but doesn't restore the old DRI context, hence remaining in a
funny state. It's worth mentioning that despite trying, there
is no guarantee that the old DRI context can be restored,
depending on the runtime.
Before this change, if bindContext() failed then
dri2_make_current() would rebind the old EGL context and
surfaces and return EGL_BAD_MATCH. However, it wouldn't rebind
the DRI context and surfaces, thus leaving it in an
inconsistent and unrecoverable state.
After this change, dri2_make_current() tries to bind the old
DRI context and surfaces when bindContext() failed. If unable
to do so, it leaves EGL and the DRI driver in a consistent
state, it reports an error and returns EGL_BAD_MATCH.
Fixes: 4e8f95f64d004aa1 ("egl_dri2: Always unbind old contexts")
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5707>
2020-06-30 14:59:45 +01:00
|
|
|
|
dsurf = rsurf = NULL;
|
|
|
|
|
ctx = NULL;
|
2016-10-14 16:07:33 +01:00
|
|
|
|
|
egl/dri2: try to bind old context if bindContext failed
This change mostly touches error handling code paths, where a
bug was found when the DRI driver failed to bind a new DRI
context. Specifically, the reason for it to fail was the window
system unable (for whatever reason) to provide the DRI drawable
with a buffer. In this instance, Mesa un-does the EGL bindings,
but doesn't restore the old DRI context, hence remaining in a
funny state. It's worth mentioning that despite trying, there
is no guarantee that the old DRI context can be restored,
depending on the runtime.
Before this change, if bindContext() failed then
dri2_make_current() would rebind the old EGL context and
surfaces and return EGL_BAD_MATCH. However, it wouldn't rebind
the DRI context and surfaces, thus leaving it in an
inconsistent and unrecoverable state.
After this change, dri2_make_current() tries to bind the old
DRI context and surfaces when bindContext() failed. If unable
to do so, it leaves EGL and the DRI driver in a consistent
state, it reports an error and returns EGL_BAD_MATCH.
Fixes: 4e8f95f64d004aa1 ("egl_dri2: Always unbind old contexts")
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5707>
2020-06-30 14:59:45 +01:00
|
|
|
|
_eglBindContext(ctx, dsurf, rsurf, &tmp_ctx, &tmp_dsurf, &tmp_rsurf);
|
|
|
|
|
assert(tmp_ctx == old_ctx && tmp_dsurf == old_dsurf &&
|
|
|
|
|
tmp_rsurf == old_rsurf);
|
|
|
|
|
|
|
|
|
|
_eglLog(_EGL_WARNING, "DRI2: failed to rebind the previous context");
|
2020-07-28 15:50:30 +01:00
|
|
|
|
} else {
|
|
|
|
|
/* dri2_dpy->core->bindContext succeeded, so take a reference on the
|
|
|
|
|
* dri2_dpy. This prevents dri2_dpy from being reinitialized when a
|
|
|
|
|
* EGLDisplay is terminated and then initialized again while a
|
|
|
|
|
* context is still bound. See dri2_intitialize() for a more in depth
|
|
|
|
|
* explanation. */
|
|
|
|
|
dri2_dpy->ref_count++;
|
egl/dri2: try to bind old context if bindContext failed
This change mostly touches error handling code paths, where a
bug was found when the DRI driver failed to bind a new DRI
context. Specifically, the reason for it to fail was the window
system unable (for whatever reason) to provide the DRI drawable
with a buffer. In this instance, Mesa un-does the EGL bindings,
but doesn't restore the old DRI context, hence remaining in a
funny state. It's worth mentioning that despite trying, there
is no guarantee that the old DRI context can be restored,
depending on the runtime.
Before this change, if bindContext() failed then
dri2_make_current() would rebind the old EGL context and
surfaces and return EGL_BAD_MATCH. However, it wouldn't rebind
the DRI context and surfaces, thus leaving it in an
inconsistent and unrecoverable state.
After this change, dri2_make_current() tries to bind the old
DRI context and surfaces when bindContext() failed. If unable
to do so, it leaves EGL and the DRI driver in a consistent
state, it reports an error and returns EGL_BAD_MATCH.
Fixes: 4e8f95f64d004aa1 ("egl_dri2: Always unbind old contexts")
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5707>
2020-06-30 14:59:45 +01:00
|
|
|
|
}
|
2016-10-14 16:07:33 +01:00
|
|
|
|
}
|
2018-04-07 21:01:15 +01:00
|
|
|
|
|
|
|
|
|
dri2_destroy_surface(drv, disp, old_dsurf);
|
|
|
|
|
dri2_destroy_surface(drv, disp, old_rsurf);
|
|
|
|
|
|
|
|
|
|
if (old_ctx) {
|
|
|
|
|
dri2_destroy_context(drv, disp, old_ctx);
|
|
|
|
|
dri2_display_release(old_disp);
|
|
|
|
|
}
|
|
|
|
|
|
egl/dri2: try to bind old context if bindContext failed
This change mostly touches error handling code paths, where a
bug was found when the DRI driver failed to bind a new DRI
context. Specifically, the reason for it to fail was the window
system unable (for whatever reason) to provide the DRI drawable
with a buffer. In this instance, Mesa un-does the EGL bindings,
but doesn't restore the old DRI context, hence remaining in a
funny state. It's worth mentioning that despite trying, there
is no guarantee that the old DRI context can be restored,
depending on the runtime.
Before this change, if bindContext() failed then
dri2_make_current() would rebind the old EGL context and
surfaces and return EGL_BAD_MATCH. However, it wouldn't rebind
the DRI context and surfaces, thus leaving it in an
inconsistent and unrecoverable state.
After this change, dri2_make_current() tries to bind the old
DRI context and surfaces when bindContext() failed. If unable
to do so, it leaves EGL and the DRI driver in a consistent
state, it reports an error and returns EGL_BAD_MATCH.
Fixes: 4e8f95f64d004aa1 ("egl_dri2: Always unbind old contexts")
Signed-off-by: Luigi Santivetti <luigi.santivetti@imgtec.com>
Reviewed-by: Emil Velikov <emil.velikov@collabora.com>
Acked-by: Eric Engestrom <eric@engestrom.ch>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5707>
2020-06-30 14:59:45 +01:00
|
|
|
|
if (egl_error != EGL_SUCCESS)
|
|
|
|
|
return _eglError(egl_error, "eglMakeCurrent");
|
|
|
|
|
|
2018-05-01 06:35:17 +01:00
|
|
|
|
if (dsurf && _eglSurfaceHasMutableRenderBuffer(dsurf) &&
|
|
|
|
|
dri2_dpy->vtbl->set_shared_buffer_mode) {
|
|
|
|
|
/* Always update the shared buffer mode. This is obviously needed when
|
|
|
|
|
* the active EGL_RENDER_BUFFER is EGL_SINGLE_BUFFER. When
|
|
|
|
|
* EGL_RENDER_BUFFER is EGL_BACK_BUFFER, the update protects us in the
|
|
|
|
|
* case where external non-EGL API may have changed window's shared
|
|
|
|
|
* buffer mode since we last saw it.
|
|
|
|
|
*/
|
|
|
|
|
bool mode = (dsurf->ActiveRenderBuffer == EGL_SINGLE_BUFFER);
|
|
|
|
|
dri2_dpy->vtbl->set_shared_buffer_mode(disp, dsurf, mode);
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-07 21:01:15 +01:00
|
|
|
|
return EGL_TRUE;
|
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
|
|
|
|
/*
|
2020-07-20 12:38:24 +01:00
|
|
|
|
* Called from eglGetProcAddress() via drv->GetProcAddress().
|
2010-02-03 15:18:28 +00:00
|
|
|
|
*/
|
|
|
|
|
static _EGLProc
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_get_proc_address(const _EGLDriver *drv, const char *procname)
|
2010-02-03 15:18:28 +00:00
|
|
|
|
{
|
2017-09-27 17:36:29 +01:00
|
|
|
|
return _glapi_get_proc_address(procname);
|
2010-02-03 15:18:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:39:09 +00:00
|
|
|
|
static _EGLSurface*
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_window_surface(const _EGLDriver *drv, _EGLDisplay *disp,
|
egl/main: Stop using EGLNative types internally
Internally, much of the EGL code uses EGLNativeDisplayType,
EGLNativeWindowType, and EGLPixmapType. However, the EGLNative type
often does not match the variable's actual type.
The concept of EGLNative types are a bad match for Linux, as explained
below. And the EGL platform extensions don't use EGLNative types at all.
Those extensions attempt to solve cross-platform issues by moving the
EGL API away from the EGLNative types.
The core of the problem is that eglplatform.h can define each EGLNative
type once only, but Linux supports multiple EGL platforms.
To work around the problem, Mesa's eglplatform.h contains multiple
definitions of each EGLNative type, selected by feature macros. Mesa
expects EGL clients to set the feature macro approrpiately. But the
feature macros don't work when a single codebase must be built with
support for multiple EGL platforms, *such as Mesa itself*.
When building libEGL, autotools chooses the EGLNative typedefs based on
the first element of '--with-egl-platforms'. For example,
'--with-egl-platforms=x11,drm,wayland' defines the following:
typedef Display* EGLNativeDisplayType;
typedef Window EGLNativeWindowType;
typedef Pixmap EGLNativePixmapType;
Clearly, this doesn't work well for Wayland and GBM. Mesa works around
the problem by casting the EGLNative types to different things in
different files.
For sanity's sake, and to prepare for the EGL platform extensions, this
patch removes from egl/main and egl/dri2 all internal use of the
EGLNative types. It replaces them with 'void*' and checks each explicit
cast with a static assertion. Also, the patch touches egl_gallium the
minimal amount to keep it compatible with eglapi.h.
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
2014-01-07 22:54:51 +00:00
|
|
|
|
_EGLConfig *conf, void *native_window,
|
2014-01-29 00:39:09 +00:00
|
|
|
|
const EGLint *attrib_list)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
return dri2_dpy->vtbl->create_window_surface(drv, disp, conf, native_window,
|
2014-01-29 00:39:09 +00:00
|
|
|
|
attrib_list);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:45:07 +00:00
|
|
|
|
static _EGLSurface*
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_pixmap_surface(const _EGLDriver *drv, _EGLDisplay *disp,
|
egl/main: Stop using EGLNative types internally
Internally, much of the EGL code uses EGLNativeDisplayType,
EGLNativeWindowType, and EGLPixmapType. However, the EGLNative type
often does not match the variable's actual type.
The concept of EGLNative types are a bad match for Linux, as explained
below. And the EGL platform extensions don't use EGLNative types at all.
Those extensions attempt to solve cross-platform issues by moving the
EGL API away from the EGLNative types.
The core of the problem is that eglplatform.h can define each EGLNative
type once only, but Linux supports multiple EGL platforms.
To work around the problem, Mesa's eglplatform.h contains multiple
definitions of each EGLNative type, selected by feature macros. Mesa
expects EGL clients to set the feature macro approrpiately. But the
feature macros don't work when a single codebase must be built with
support for multiple EGL platforms, *such as Mesa itself*.
When building libEGL, autotools chooses the EGLNative typedefs based on
the first element of '--with-egl-platforms'. For example,
'--with-egl-platforms=x11,drm,wayland' defines the following:
typedef Display* EGLNativeDisplayType;
typedef Window EGLNativeWindowType;
typedef Pixmap EGLNativePixmapType;
Clearly, this doesn't work well for Wayland and GBM. Mesa works around
the problem by casting the EGLNative types to different things in
different files.
For sanity's sake, and to prepare for the EGL platform extensions, this
patch removes from egl/main and egl/dri2 all internal use of the
EGLNative types. It replaces them with 'void*' and checks each explicit
cast with a static assertion. Also, the patch touches egl_gallium the
minimal amount to keep it compatible with eglapi.h.
Signed-off-by: Chad Versace <chad.versace@linux.intel.com>
2014-01-07 22:54:51 +00:00
|
|
|
|
_EGLConfig *conf, void *native_pixmap,
|
2014-01-29 00:45:07 +00:00
|
|
|
|
const EGLint *attrib_list)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2020-07-10 23:29:17 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->create_pixmap_surface)
|
|
|
|
|
return NULL;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->create_pixmap_surface(drv, disp, conf, native_pixmap,
|
2014-01-29 00:45:07 +00:00
|
|
|
|
attrib_list);
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static _EGLSurface*
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_pbuffer_surface(const _EGLDriver *drv, _EGLDisplay *disp,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
_EGLConfig *conf, const EGLint *attrib_list)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2020-07-10 23:31:32 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->create_pbuffer_surface)
|
|
|
|
|
return NULL;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->create_pbuffer_surface(drv, disp, conf, attrib_list);
|
2014-01-29 01:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-28 20:34:19 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_swap_interval(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
|
2014-01-28 20:34:19 +00:00
|
|
|
|
EGLint interval)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2017-08-02 17:25:44 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->swap_interval)
|
|
|
|
|
return EGL_TRUE;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->swap_interval(drv, disp, surf, interval);
|
2014-01-28 20:34:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_swap_buffers(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
|
2014-01-29 00:21:21 +00:00
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2019-08-12 11:07:06 +01:00
|
|
|
|
__DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
|
2017-09-15 18:32:42 +01:00
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
2019-08-12 11:07:06 +01:00
|
|
|
|
EGLBoolean ret;
|
2017-09-15 18:32:42 +01:00
|
|
|
|
|
|
|
|
|
if (ctx && surf)
|
2019-02-02 11:38:45 +00:00
|
|
|
|
dri2_surf_update_fence_fd(ctx, disp, surf);
|
2019-08-12 11:07:06 +01:00
|
|
|
|
ret = dri2_dpy->vtbl->swap_buffers(drv, disp, surf);
|
|
|
|
|
|
|
|
|
|
/* SwapBuffers marks the end of the frame; reset the damage region for
|
|
|
|
|
* use again next time.
|
|
|
|
|
*/
|
|
|
|
|
if (ret && dri2_dpy->buffer_damage &&
|
|
|
|
|
dri2_dpy->buffer_damage->set_damage_region)
|
|
|
|
|
dri2_dpy->buffer_damage->set_damage_region(dri_drawable, 0, NULL);
|
|
|
|
|
|
|
|
|
|
return ret;
|
2014-01-29 00:21:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 00:26:44 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_swap_buffers_with_damage(const _EGLDriver *drv, _EGLDisplay *disp,
|
2014-01-29 00:26:44 +00:00
|
|
|
|
_EGLSurface *surf,
|
|
|
|
|
const EGLint *rects, EGLint n_rects)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2019-08-12 11:07:06 +01:00
|
|
|
|
__DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
|
2017-09-15 18:32:42 +01:00
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
2019-08-12 11:07:06 +01:00
|
|
|
|
EGLBoolean ret;
|
2017-09-15 18:32:42 +01:00
|
|
|
|
|
|
|
|
|
if (ctx && surf)
|
2019-02-02 11:38:45 +00:00
|
|
|
|
dri2_surf_update_fence_fd(ctx, disp, surf);
|
2020-07-10 23:36:08 +01:00
|
|
|
|
if (dri2_dpy->vtbl->swap_buffers_with_damage)
|
|
|
|
|
ret = dri2_dpy->vtbl->swap_buffers_with_damage(drv, disp, surf,
|
|
|
|
|
rects, n_rects);
|
|
|
|
|
else
|
|
|
|
|
ret = dri2_dpy->vtbl->swap_buffers(drv, disp, surf);
|
2019-08-12 11:07:06 +01:00
|
|
|
|
|
|
|
|
|
/* SwapBuffers marks the end of the frame; reset the damage region for
|
|
|
|
|
* use again next time.
|
|
|
|
|
*/
|
|
|
|
|
if (ret && dri2_dpy->buffer_damage &&
|
|
|
|
|
dri2_dpy->buffer_damage->set_damage_region)
|
|
|
|
|
dri2_dpy->buffer_damage->set_damage_region(dri_drawable, 0, NULL);
|
|
|
|
|
|
|
|
|
|
return ret;
|
2014-01-29 00:26:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_swap_buffers_region(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
EGLint numRects, const EGLint *rects)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2019-08-12 11:07:06 +01:00
|
|
|
|
__DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
|
|
|
|
|
EGLBoolean ret;
|
|
|
|
|
|
2020-07-10 23:38:38 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->swap_buffers_region)
|
|
|
|
|
return EGL_FALSE;
|
2019-08-12 11:07:06 +01:00
|
|
|
|
ret = dri2_dpy->vtbl->swap_buffers_region(drv, disp, surf, numRects, rects);
|
|
|
|
|
|
|
|
|
|
/* SwapBuffers marks the end of the frame; reset the damage region for
|
|
|
|
|
* use again next time.
|
|
|
|
|
*/
|
|
|
|
|
if (ret && dri2_dpy->buffer_damage &&
|
|
|
|
|
dri2_dpy->buffer_damage->set_damage_region)
|
|
|
|
|
dri2_dpy->buffer_damage->set_damage_region(dri_drawable, 0, NULL);
|
|
|
|
|
|
|
|
|
|
return ret;
|
2014-01-29 01:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-09 15:43:34 +01:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_set_damage_region(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
|
2017-06-09 15:43:34 +01:00
|
|
|
|
EGLint *rects, EGLint n_rects)
|
|
|
|
|
{
|
2019-08-12 11:07:06 +01:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
__DRIdrawable *drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
|
|
|
|
|
|
|
|
|
|
if (!dri2_dpy->buffer_damage || !dri2_dpy->buffer_damage->set_damage_region)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
dri2_dpy->buffer_damage->set_damage_region(drawable, n_rects, rects);
|
|
|
|
|
return EGL_TRUE;
|
2017-06-09 15:43:34 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_post_sub_buffer(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
EGLint x, EGLint y, EGLint width, EGLint height)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2020-07-10 23:39:41 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->post_sub_buffer)
|
|
|
|
|
return EGL_FALSE;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->post_sub_buffer(drv, disp, surf, x, y, width, height);
|
2014-01-29 01:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_copy_buffers(const _EGLDriver *drv, _EGLDisplay *disp, _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
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2020-07-10 23:40:20 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->copy_buffers)
|
|
|
|
|
return _eglError(EGL_BAD_NATIVE_PIXMAP, "no support for native pixmaps");
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->copy_buffers(drv, disp, surf, native_pixmap_target);
|
2014-01-29 01:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static EGLint
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_query_buffer_age(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
|
2014-01-29 01:03:03 +00:00
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2020-07-10 23:40:57 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->query_buffer_age)
|
|
|
|
|
return 0;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->query_buffer_age(drv, disp, surf);
|
2014-01-29 01:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-02-03 15:18:28 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_wait_client(const _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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_wait_native(const _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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_bind_tex_image(const _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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_release_tex_image(const _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:
|
2018-10-28 18:20:20 +00:00
|
|
|
|
assert(!"missing texture target");
|
2011-01-09 17:03:02 +00:00
|
|
|
|
}
|
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*
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_image(const _EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
EGLenum target, EGLClientBuffer buffer,
|
|
|
|
|
const EGLint *attr_list)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
return dri2_dpy->vtbl->create_image(drv, disp, ctx, target, buffer,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2017-06-20 15:22:39 +01:00
|
|
|
|
_eglInitImage(&dri2_img->base, disp);
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-10 12:58:47 +01:00
|
|
|
|
/**
|
|
|
|
|
* Translate a DRI Image extension error code into an EGL error code.
|
|
|
|
|
*/
|
|
|
|
|
static EGLint
|
|
|
|
|
egl_error_from_dri_image_error(int dri_error)
|
|
|
|
|
{
|
|
|
|
|
switch (dri_error) {
|
|
|
|
|
case __DRI_IMAGE_ERROR_SUCCESS:
|
|
|
|
|
return EGL_SUCCESS;
|
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_ALLOC:
|
|
|
|
|
return EGL_BAD_ALLOC;
|
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_MATCH:
|
|
|
|
|
return EGL_BAD_MATCH;
|
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_PARAMETER:
|
|
|
|
|
return EGL_BAD_PARAMETER;
|
|
|
|
|
case __DRI_IMAGE_ERROR_BAD_ACCESS:
|
|
|
|
|
return EGL_BAD_ACCESS;
|
|
|
|
|
default:
|
2018-10-28 18:20:20 +00:00
|
|
|
|
assert(!"unknown dri_error code");
|
2017-10-10 12:58:47 +01:00
|
|
|
|
return EGL_BAD_ALLOC;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2017-06-29 00:35:56 +01:00
|
|
|
|
if (!disp->Extensions.KHR_gl_renderbuffer_image) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-10 18:50:13 +01:00
|
|
|
|
if (dri2_dpy->image->base.version >= 17 &&
|
|
|
|
|
dri2_dpy->image->createImageFromRenderbuffer2) {
|
2017-10-10 12:58:47 +01:00
|
|
|
|
unsigned error = ~0;
|
|
|
|
|
|
|
|
|
|
dri_image = dri2_dpy->image->createImageFromRenderbuffer2(
|
|
|
|
|
dri2_ctx->dri_context, renderbuffer, NULL, &error);
|
|
|
|
|
|
|
|
|
|
assert(!!dri_image == (error == __DRI_IMAGE_ERROR_SUCCESS));
|
|
|
|
|
|
|
|
|
|
if (!dri_image) {
|
|
|
|
|
_eglError(egl_error_from_dri_image_error(error), "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
dri_image = dri2_dpy->image->createImageFromRenderbuffer(
|
|
|
|
|
dri2_ctx->dri_context, renderbuffer, NULL);
|
|
|
|
|
if (!dri_image) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
}
|
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;
|
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
|
|
|
|
|
2017-06-28 20:31:18 +01:00
|
|
|
|
if (!_eglParseImageAttribList(&attrs, disp, attr_list))
|
2012-07-05 21:43:04 +01:00
|
|
|
|
return NULL;
|
|
|
|
|
|
2017-06-28 20:31:18 +01:00
|
|
|
|
plane = attrs.PlaneWL;
|
2012-07-05 21:43:04 +01:00
|
|
|
|
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);
|
2017-09-28 08:18:33 +01:00
|
|
|
|
if (dri_image == NULL && plane == 0)
|
|
|
|
|
dri_image = dri2_dpy->image->dupImage(buffer->driver_buffer, NULL);
|
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
|
2019-02-02 11:38:45 +00:00
|
|
|
|
dri2_get_sync_values_chromium(_EGLDisplay *disp, _EGLSurface *surf,
|
2014-05-06 20:10:57 +01:00
|
|
|
|
EGLuint64KHR *ust, EGLuint64KHR *msc,
|
|
|
|
|
EGLuint64KHR *sbc)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2020-07-10 23:42:08 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->get_sync_values)
|
|
|
|
|
return EGL_FALSE;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->get_sync_values(disp, surf, ust, msc, sbc);
|
2014-05-06 20:10:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2017-10-10 12:58:47 +01:00
|
|
|
|
EGLint egl_error = egl_error_from_dri_image_error(dri_error);
|
2012-11-27 13:19:54 +00:00
|
|
|
|
|
2017-10-10 12:58:47 +01:00
|
|
|
|
if (egl_error != EGL_SUCCESS)
|
|
|
|
|
_eglError(egl_error, "dri2_create_image_khr_texture");
|
2012-11-27 13:19:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-28 20:31:18 +01:00
|
|
|
|
if (!_eglParseImageAttribList(&attrs, disp, attr_list))
|
2012-11-27 13:19:54 +00:00
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
|
|
|
|
|
switch (target) {
|
|
|
|
|
case EGL_GL_TEXTURE_2D_KHR:
|
2017-06-29 00:35:56 +01:00
|
|
|
|
if (!disp->Extensions.KHR_gl_texture_2D_image) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
2012-11-27 13:19:54 +00:00
|
|
|
|
depth = 0;
|
|
|
|
|
gl_target = GL_TEXTURE_2D;
|
|
|
|
|
break;
|
|
|
|
|
case EGL_GL_TEXTURE_3D_KHR:
|
2017-06-29 00:35:56 +01:00
|
|
|
|
if (!disp->Extensions.KHR_gl_texture_3D_image) {
|
2015-06-10 13:42:31 +01:00
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
2017-06-29 00:35:56 +01:00
|
|
|
|
|
|
|
|
|
depth = attrs.GLTextureZOffset;
|
|
|
|
|
gl_target = GL_TEXTURE_3D;
|
|
|
|
|
break;
|
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:
|
2017-06-29 00:35:56 +01:00
|
|
|
|
if (!disp->Extensions.KHR_gl_texture_cubemap_image) {
|
|
|
|
|
_eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-27 13:19:54 +00:00
|
|
|
|
depth = target - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR;
|
|
|
|
|
gl_target = GL_TEXTURE_CUBE_MAP;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2017-06-29 00:35:56 +01:00
|
|
|
|
unreachable("Unexpected target in dri2_create_image_khr_texture()");
|
2012-11-27 13:19:54 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-20 15:22:39 +01:00
|
|
|
|
_eglInitImage(&dri2_img->base, disp);
|
2012-11-27 13:19:54 +00:00
|
|
|
|
|
|
|
|
|
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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_query_surface(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
|
2016-07-28 18:51:12 +01:00
|
|
|
|
EGLint attribute, EGLint *value)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2016-07-28 18:51:12 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->query_surface)
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return _eglQuerySurface(drv, disp, surf, attribute, value);
|
|
|
|
|
return dri2_dpy->vtbl->query_surface(drv, disp, surf, attribute, value);
|
2016-07-28 18:51:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
2014-01-29 01:03:03 +00:00
|
|
|
|
static struct wl_buffer*
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_wayland_buffer_from_image(const _EGLDriver *drv, _EGLDisplay *disp,
|
2014-01-29 01:03:03 +00:00
|
|
|
|
_EGLImage *img)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2020-07-10 23:41:35 +01:00
|
|
|
|
if (!dri2_dpy->vtbl->create_wayland_buffer_from_image)
|
|
|
|
|
return NULL;
|
2019-02-02 11:38:45 +00:00
|
|
|
|
return dri2_dpy->vtbl->create_wayland_buffer_from_image(drv, disp, img);
|
2014-01-29 01:03:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
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);
|
2017-07-13 10:38:48 +01:00
|
|
|
|
EGLint format, name, pitch;
|
2015-07-10 11:01:35 +01:00
|
|
|
|
_EGLImageAttribs attrs;
|
|
|
|
|
__DRIimage *dri_image;
|
|
|
|
|
|
|
|
|
|
name = (EGLint) (uintptr_t) buffer;
|
|
|
|
|
|
2017-06-28 20:31:18 +01:00
|
|
|
|
if (!_eglParseImageAttribList(&attrs, disp, attr_list))
|
2015-07-10 11:01:35 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-12 15:32:41 +00:00
|
|
|
|
dri_image =
|
|
|
|
|
dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* 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 ||
|
2017-06-20 15:40:28 +01:00
|
|
|
|
!attrs->DMABufFourCC.IsPresent)
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "attribute(s) missing");
|
2013-03-22 13:58:05 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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."
|
|
|
|
|
*/
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 0; i < ARRAY_SIZE(attrs->DMABufPlanePitches); ++i) {
|
2013-03-22 13:58:05 +00:00
|
|
|
|
if (attrs->DMABufPlanePitches[i].IsPresent &&
|
2017-06-20 15:40:28 +01:00
|
|
|
|
attrs->DMABufPlanePitches[i].Value <= 0)
|
|
|
|
|
return _eglError(EGL_BAD_ACCESS, "invalid pitch");
|
2013-03-22 13:58:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 0; i < DMA_BUF_MAX_PLANES; ++i) {
|
2017-05-30 12:53:37 +01:00
|
|
|
|
if (attrs->DMABufPlaneModifiersLo[i].IsPresent !=
|
2017-06-20 15:40:28 +01:00
|
|
|
|
attrs->DMABufPlaneModifiersHi[i].IsPresent)
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "modifier attribute lo or hi missing");
|
2017-05-30 12:53:37 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Although the EGL_EXT_image_dma_buf_import_modifiers spec doesn't
|
|
|
|
|
* mandate it, we only accept the same modifier across all planes. */
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 1; i < DMA_BUF_MAX_PLANES; ++i) {
|
2017-05-30 12:53:37 +01:00
|
|
|
|
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 !=
|
2017-06-20 15:40:28 +01:00
|
|
|
|
attrs->DMABufPlaneModifiersHi[i].Value))
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "modifier attributes not equal");
|
2017-05-30 12:53:37 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-28 22:31:22 +01:00
|
|
|
|
/* Returns the total number of planes for the format or zero if it isn't a
|
|
|
|
|
* valid fourcc format.
|
|
|
|
|
*/
|
2013-03-22 13:58:05 +00:00
|
|
|
|
static unsigned
|
2018-08-28 22:31:22 +01:00
|
|
|
|
dri2_num_fourcc_format_planes(EGLint format)
|
2013-03-22 13:58:05 +00:00
|
|
|
|
{
|
2018-08-28 22:31:22 +01:00
|
|
|
|
switch (format) {
|
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:
|
2019-01-25 01:32:36 +00:00
|
|
|
|
case DRM_FORMAT_XBGR16161616F:
|
|
|
|
|
case DRM_FORMAT_ABGR16161616F:
|
2013-03-22 13:58:05 +00:00
|
|
|
|
case DRM_FORMAT_YUYV:
|
|
|
|
|
case DRM_FORMAT_YVYU:
|
|
|
|
|
case DRM_FORMAT_UYVY:
|
|
|
|
|
case DRM_FORMAT_VYUY:
|
2018-11-08 17:28:20 +00:00
|
|
|
|
case DRM_FORMAT_AYUV:
|
2019-02-13 00:44:04 +00:00
|
|
|
|
case DRM_FORMAT_XYUV8888:
|
2018-08-28 22:31:22 +01:00
|
|
|
|
return 1;
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
case DRM_FORMAT_NV12:
|
|
|
|
|
case DRM_FORMAT_NV21:
|
|
|
|
|
case DRM_FORMAT_NV16:
|
|
|
|
|
case DRM_FORMAT_NV61:
|
2019-02-11 08:01:35 +00:00
|
|
|
|
case DRM_FORMAT_P010:
|
|
|
|
|
case DRM_FORMAT_P012:
|
|
|
|
|
case DRM_FORMAT_P016:
|
2018-08-28 22:31:22 +01:00
|
|
|
|
return 2;
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
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:
|
2018-08-28 22:31:22 +01:00
|
|
|
|
return 3;
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
default:
|
2018-08-28 22:31:22 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Returns the total number of file descriptors. Zero indicates an error. */
|
|
|
|
|
static unsigned
|
|
|
|
|
dri2_check_dma_buf_format(const _EGLImageAttribs *attrs)
|
|
|
|
|
{
|
|
|
|
|
unsigned plane_n = dri2_num_fourcc_format_planes(attrs->DMABufFourCC.Value);
|
|
|
|
|
if (plane_n == 0) {
|
2018-11-13 14:10:45 +00:00
|
|
|
|
_eglError(EGL_BAD_MATCH, "unknown drm fourcc format");
|
2013-03-22 13:58:05 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-31 18:34:57 +01:00
|
|
|
|
for (unsigned i = plane_n; i < DMA_BUF_MAX_PLANES; i++) {
|
|
|
|
|
/**
|
|
|
|
|
* 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) {
|
|
|
|
|
plane_n = i + 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* The spec says:
|
|
|
|
|
*
|
|
|
|
|
* "* If <target> is EGL_LINUX_DMA_BUF_EXT, and the list of attributes is
|
|
|
|
|
* incomplete, EGL_BAD_PARAMETER is generated."
|
|
|
|
|
*/
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 0; i < plane_n; ++i) {
|
2013-03-22 13:58:05 +00:00
|
|
|
|
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-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned 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-07-31 18:34:57 +01:00
|
|
|
|
attrs->DMABufPlanePitches[i].IsPresent) {
|
2013-03-22 13:58:05 +00:00
|
|
|
|
_eglError(EGL_BAD_ATTRIBUTE, "too many plane attributes");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return plane_n;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:38 +01:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_query_dma_buf_formats(const _EGLDriver *drv, _EGLDisplay *disp,
|
2017-05-30 12:53:38 +01:00
|
|
|
|
EGLint max, EGLint *formats, EGLint *count)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2017-06-20 15:40:28 +01:00
|
|
|
|
if (max < 0 || (max > 0 && formats == NULL))
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "invalid value for max count of formats");
|
2017-05-30 12:53:38 +01:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->image->base.version < 15 ||
|
|
|
|
|
dri2_dpy->image->queryDmaBufFormats == NULL)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
if (!dri2_dpy->image->queryDmaBufFormats(dri2_dpy->dri_screen, max,
|
|
|
|
|
formats, count))
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2018-08-28 22:43:57 +01:00
|
|
|
|
if (max > 0) {
|
|
|
|
|
/* Assert that all of the formats returned are actually fourcc formats.
|
|
|
|
|
* Some day, if we want the internal interface function to be able to
|
|
|
|
|
* return the fake fourcc formats defined in dri_interface.h, we'll have
|
|
|
|
|
* to do something more clever here to pair the list down to just real
|
|
|
|
|
* fourcc formats so that we don't leak the fake internal ones.
|
|
|
|
|
*/
|
|
|
|
|
for (int i = 0; i < *count; i++) {
|
|
|
|
|
assert(dri2_num_fourcc_format_planes(formats[i]) > 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:38 +01:00
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 12:53:39 +01:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_query_dma_buf_modifiers(const _EGLDriver *drv, _EGLDisplay *disp, EGLint format,
|
2017-05-30 12:53:39 +01:00
|
|
|
|
EGLint max, EGLuint64KHR *modifiers,
|
|
|
|
|
EGLBoolean *external_only, EGLint *count)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
|
2018-08-28 22:43:57 +01:00
|
|
|
|
if (dri2_num_fourcc_format_planes(format) == 0)
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "invalid fourcc format");
|
|
|
|
|
|
2017-06-20 15:40:28 +01:00
|
|
|
|
if (max < 0)
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "invalid value for max count of formats");
|
2017-05-30 12:53:39 +01:00
|
|
|
|
|
2017-06-20 15:40:28 +01:00
|
|
|
|
if (max > 0 && modifiers == NULL)
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "invalid modifiers array");
|
2017-05-30 12:53:39 +01:00
|
|
|
|
|
|
|
|
|
if (dri2_dpy->image->base.version < 15 ||
|
|
|
|
|
dri2_dpy->image->queryDmaBufModifiers == NULL)
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
|
|
|
|
if (dri2_dpy->image->queryDmaBufModifiers(dri2_dpy->dri_screen, format,
|
|
|
|
|
max, modifiers,
|
|
|
|
|
(unsigned int *) external_only,
|
2017-06-20 15:40:28 +01:00
|
|
|
|
count) == false)
|
|
|
|
|
return _eglError(EGL_BAD_PARAMETER, "invalid format");
|
2017-05-30 12:53:39 +01:00
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-03-22 13:58:05 +00:00
|
|
|
|
/**
|
|
|
|
|
* 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;
|
|
|
|
|
_EGLImageAttribs attrs;
|
|
|
|
|
__DRIimage *dri_image;
|
|
|
|
|
unsigned num_fds;
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-28 20:31:18 +01:00
|
|
|
|
if (!_eglParseImageAttribList(&attrs, disp, attr_list))
|
2013-03-22 13:58:05 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (!dri2_check_dma_buf_attribs(&attrs))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
num_fds = dri2_check_dma_buf_format(&attrs);
|
|
|
|
|
if (!num_fds)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (unsigned i = 0; i < num_fds; ++i) {
|
2013-03-22 13:58:05 +00:00
|
|
|
|
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) {
|
2018-08-16 15:22:46 +01:00
|
|
|
|
modifier = combine_u32_into_u64(attrs.DMABufPlaneModifiersHi[0].Value,
|
|
|
|
|
attrs.DMABufPlaneModifiersLo[0].Value);
|
2017-05-30 12:53:37 +01:00
|
|
|
|
has_modifier = true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-12 15:32:41 +00:00
|
|
|
|
if (has_modifier) {
|
2017-05-30 12:53:37 +01:00
|
|
|
|
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);
|
2019-11-12 15:32:41 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2017-05-30 12:53:37 +01:00
|
|
|
|
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 *
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_drm_image_mesa(const _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
|
|
|
|
|
2010-09-23 17:39:42 +01:00
|
|
|
|
(void) drv;
|
|
|
|
|
|
2010-06-04 02:36:40 +01:00
|
|
|
|
if (!attr_list) {
|
2017-06-28 21:23:00 +01:00
|
|
|
|
_eglError(EGL_BAD_PARAMETER, __func__);
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-28 20:31:18 +01:00
|
|
|
|
if (!_eglParseImageAttribList(&attrs, disp, attr_list))
|
2017-06-28 21:23:00 +01:00
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
2010-10-22 10:09:40 +01:00
|
|
|
|
if (attrs.Width <= 0 || attrs.Height <= 0) {
|
2017-06-28 21:23:00 +01:00
|
|
|
|
_eglError(EGL_BAD_PARAMETER, __func__);
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
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:
|
2017-06-28 21:23:00 +01:00
|
|
|
|
_eglError(EGL_BAD_PARAMETER, __func__);
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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) {
|
2017-06-28 21:23:00 +01:00
|
|
|
|
_eglError(EGL_BAD_PARAMETER, __func__);
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2017-06-28 21:23:00 +01:00
|
|
|
|
dri2_img = malloc(sizeof *dri2_img);
|
|
|
|
|
if (!dri2_img) {
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_eglInitImage(&dri2_img->base, disp);
|
|
|
|
|
|
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) {
|
2017-06-28 21:23:00 +01:00
|
|
|
|
free(dri2_img);
|
|
|
|
|
_eglError(EGL_BAD_ALLOC, "dri2_create_drm_image_mesa");
|
|
|
|
|
return EGL_NO_IMAGE_KHR;
|
2010-06-04 02:36:40 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &dri2_img->base;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_export_drm_image_mesa(const _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,
|
2017-06-20 15:40:28 +01:00
|
|
|
|
__DRI_IMAGE_ATTRIB_NAME, name))
|
|
|
|
|
return _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa");
|
2010-06-04 02:36:40 +01:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
2018-07-17 00:18:03 +01:00
|
|
|
|
/**
|
|
|
|
|
* Checks if we can support EGL_MESA_image_dma_buf_export on this image.
|
|
|
|
|
|
|
|
|
|
* The spec provides a boolean return for the driver to reject exporting for
|
|
|
|
|
* basically any reason, but doesn't specify any particular error cases. For
|
|
|
|
|
* now, we just fail if we don't have a DRM fourcc for the format.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
dri2_can_export_dma_buf_image(_EGLDisplay *disp, _EGLImage *img)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
|
|
|
struct dri2_egl_image *dri2_img = dri2_egl_image(img);
|
|
|
|
|
EGLint fourcc;
|
|
|
|
|
|
|
|
|
|
if (!dri2_dpy->image->queryImage(dri2_img->dri_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_FOURCC, &fourcc)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-03 03:57:16 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_export_dma_buf_image_query_mesa(const _EGLDriver *drv, _EGLDisplay *disp,
|
2014-03-03 03:57:16 +00:00
|
|
|
|
_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);
|
2019-07-14 19:48:11 +01:00
|
|
|
|
int num_planes;
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
2018-07-17 00:18:03 +01:00
|
|
|
|
if (!dri2_can_export_dma_buf_image(disp, img))
|
|
|
|
|
return EGL_FALSE;
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
2019-07-14 19:48:11 +01:00
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes);
|
2014-03-03 03:57:16 +00:00
|
|
|
|
if (nplanes)
|
2019-07-14 19:48:11 +01:00
|
|
|
|
*nplanes = num_planes;
|
|
|
|
|
|
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
|
|
|
|
|
2019-07-14 19:48:11 +01:00
|
|
|
|
if (modifiers) {
|
|
|
|
|
int mod_hi, mod_lo;
|
|
|
|
|
uint64_t modifier = DRM_FORMAT_MOD_INVALID;
|
|
|
|
|
bool query;
|
|
|
|
|
|
|
|
|
|
query = dri2_dpy->image->queryImage(dri2_img->dri_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
|
|
|
|
|
&mod_hi);
|
|
|
|
|
query &= dri2_dpy->image->queryImage(dri2_img->dri_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
|
|
|
|
|
&mod_lo);
|
|
|
|
|
if (query)
|
|
|
|
|
modifier = combine_u32_into_u64 (mod_hi, mod_lo);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < num_planes; i++)
|
|
|
|
|
modifiers[i] = modifier;
|
|
|
|
|
}
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_export_dma_buf_image_mesa(const _EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
|
2014-03-03 03:57:16 +00:00
|
|
|
|
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);
|
2019-04-09 08:43:59 +01:00
|
|
|
|
EGLint nplanes;
|
2014-03-03 03:57:16 +00:00
|
|
|
|
|
|
|
|
|
(void) drv;
|
|
|
|
|
|
2018-07-17 00:18:03 +01:00
|
|
|
|
if (!dri2_can_export_dma_buf_image(disp, img))
|
|
|
|
|
return EGL_FALSE;
|
|
|
|
|
|
2019-04-09 08:43:59 +01:00
|
|
|
|
/* EGL_MESA_image_dma_buf_export spec says:
|
|
|
|
|
* "If the number of fds is less than the number of planes, then
|
|
|
|
|
* subsequent fd slots should contain -1."
|
|
|
|
|
*/
|
|
|
|
|
if (fds) {
|
|
|
|
|
/* Query nplanes so that we know how big the given array is. */
|
|
|
|
|
dri2_dpy->image->queryImage(dri2_img->dri_image,
|
|
|
|
|
__DRI_IMAGE_ATTRIB_NUM_PLANES, &nplanes);
|
|
|
|
|
memset(fds, -1, nplanes * sizeof(int));
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-03 03:57:16 +00:00
|
|
|
|
/* 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 *
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_image_khr(const _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:
|
|
|
|
|
case EGL_GL_TEXTURE_3D_KHR:
|
2017-06-29 00:35:56 +01:00
|
|
|
|
return dri2_create_image_khr_texture(disp, ctx, target, buffer, attr_list);
|
2015-07-10 11:01:35 +01:00
|
|
|
|
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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_destroy_image_khr(const _EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
|
2015-07-10 11:01:35 +01:00
|
|
|
|
{
|
|
|
|
|
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;
|
2017-06-22 19:00:40 +01:00
|
|
|
|
int dri_components = 0;
|
2012-08-31 18:48:26 +01:00
|
|
|
|
|
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;
|
2017-06-22 19:00:40 +01:00
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(wl_drm_components); i++)
|
2012-08-31 18:48:26 +01:00
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2011-02-21 15:22:34 +00:00
|
|
|
|
static EGLBoolean
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_bind_wayland_display_wl(const _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);
|
2017-09-27 19:49:12 +01:00
|
|
|
|
const struct wayland_drm_callbacks wl_drm_callbacks = {
|
|
|
|
|
.authenticate = (int(*)(void *, uint32_t)) dri2_dpy->vtbl->authenticate,
|
|
|
|
|
.reference_buffer = dri2_wl_reference_buffer,
|
2018-06-13 05:04:15 +01:00
|
|
|
|
.release_buffer = dri2_wl_release_buffer,
|
|
|
|
|
.is_format_supported = dri2_wl_is_format_supported
|
2017-09-27 19:49:12 +01:00
|
|
|
|
};
|
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
|
|
|
|
|
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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_unbind_wayland_display_wl(const _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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_query_wayland_buffer_wl(const _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 *
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_create_sync(const _EGLDriver *drv, _EGLDisplay *disp,
|
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();
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2015-04-10 09:56:02 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-02 11:38:45 +00:00
|
|
|
|
if (!_eglInitSync(&dri2_sync->base, disp, 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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_destroy_sync(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync)
|
2015-04-10 09:56:02 +01:00
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2015-04-10 09:56:02 +01:00
|
|
|
|
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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_dup_native_fence_fd(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync)
|
2016-11-18 13:39:33 +00:00
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2016-11-18 13:39:33 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-05 09:22:22 +01:00
|
|
|
|
return os_dupfd_cloexec(sync->SyncFd);
|
2016-11-18 13:39:33 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-28 08:51:11 +00:00
|
|
|
|
static void
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_set_blob_cache_funcs(const _EGLDriver *drv, _EGLDisplay *disp,
|
2017-12-28 08:51:11 +00:00
|
|
|
|
EGLSetBlobFuncANDROID set,
|
|
|
|
|
EGLGetBlobFuncANDROID get)
|
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2017-12-28 08:51:11 +00:00
|
|
|
|
dri2_dpy->blob->set_cache_funcs(dri2_dpy->dri_screen,
|
2019-02-02 11:38:45 +00:00
|
|
|
|
disp->BlobCacheSet,
|
|
|
|
|
disp->BlobCacheGet);
|
2017-12-28 08:51:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-04-10 09:56:02 +01:00
|
|
|
|
static EGLint
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_client_wait_sync(const _EGLDriver *drv, _EGLDisplay *disp, _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();
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2015-04-10 09:56:02 +01:00
|
|
|
|
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
|
|
|
|
|
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 */
|
2017-09-26 12:16:33 +01:00
|
|
|
|
dri2_gl_flush();
|
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) {
|
2017-10-22 16:38:45 +01:00
|
|
|
|
/* timespecs for cnd_timedwait */
|
|
|
|
|
struct timespec current;
|
|
|
|
|
struct timespec expire;
|
|
|
|
|
|
|
|
|
|
/* We override the clock to monotonic when creating the condition
|
|
|
|
|
* variable. */
|
2016-04-05 01:14:10 +01:00
|
|
|
|
clock_gettime(CLOCK_MONOTONIC, ¤t);
|
|
|
|
|
|
|
|
|
|
/* calculating when to expire */
|
2017-10-22 16:38:45 +01:00
|
|
|
|
expire.tv_nsec = timeout % 1000000000L;
|
|
|
|
|
expire.tv_sec = timeout / 1000000000L;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
2017-10-22 16:38:45 +01:00
|
|
|
|
expire.tv_nsec += current.tv_nsec;
|
|
|
|
|
expire.tv_sec += current.tv_sec;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
|
|
|
|
/* expire.nsec now is a number between 0 and 1999999998 */
|
2017-10-22 16:38:45 +01:00
|
|
|
|
if (expire.tv_nsec > 999999999L) {
|
|
|
|
|
expire.tv_sec++;
|
|
|
|
|
expire.tv_nsec -= 1000000000L;
|
2016-04-05 01:14:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
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
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_signal_sync(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync,
|
2016-04-05 01:14:10 +01:00
|
|
|
|
EGLenum mode)
|
|
|
|
|
{
|
|
|
|
|
struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
|
|
|
|
|
EGLint ret;
|
|
|
|
|
|
2017-06-20 15:40:28 +01:00
|
|
|
|
if (sync->Type != EGL_SYNC_REUSABLE_KHR)
|
|
|
|
|
return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
2017-06-20 15:40:28 +01:00
|
|
|
|
if (mode != EGL_SIGNALED_KHR && mode != EGL_UNSIGNALED_KHR)
|
|
|
|
|
return _eglError(EGL_BAD_ATTRIBUTE, "eglSignalSyncKHR");
|
2016-04-05 01:14:10 +01:00
|
|
|
|
|
|
|
|
|
dri2_sync->base.SyncStatus = mode;
|
|
|
|
|
|
|
|
|
|
if (mode == EGL_SIGNALED_KHR) {
|
|
|
|
|
ret = cnd_broadcast(&dri2_sync->cond);
|
|
|
|
|
|
|
|
|
|
/* fail to broadcast */
|
2017-06-20 15:40:28 +01:00
|
|
|
|
if (ret)
|
|
|
|
|
return _eglError(EGL_BAD_ACCESS, "eglSignalSyncKHR");
|
2016-04-05 01:14:10 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return EGL_TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-10 11:04:18 +01:00
|
|
|
|
static EGLint
|
2020-07-31 00:38:41 +01:00
|
|
|
|
dri2_server_wait_sync(const _EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync)
|
2015-04-10 11:04:18 +01:00
|
|
|
|
{
|
|
|
|
|
_EGLContext *ctx = _eglGetCurrentContext();
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2015-04-10 11:04:18 +01:00
|
|
|
|
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
|
2019-02-02 11:38:45 +00:00
|
|
|
|
dri2_interop_query_device_info(_EGLDisplay *disp, _EGLContext *ctx,
|
2016-05-30 10:56:33 +01:00
|
|
|
|
struct mesa_glinterop_device_info *out)
|
2016-03-03 14:59:48 +00:00
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2016-03-03 14:59:48 +00:00
|
|
|
|
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
|
2019-02-02 11:38:45 +00:00
|
|
|
|
dri2_interop_export_object(_EGLDisplay *disp, _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
|
|
|
|
{
|
2019-02-02 11:38:45 +00:00
|
|
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
2016-03-03 14:59:48 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-31 00:38:41 +01:00
|
|
|
|
const _EGLDriver _eglDriver = {
|
2020-07-22 00:06:05 +01:00
|
|
|
|
.Initialize = dri2_initialize,
|
|
|
|
|
.Terminate = dri2_terminate,
|
|
|
|
|
.CreateContext = dri2_create_context,
|
|
|
|
|
.DestroyContext = dri2_destroy_context,
|
|
|
|
|
.MakeCurrent = dri2_make_current,
|
|
|
|
|
.CreateWindowSurface = dri2_create_window_surface,
|
|
|
|
|
.CreatePixmapSurface = dri2_create_pixmap_surface,
|
|
|
|
|
.CreatePbufferSurface = dri2_create_pbuffer_surface,
|
|
|
|
|
.DestroySurface = dri2_destroy_surface,
|
|
|
|
|
.GetProcAddress = dri2_get_proc_address,
|
|
|
|
|
.WaitClient = dri2_wait_client,
|
|
|
|
|
.WaitNative = dri2_wait_native,
|
|
|
|
|
.BindTexImage = dri2_bind_tex_image,
|
|
|
|
|
.ReleaseTexImage = dri2_release_tex_image,
|
|
|
|
|
.SwapInterval = dri2_swap_interval,
|
|
|
|
|
.SwapBuffers = dri2_swap_buffers,
|
|
|
|
|
.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage,
|
|
|
|
|
.SwapBuffersRegionNOK = dri2_swap_buffers_region,
|
|
|
|
|
.SetDamageRegion = dri2_set_damage_region,
|
|
|
|
|
.PostSubBufferNV = dri2_post_sub_buffer,
|
|
|
|
|
.CopyBuffers = dri2_copy_buffers,
|
|
|
|
|
.QueryBufferAge = dri2_query_buffer_age,
|
|
|
|
|
.CreateImageKHR = dri2_create_image,
|
|
|
|
|
.DestroyImageKHR = dri2_destroy_image_khr,
|
|
|
|
|
.CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image,
|
|
|
|
|
.QuerySurface = dri2_query_surface,
|
|
|
|
|
.QueryDriverName = dri2_query_driver_name,
|
|
|
|
|
.QueryDriverConfig = dri2_query_driver_config,
|
2015-01-14 19:36:04 +00:00
|
|
|
|
#ifdef HAVE_LIBDRM
|
2020-07-22 00:06:05 +01:00
|
|
|
|
.CreateDRMImageMESA = dri2_create_drm_image_mesa,
|
|
|
|
|
.ExportDRMImageMESA = dri2_export_drm_image_mesa,
|
|
|
|
|
.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa,
|
|
|
|
|
.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa,
|
|
|
|
|
.QueryDmaBufFormatsEXT = dri2_query_dma_buf_formats,
|
|
|
|
|
.QueryDmaBufModifiersEXT = dri2_query_dma_buf_modifiers,
|
2013-11-10 18:32:01 +00:00
|
|
|
|
#endif
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#ifdef HAVE_WAYLAND_PLATFORM
|
2020-07-22 00:06:05 +01:00
|
|
|
|
.BindWaylandDisplayWL = dri2_bind_wayland_display_wl,
|
|
|
|
|
.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl,
|
|
|
|
|
.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl,
|
2011-02-21 15:22:34 +00:00
|
|
|
|
#endif
|
2020-07-22 00:06:05 +01:00
|
|
|
|
.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium,
|
|
|
|
|
.CreateSyncKHR = dri2_create_sync,
|
|
|
|
|
.ClientWaitSyncKHR = dri2_client_wait_sync,
|
|
|
|
|
.SignalSyncKHR = dri2_signal_sync,
|
|
|
|
|
.WaitSyncKHR = dri2_server_wait_sync,
|
|
|
|
|
.DestroySyncKHR = dri2_destroy_sync,
|
|
|
|
|
.GLInteropQueryDeviceInfo = dri2_interop_query_device_info,
|
|
|
|
|
.GLInteropExportObject = dri2_interop_export_object,
|
|
|
|
|
.DupNativeFenceFDANDROID = dri2_dup_native_fence_fd,
|
|
|
|
|
.SetBlobCacheFuncsANDROID = dri2_set_blob_cache_funcs,
|
|
|
|
|
};
|