1848b8605Smrg/*
2848b8605Smrg * Copyright © 2010 Intel Corporation
3848b8605Smrg *
4848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5848b8605Smrg * copy of this software and associated documentation files (the "Software"),
6848b8605Smrg * to deal in the Software without restriction, including without limitation
7848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
9848b8605Smrg * Software is furnished to do so, subject to the following conditions:
10848b8605Smrg *
11848b8605Smrg * The above copyright notice and this permission notice (including the next
12848b8605Smrg * paragraph) shall be included in all copies or substantial portions of the
13848b8605Smrg * Software.
14848b8605Smrg *
15848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16848b8605Smrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17848b8605Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18848b8605Smrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19848b8605Smrg * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20848b8605Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21848b8605Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22848b8605Smrg * DEALINGS IN THE SOFTWARE.
23848b8605Smrg *
24848b8605Smrg * Authors:
25848b8605Smrg *    Kristian Høgsberg <krh@bitplanet.net>
26848b8605Smrg */
27848b8605Smrg
28b8e80941Smrg#include <stdbool.h>
29b8e80941Smrg#include <stdint.h>
30b8e80941Smrg#include <stdbool.h>
31848b8605Smrg#include <stdlib.h>
32848b8605Smrg#include <string.h>
33848b8605Smrg#include <stdio.h>
34848b8605Smrg#include <limits.h>
35848b8605Smrg#include <dlfcn.h>
36848b8605Smrg#include <fcntl.h>
37848b8605Smrg#include <errno.h>
38848b8605Smrg#include <unistd.h>
39b8e80941Smrg#include <c11/threads.h>
40b8e80941Smrg#include <time.h>
41848b8605Smrg#ifdef HAVE_LIBDRM
42848b8605Smrg#include <xf86drm.h>
43b8e80941Smrg#include "drm-uapi/drm_fourcc.h"
44848b8605Smrg#endif
45848b8605Smrg#include <GL/gl.h>
46848b8605Smrg#include <GL/internal/dri_interface.h>
47848b8605Smrg#include <sys/types.h>
48848b8605Smrg#include <sys/stat.h>
49848b8605Smrg
50848b8605Smrg#ifdef HAVE_WAYLAND_PLATFORM
51b8e80941Smrg#include <wayland-client.h>
52848b8605Smrg#include "wayland-drm.h"
53848b8605Smrg#include "wayland-drm-client-protocol.h"
54b8e80941Smrg#include "linux-dmabuf-unstable-v1-client-protocol.h"
55b8e80941Smrg#endif
56b8e80941Smrg
57b8e80941Smrg#ifdef HAVE_X11_PLATFORM
58b8e80941Smrg#include "X11/Xlibint.h"
59848b8605Smrg#endif
60848b8605Smrg
61b8e80941Smrg#include "egldefines.h"
62848b8605Smrg#include "egl_dri2.h"
63b8e80941Smrg#include "GL/mesa_glinterop.h"
64b8e80941Smrg#include "loader/loader.h"
65b8e80941Smrg#include "util/u_atomic.h"
66b8e80941Smrg#include "util/u_vector.h"
67b8e80941Smrg#include "mapi/glapi/glapi.h"
68b8e80941Smrg
69b8e80941Smrg/* Additional definitions not yet in the drm_fourcc.h.
70b8e80941Smrg */
71b8e80941Smrg#ifndef DRM_FORMAT_P010
72b8e80941Smrg#define DRM_FORMAT_P010 	 fourcc_code('P', '0', '1', '0') /* 2x2 subsampled Cb:Cr plane 10 bits per channel */
73b8e80941Smrg#endif
74b8e80941Smrg
75b8e80941Smrg#ifndef DRM_FORMAT_P012
76b8e80941Smrg#define DRM_FORMAT_P012 	 fourcc_code('P', '0', '1', '2') /* 2x2 subsampled Cb:Cr plane 12 bits per channel */
77b8e80941Smrg#endif
78b8e80941Smrg
79b8e80941Smrg#ifndef DRM_FORMAT_P016
80b8e80941Smrg#define DRM_FORMAT_P016 	 fourcc_code('P', '0', '1', '6') /* 2x2 subsampled Cb:Cr plane 16 bits per channel */
81b8e80941Smrg#endif
82b8e80941Smrg
83b8e80941Smrg#define NUM_ATTRIBS 12
84b8e80941Smrg
85b8e80941Smrgstatic void
86b8e80941Smrgdri_set_background_context(void *loaderPrivate)
87b8e80941Smrg{
88b8e80941Smrg   _EGLContext *ctx = _eglGetCurrentContext();
89b8e80941Smrg   _EGLThreadInfo *t = _eglGetCurrentThread();
90b8e80941Smrg
91b8e80941Smrg   _eglBindContextToThread(ctx, t);
92b8e80941Smrg}
93b8e80941Smrg
94b8e80941Smrgstatic void
95b8e80941Smrgdri2_gl_flush()
96b8e80941Smrg{
97b8e80941Smrg   static void (*glFlush)(void);
98b8e80941Smrg   static mtx_t glFlushMutex = _MTX_INITIALIZER_NP;
99b8e80941Smrg
100b8e80941Smrg   mtx_lock(&glFlushMutex);
101b8e80941Smrg   if (!glFlush)
102b8e80941Smrg      glFlush = _glapi_get_proc_address("glFlush");
103b8e80941Smrg   mtx_unlock(&glFlushMutex);
104b8e80941Smrg
105b8e80941Smrg   /* if glFlush is not available things are horribly broken */
106b8e80941Smrg   if (!glFlush) {
107b8e80941Smrg      _eglLog(_EGL_WARNING, "DRI2: failed to find glFlush entry point");
108b8e80941Smrg      return;
109b8e80941Smrg   }
110b8e80941Smrg
111b8e80941Smrg   glFlush();
112b8e80941Smrg}
113b8e80941Smrg
114b8e80941Smrgstatic GLboolean
115b8e80941Smrgdri_is_thread_safe(void *loaderPrivate)
116b8e80941Smrg{
117b8e80941Smrg   struct dri2_egl_surface *dri2_surf = loaderPrivate;
118b8e80941Smrg   MAYBE_UNUSED _EGLDisplay *display =  dri2_surf->base.Resource.Display;
119b8e80941Smrg
120b8e80941Smrg#ifdef HAVE_X11_PLATFORM
121b8e80941Smrg   Display *xdpy = (Display*)display->PlatformDisplay;
122b8e80941Smrg
123b8e80941Smrg   /* Check Xlib is running in thread safe mode when running on EGL/X11-xlib
124b8e80941Smrg    * platform
125b8e80941Smrg    *
126b8e80941Smrg    * 'lock_fns' is the XLockDisplay function pointer of the X11 display 'dpy'.
127b8e80941Smrg    * It wll be NULL if XInitThreads wasn't called.
128b8e80941Smrg    */
129b8e80941Smrg   if (display->Platform == _EGL_PLATFORM_X11 && xdpy && !xdpy->lock_fns)
130b8e80941Smrg      return false;
131b8e80941Smrg#endif
132b8e80941Smrg
133b8e80941Smrg#ifdef HAVE_WAYLAND_PLATFORM
134b8e80941Smrg   if (display->Platform == _EGL_PLATFORM_WAYLAND)
135b8e80941Smrg      return true;
136b8e80941Smrg#endif
137b8e80941Smrg
138b8e80941Smrg   return true;
139b8e80941Smrg}
140b8e80941Smrg
141b8e80941Smrgconst __DRIbackgroundCallableExtension background_callable_extension = {
142b8e80941Smrg   .base = { __DRI_BACKGROUND_CALLABLE, 2 },
143b8e80941Smrg
144b8e80941Smrg   .setBackgroundContext = dri_set_background_context,
145b8e80941Smrg   .isThreadSafe         = dri_is_thread_safe,
146b8e80941Smrg};
147848b8605Smrg
148848b8605Smrgconst __DRIuseInvalidateExtension use_invalidate = {
149848b8605Smrg   .base = { __DRI_USE_INVALIDATE, 1 }
150848b8605Smrg};
151848b8605Smrg
152b8e80941Smrgstatic const EGLint dri2_to_egl_attribute_map[__DRI_ATTRIB_MAX] = {
153b8e80941Smrg   [__DRI_ATTRIB_BUFFER_SIZE ]          = EGL_BUFFER_SIZE,
154b8e80941Smrg   [__DRI_ATTRIB_LEVEL]                 = EGL_LEVEL,
155b8e80941Smrg   [__DRI_ATTRIB_RED_SIZE]              = EGL_RED_SIZE,
156b8e80941Smrg   [__DRI_ATTRIB_GREEN_SIZE]            = EGL_GREEN_SIZE,
157b8e80941Smrg   [__DRI_ATTRIB_BLUE_SIZE]             = EGL_BLUE_SIZE,
158b8e80941Smrg   [__DRI_ATTRIB_LUMINANCE_SIZE]        = EGL_LUMINANCE_SIZE,
159b8e80941Smrg   [__DRI_ATTRIB_ALPHA_SIZE]            = EGL_ALPHA_SIZE,
160b8e80941Smrg   [__DRI_ATTRIB_DEPTH_SIZE]            = EGL_DEPTH_SIZE,
161b8e80941Smrg   [__DRI_ATTRIB_STENCIL_SIZE]          = EGL_STENCIL_SIZE,
162b8e80941Smrg   [__DRI_ATTRIB_SAMPLE_BUFFERS]        = EGL_SAMPLE_BUFFERS,
163b8e80941Smrg   [__DRI_ATTRIB_SAMPLES]               = EGL_SAMPLES,
164b8e80941Smrg   [__DRI_ATTRIB_MAX_PBUFFER_WIDTH]     = EGL_MAX_PBUFFER_WIDTH,
165b8e80941Smrg   [__DRI_ATTRIB_MAX_PBUFFER_HEIGHT]    = EGL_MAX_PBUFFER_HEIGHT,
166b8e80941Smrg   [__DRI_ATTRIB_MAX_PBUFFER_PIXELS]    = EGL_MAX_PBUFFER_PIXELS,
167b8e80941Smrg   [__DRI_ATTRIB_MAX_SWAP_INTERVAL]     = EGL_MAX_SWAP_INTERVAL,
168b8e80941Smrg   [__DRI_ATTRIB_MIN_SWAP_INTERVAL]     = EGL_MIN_SWAP_INTERVAL,
169b8e80941Smrg   [__DRI_ATTRIB_YINVERTED]             = EGL_Y_INVERTED_NOK,
170848b8605Smrg};
171848b8605Smrg
172b8e80941Smrgconst __DRIconfig *
173b8e80941Smrgdri2_get_dri_config(struct dri2_egl_config *conf, EGLint surface_type,
174b8e80941Smrg                    EGLenum colorspace)
175b8e80941Smrg{
176b8e80941Smrg   const bool double_buffer = surface_type == EGL_WINDOW_BIT;
177b8e80941Smrg   const bool srgb = colorspace == EGL_GL_COLORSPACE_SRGB_KHR;
178b8e80941Smrg
179b8e80941Smrg   return conf->dri_config[double_buffer][srgb];
180b8e80941Smrg}
181b8e80941Smrg
182848b8605Smrgstatic EGLBoolean
183848b8605Smrgdri2_match_config(const _EGLConfig *conf, const _EGLConfig *criteria)
184848b8605Smrg{
185848b8605Smrg   if (_eglCompareConfigs(conf, criteria, NULL, EGL_FALSE) != 0)
186848b8605Smrg      return EGL_FALSE;
187848b8605Smrg
188848b8605Smrg   if (!_eglMatchConfig(conf, criteria))
189848b8605Smrg      return EGL_FALSE;
190848b8605Smrg
191848b8605Smrg   return EGL_TRUE;
192848b8605Smrg}
193848b8605Smrg
194848b8605Smrgstruct dri2_egl_config *
195848b8605Smrgdri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id,
196b8e80941Smrg                EGLint surface_type, const EGLint *attr_list,
197b8e80941Smrg                const unsigned int *rgba_masks)
198848b8605Smrg{
199848b8605Smrg   struct dri2_egl_config *conf;
200b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
201848b8605Smrg   _EGLConfig base;
202848b8605Smrg   unsigned int attrib, value, double_buffer;
203b8e80941Smrg   bool srgb = false;
204848b8605Smrg   EGLint key, bind_to_texture_rgb, bind_to_texture_rgba;
205848b8605Smrg   unsigned int dri_masks[4] = { 0, 0, 0, 0 };
206848b8605Smrg   _EGLConfig *matching_config;
207848b8605Smrg   EGLint num_configs = 0;
208848b8605Smrg   EGLint config_id;
209848b8605Smrg
210848b8605Smrg   _eglInitConfig(&base, disp, id);
211b8e80941Smrg
212848b8605Smrg   double_buffer = 0;
213848b8605Smrg   bind_to_texture_rgb = 0;
214848b8605Smrg   bind_to_texture_rgba = 0;
215848b8605Smrg
216b8e80941Smrg   for (int i = 0; i < __DRI_ATTRIB_MAX; ++i) {
217b8e80941Smrg      if (!dri2_dpy->core->indexConfigAttrib(dri_config, i, &attrib, &value))
218b8e80941Smrg         break;
219b8e80941Smrg
220848b8605Smrg      switch (attrib) {
221848b8605Smrg      case __DRI_ATTRIB_RENDER_TYPE:
222b8e80941Smrg         if (value & __DRI_ATTRIB_RGBA_BIT)
223b8e80941Smrg            value = EGL_RGB_BUFFER;
224b8e80941Smrg         else if (value & __DRI_ATTRIB_LUMINANCE_BIT)
225b8e80941Smrg            value = EGL_LUMINANCE_BUFFER;
226b8e80941Smrg         else
227b8e80941Smrg            return NULL;
228b8e80941Smrg         _eglSetConfigKey(&base, EGL_COLOR_BUFFER_TYPE, value);
229b8e80941Smrg         break;
230848b8605Smrg
231848b8605Smrg      case __DRI_ATTRIB_CONFIG_CAVEAT:
232848b8605Smrg         if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
233848b8605Smrg            value = EGL_NON_CONFORMANT_CONFIG;
234848b8605Smrg         else if (value & __DRI_ATTRIB_SLOW_BIT)
235848b8605Smrg            value = EGL_SLOW_CONFIG;
236b8e80941Smrg         else
237b8e80941Smrg            value = EGL_NONE;
238b8e80941Smrg         _eglSetConfigKey(&base, EGL_CONFIG_CAVEAT, value);
239848b8605Smrg         break;
240848b8605Smrg
241848b8605Smrg      case __DRI_ATTRIB_BIND_TO_TEXTURE_RGB:
242b8e80941Smrg         bind_to_texture_rgb = value;
243b8e80941Smrg         break;
244848b8605Smrg
245848b8605Smrg      case __DRI_ATTRIB_BIND_TO_TEXTURE_RGBA:
246b8e80941Smrg         bind_to_texture_rgba = value;
247b8e80941Smrg         break;
248848b8605Smrg
249848b8605Smrg      case __DRI_ATTRIB_DOUBLE_BUFFER:
250b8e80941Smrg         double_buffer = value;
251b8e80941Smrg         break;
252848b8605Smrg
253848b8605Smrg      case __DRI_ATTRIB_RED_MASK:
254848b8605Smrg         dri_masks[0] = value;
255848b8605Smrg         break;
256848b8605Smrg
257848b8605Smrg      case __DRI_ATTRIB_GREEN_MASK:
258848b8605Smrg         dri_masks[1] = value;
259848b8605Smrg         break;
260848b8605Smrg
261848b8605Smrg      case __DRI_ATTRIB_BLUE_MASK:
262848b8605Smrg         dri_masks[2] = value;
263848b8605Smrg         break;
264848b8605Smrg
265848b8605Smrg      case __DRI_ATTRIB_ALPHA_MASK:
266848b8605Smrg         dri_masks[3] = value;
267848b8605Smrg         break;
268848b8605Smrg
269b8e80941Smrg      case __DRI_ATTRIB_ACCUM_RED_SIZE:
270b8e80941Smrg      case __DRI_ATTRIB_ACCUM_GREEN_SIZE:
271b8e80941Smrg      case __DRI_ATTRIB_ACCUM_BLUE_SIZE:
272b8e80941Smrg      case __DRI_ATTRIB_ACCUM_ALPHA_SIZE:
273b8e80941Smrg         /* Don't expose visuals with the accumulation buffer. */
274b8e80941Smrg         if (value > 0)
275b8e80941Smrg            return NULL;
276b8e80941Smrg         break;
277b8e80941Smrg
278b8e80941Smrg      case __DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE:
279b8e80941Smrg         srgb = value != 0;
280b8e80941Smrg         if (!disp->Extensions.KHR_gl_colorspace && srgb)
281b8e80941Smrg            return NULL;
282b8e80941Smrg         break;
283b8e80941Smrg
284b8e80941Smrg      case __DRI_ATTRIB_MAX_PBUFFER_WIDTH:
285b8e80941Smrg         _eglSetConfigKey(&base, EGL_MAX_PBUFFER_WIDTH,
286b8e80941Smrg                          _EGL_MAX_PBUFFER_WIDTH);
287b8e80941Smrg         break;
288b8e80941Smrg      case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT:
289b8e80941Smrg         _eglSetConfigKey(&base, EGL_MAX_PBUFFER_HEIGHT,
290b8e80941Smrg                          _EGL_MAX_PBUFFER_HEIGHT);
291b8e80941Smrg         break;
292b8e80941Smrg      case __DRI_ATTRIB_MUTABLE_RENDER_BUFFER:
293b8e80941Smrg         if (disp->Extensions.KHR_mutable_render_buffer)
294b8e80941Smrg            surface_type |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR;
295b8e80941Smrg         break;
296848b8605Smrg      default:
297b8e80941Smrg         key = dri2_to_egl_attribute_map[attrib];
298b8e80941Smrg         if (key != 0)
299b8e80941Smrg            _eglSetConfigKey(&base, key, value);
300b8e80941Smrg         break;
301848b8605Smrg      }
302848b8605Smrg   }
303848b8605Smrg
304848b8605Smrg   if (attr_list)
305b8e80941Smrg      for (int i = 0; attr_list[i] != EGL_NONE; i += 2)
306848b8605Smrg         _eglSetConfigKey(&base, attr_list[i], attr_list[i+1]);
307848b8605Smrg
308848b8605Smrg   if (rgba_masks && memcmp(rgba_masks, dri_masks, sizeof(dri_masks)))
309848b8605Smrg      return NULL;
310848b8605Smrg
311848b8605Smrg   base.NativeRenderable = EGL_TRUE;
312848b8605Smrg
313848b8605Smrg   base.SurfaceType = surface_type;
314848b8605Smrg   if (surface_type & (EGL_PBUFFER_BIT |
315848b8605Smrg       (disp->Extensions.NOK_texture_from_pixmap ? EGL_PIXMAP_BIT : 0))) {
316848b8605Smrg      base.BindToTextureRGB = bind_to_texture_rgb;
317848b8605Smrg      if (base.AlphaSize > 0)
318848b8605Smrg         base.BindToTextureRGBA = bind_to_texture_rgba;
319848b8605Smrg   }
320848b8605Smrg
321848b8605Smrg   base.RenderableType = disp->ClientAPIs;
322848b8605Smrg   base.Conformant = disp->ClientAPIs;
323848b8605Smrg
324848b8605Smrg   base.MinSwapInterval = dri2_dpy->min_swap_interval;
325848b8605Smrg   base.MaxSwapInterval = dri2_dpy->max_swap_interval;
326848b8605Smrg
327848b8605Smrg   if (!_eglValidateConfig(&base, EGL_FALSE)) {
328848b8605Smrg      _eglLog(_EGL_DEBUG, "DRI2: failed to validate config %d", id);
329848b8605Smrg      return NULL;
330848b8605Smrg   }
331848b8605Smrg
332848b8605Smrg   config_id = base.ConfigID;
333848b8605Smrg   base.ConfigID    = EGL_DONT_CARE;
334848b8605Smrg   base.SurfaceType = EGL_DONT_CARE;
335848b8605Smrg   num_configs = _eglFilterArray(disp->Configs, (void **) &matching_config, 1,
336848b8605Smrg                                 (_EGLArrayForEach) dri2_match_config, &base);
337848b8605Smrg
338848b8605Smrg   if (num_configs == 1) {
339848b8605Smrg      conf = (struct dri2_egl_config *) matching_config;
340848b8605Smrg
341b8e80941Smrg      if (!conf->dri_config[double_buffer][srgb])
342b8e80941Smrg         conf->dri_config[double_buffer][srgb] = dri_config;
343848b8605Smrg      else
344848b8605Smrg         /* a similar config type is already added (unlikely) => discard */
345848b8605Smrg         return NULL;
346848b8605Smrg   }
347848b8605Smrg   else if (num_configs == 0) {
348b8e80941Smrg      conf = calloc(1, sizeof *conf);
349848b8605Smrg      if (conf == NULL)
350848b8605Smrg         return NULL;
351848b8605Smrg
352b8e80941Smrg      conf->dri_config[double_buffer][srgb] = dri_config;
353b8e80941Smrg
354848b8605Smrg      memcpy(&conf->base, &base, sizeof base);
355848b8605Smrg      conf->base.SurfaceType = 0;
356848b8605Smrg      conf->base.ConfigID = config_id;
357848b8605Smrg
358848b8605Smrg      _eglLinkConfig(&conf->base);
359848b8605Smrg   }
360848b8605Smrg   else {
361b8e80941Smrg      unreachable("duplicates should not be possible");
362848b8605Smrg      return NULL;
363848b8605Smrg   }
364848b8605Smrg
365848b8605Smrg   if (double_buffer) {
366848b8605Smrg      surface_type &= ~EGL_PIXMAP_BIT;
367848b8605Smrg   }
368848b8605Smrg
369b8e80941Smrg   /* No support for pbuffer + MSAA for now.
370b8e80941Smrg    *
371b8e80941Smrg    * XXX TODO: pbuffer + MSAA does not work and causes crashes.
372b8e80941Smrg    * See QT bugreport: https://bugreports.qt.io/browse/QTBUG-47509
373b8e80941Smrg    */
374b8e80941Smrg   if (base.Samples) {
375b8e80941Smrg      surface_type &= ~EGL_PBUFFER_BIT;
376b8e80941Smrg   }
377b8e80941Smrg
378848b8605Smrg   conf->base.SurfaceType |= surface_type;
379848b8605Smrg
380848b8605Smrg   return conf;
381848b8605Smrg}
382848b8605Smrg
383848b8605Smrg__DRIimage *
384848b8605Smrgdri2_lookup_egl_image(__DRIscreen *screen, void *image, void *data)
385848b8605Smrg{
386848b8605Smrg   _EGLDisplay *disp = data;
387848b8605Smrg   struct dri2_egl_image *dri2_img;
388848b8605Smrg   _EGLImage *img;
389848b8605Smrg
390848b8605Smrg   (void) screen;
391848b8605Smrg
392848b8605Smrg   img = _eglLookupImage(image, disp);
393848b8605Smrg   if (img == NULL) {
394848b8605Smrg      _eglError(EGL_BAD_PARAMETER, "dri2_lookup_egl_image");
395848b8605Smrg      return NULL;
396848b8605Smrg   }
397848b8605Smrg
398848b8605Smrg   dri2_img = dri2_egl_image(image);
399848b8605Smrg
400848b8605Smrg   return dri2_img->dri_image;
401848b8605Smrg}
402848b8605Smrg
403848b8605Smrgconst __DRIimageLookupExtension image_lookup_extension = {
404848b8605Smrg   .base = { __DRI_IMAGE_LOOKUP, 1 },
405848b8605Smrg
406848b8605Smrg   .lookupEGLImage       = dri2_lookup_egl_image
407848b8605Smrg};
408848b8605Smrg
409848b8605Smrgstruct dri2_extension_match {
410848b8605Smrg   const char *name;
411848b8605Smrg   int version;
412848b8605Smrg   int offset;
413848b8605Smrg};
414848b8605Smrg
415b8e80941Smrgstatic const struct dri2_extension_match dri3_driver_extensions[] = {
416b8e80941Smrg   { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
417b8e80941Smrg   { __DRI_IMAGE_DRIVER, 1, offsetof(struct dri2_egl_display, image_driver) },
418b8e80941Smrg   { NULL, 0, 0 }
419b8e80941Smrg};
420b8e80941Smrg
421b8e80941Smrgstatic const struct dri2_extension_match dri2_driver_extensions[] = {
422848b8605Smrg   { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
423848b8605Smrg   { __DRI_DRI2, 2, offsetof(struct dri2_egl_display, dri2) },
424848b8605Smrg   { NULL, 0, 0 }
425848b8605Smrg};
426848b8605Smrg
427b8e80941Smrgstatic const struct dri2_extension_match dri2_core_extensions[] = {
428848b8605Smrg   { __DRI2_FLUSH, 1, offsetof(struct dri2_egl_display, flush) },
429848b8605Smrg   { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
430848b8605Smrg   { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
431848b8605Smrg   { NULL, 0, 0 }
432848b8605Smrg};
433848b8605Smrg
434b8e80941Smrgstatic const struct dri2_extension_match swrast_driver_extensions[] = {
435848b8605Smrg   { __DRI_CORE, 1, offsetof(struct dri2_egl_display, core) },
436848b8605Smrg   { __DRI_SWRAST, 2, offsetof(struct dri2_egl_display, swrast) },
437848b8605Smrg   { NULL, 0, 0 }
438848b8605Smrg};
439848b8605Smrg
440b8e80941Smrgstatic const struct dri2_extension_match swrast_core_extensions[] = {
441848b8605Smrg   { __DRI_TEX_BUFFER, 2, offsetof(struct dri2_egl_display, tex_buffer) },
442848b8605Smrg   { NULL, 0, 0 }
443848b8605Smrg};
444848b8605Smrg
445b8e80941Smrgstatic const struct dri2_extension_match optional_driver_extensions[] = {
446b8e80941Smrg   { __DRI_CONFIG_OPTIONS, 1, offsetof(struct dri2_egl_display, configOptions) },
447b8e80941Smrg   { NULL, 0, 0 }
448b8e80941Smrg};
449b8e80941Smrg
450b8e80941Smrgstatic const struct dri2_extension_match optional_core_extensions[] = {
451b8e80941Smrg   { __DRI2_ROBUSTNESS, 1, offsetof(struct dri2_egl_display, robustness) },
452b8e80941Smrg   { __DRI2_NO_ERROR, 1, offsetof(struct dri2_egl_display, no_error) },
453b8e80941Smrg   { __DRI2_CONFIG_QUERY, 1, offsetof(struct dri2_egl_display, config) },
454b8e80941Smrg   { __DRI2_FENCE, 1, offsetof(struct dri2_egl_display, fence) },
455b8e80941Smrg   { __DRI2_RENDERER_QUERY, 1, offsetof(struct dri2_egl_display, rendererQuery) },
456b8e80941Smrg   { __DRI2_INTEROP, 1, offsetof(struct dri2_egl_display, interop) },
457b8e80941Smrg   { __DRI_IMAGE, 1, offsetof(struct dri2_egl_display, image) },
458b8e80941Smrg   { __DRI2_FLUSH_CONTROL, 1, offsetof(struct dri2_egl_display, flush_control) },
459b8e80941Smrg   { __DRI2_BLOB, 1, offsetof(struct dri2_egl_display, blob) },
460b8e80941Smrg   { __DRI_MUTABLE_RENDER_BUFFER_DRIVER, 1, offsetof(struct dri2_egl_display, mutable_render_buffer) },
461b8e80941Smrg   { NULL, 0, 0 }
462b8e80941Smrg};
463b8e80941Smrg
464848b8605Smrgstatic EGLBoolean
465848b8605Smrgdri2_bind_extensions(struct dri2_egl_display *dri2_dpy,
466b8e80941Smrg                     const struct dri2_extension_match *matches,
467b8e80941Smrg                     const __DRIextension **extensions,
468b8e80941Smrg                     bool optional)
469848b8605Smrg{
470b8e80941Smrg   int ret = EGL_TRUE;
471848b8605Smrg   void *field;
472848b8605Smrg
473b8e80941Smrg   for (int i = 0; extensions[i]; i++) {
474b8e80941Smrg      _eglLog(_EGL_DEBUG, "found extension `%s'", extensions[i]->name);
475b8e80941Smrg      for (int j = 0; matches[j].name; j++) {
476b8e80941Smrg         if (strcmp(extensions[i]->name, matches[j].name) == 0 &&
477b8e80941Smrg             extensions[i]->version >= matches[j].version) {
478b8e80941Smrg            field = ((char *) dri2_dpy + matches[j].offset);
479b8e80941Smrg            *(const __DRIextension **) field = extensions[i];
480b8e80941Smrg            _eglLog(_EGL_INFO, "found extension %s version %d",
481b8e80941Smrg                    extensions[i]->name, extensions[i]->version);
482b8e80941Smrg            break;
483b8e80941Smrg         }
484848b8605Smrg      }
485848b8605Smrg   }
486b8e80941Smrg
487b8e80941Smrg   for (int j = 0; matches[j].name; j++) {
488848b8605Smrg      field = ((char *) dri2_dpy + matches[j].offset);
489848b8605Smrg      if (*(const __DRIextension **) field == NULL) {
490b8e80941Smrg         if (optional) {
491b8e80941Smrg            _eglLog(_EGL_DEBUG, "did not find optional extension %s version %d",
492b8e80941Smrg                    matches[j].name, matches[j].version);
493b8e80941Smrg         } else {
494b8e80941Smrg            _eglLog(_EGL_WARNING, "did not find extension %s version %d",
495b8e80941Smrg                    matches[j].name, matches[j].version);
496b8e80941Smrg            ret = EGL_FALSE;
497b8e80941Smrg         }
498848b8605Smrg      }
499848b8605Smrg   }
500848b8605Smrg
501848b8605Smrg   return ret;
502848b8605Smrg}
503848b8605Smrg
504848b8605Smrgstatic const __DRIextension **
505848b8605Smrgdri2_open_driver(_EGLDisplay *disp)
506848b8605Smrg{
507b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
508b8e80941Smrg   static const char *search_path_vars[] = {
509b8e80941Smrg      "LIBGL_DRIVERS_PATH",
510b8e80941Smrg      NULL,
511b8e80941Smrg   };
512b8e80941Smrg
513b8e80941Smrg   return loader_open_driver(dri2_dpy->driver_name,
514b8e80941Smrg                             &dri2_dpy->driver,
515b8e80941Smrg                             search_path_vars);
516848b8605Smrg}
517848b8605Smrg
518b8e80941Smrgstatic EGLBoolean
519b8e80941Smrgdri2_load_driver_common(_EGLDisplay *disp,
520b8e80941Smrg                        const struct dri2_extension_match *driver_extensions)
521848b8605Smrg{
522b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
523848b8605Smrg   const __DRIextension **extensions;
524848b8605Smrg
525848b8605Smrg   extensions = dri2_open_driver(disp);
526848b8605Smrg   if (!extensions)
527848b8605Smrg      return EGL_FALSE;
528848b8605Smrg
529b8e80941Smrg   if (!dri2_bind_extensions(dri2_dpy, driver_extensions, extensions, false)) {
530848b8605Smrg      dlclose(dri2_dpy->driver);
531848b8605Smrg      return EGL_FALSE;
532848b8605Smrg   }
533848b8605Smrg   dri2_dpy->driver_extensions = extensions;
534848b8605Smrg
535b8e80941Smrg   dri2_bind_extensions(dri2_dpy, optional_driver_extensions, extensions, true);
536b8e80941Smrg
537848b8605Smrg   return EGL_TRUE;
538848b8605Smrg}
539848b8605Smrg
540b8e80941SmrgEGLBoolean
541b8e80941Smrgdri2_load_driver(_EGLDisplay *disp)
542b8e80941Smrg{
543b8e80941Smrg   return dri2_load_driver_common(disp, dri2_driver_extensions);
544b8e80941Smrg}
545b8e80941Smrg
546b8e80941SmrgEGLBoolean
547b8e80941Smrgdri2_load_driver_dri3(_EGLDisplay *disp)
548b8e80941Smrg{
549b8e80941Smrg   return dri2_load_driver_common(disp, dri3_driver_extensions);
550b8e80941Smrg}
551b8e80941Smrg
552848b8605SmrgEGLBoolean
553848b8605Smrgdri2_load_driver_swrast(_EGLDisplay *disp)
554848b8605Smrg{
555b8e80941Smrg   return dri2_load_driver_common(disp, swrast_driver_extensions);
556b8e80941Smrg}
557848b8605Smrg
558b8e80941Smrgstatic unsigned
559b8e80941Smrgdri2_renderer_query_integer(struct dri2_egl_display *dri2_dpy, int param)
560b8e80941Smrg{
561b8e80941Smrg   const __DRI2rendererQueryExtension *rendererQuery = dri2_dpy->rendererQuery;
562b8e80941Smrg   unsigned int value = 0;
563848b8605Smrg
564b8e80941Smrg   if (!rendererQuery ||
565b8e80941Smrg       rendererQuery->queryInteger(dri2_dpy->dri_screen, param, &value) == -1)
566b8e80941Smrg      return 0;
567848b8605Smrg
568b8e80941Smrg   return value;
569b8e80941Smrg}
570b8e80941Smrg
571b8e80941Smrgstatic const char *
572b8e80941Smrgdri2_query_driver_name(_EGLDisplay *disp)
573b8e80941Smrg{
574b8e80941Smrg    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
575b8e80941Smrg    return dri2_dpy->driver_name;
576b8e80941Smrg}
577b8e80941Smrg
578b8e80941Smrgstatic char *
579b8e80941Smrgdri2_query_driver_config(_EGLDisplay *disp)
580b8e80941Smrg{
581b8e80941Smrg    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
582b8e80941Smrg    const __DRIconfigOptionsExtension *ext = dri2_dpy->configOptions;
583b8e80941Smrg
584b8e80941Smrg    if (ext->base.version >= 2)
585b8e80941Smrg        return ext->getXml(dri2_dpy->driver_name);
586b8e80941Smrg
587b8e80941Smrg    return strdup(ext->xml);
588848b8605Smrg}
589848b8605Smrg
590b8e80941Smrg
591848b8605Smrgvoid
592848b8605Smrgdri2_setup_screen(_EGLDisplay *disp)
593848b8605Smrg{
594848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
595848b8605Smrg   unsigned int api_mask;
596848b8605Smrg
597b8e80941Smrg   /*
598b8e80941Smrg    * EGL 1.5 specification defines the default value to 1. Moreover,
599b8e80941Smrg    * eglSwapInterval() is required to clamp requested value to the supported
600b8e80941Smrg    * range. Since the default value is implicitly assumed to be supported,
601b8e80941Smrg    * use it as both minimum and maximum for the platforms that do not allow
602b8e80941Smrg    * changing the interval. Platforms, which allow it (e.g. x11, wayland)
603b8e80941Smrg    * override these values already.
604b8e80941Smrg    */
605b8e80941Smrg   dri2_dpy->min_swap_interval = 1;
606b8e80941Smrg   dri2_dpy->max_swap_interval = 1;
607b8e80941Smrg   dri2_dpy->default_swap_interval = 1;
608b8e80941Smrg
609b8e80941Smrg   if (dri2_dpy->image_driver) {
610b8e80941Smrg      api_mask = dri2_dpy->image_driver->getAPIMask(dri2_dpy->dri_screen);
611b8e80941Smrg   } else if (dri2_dpy->dri2) {
612848b8605Smrg      api_mask = dri2_dpy->dri2->getAPIMask(dri2_dpy->dri_screen);
613848b8605Smrg   } else {
614848b8605Smrg      assert(dri2_dpy->swrast);
615848b8605Smrg      api_mask = 1 << __DRI_API_OPENGL |
616848b8605Smrg                 1 << __DRI_API_GLES |
617848b8605Smrg                 1 << __DRI_API_GLES2 |
618848b8605Smrg                 1 << __DRI_API_GLES3;
619848b8605Smrg   }
620848b8605Smrg
621848b8605Smrg   disp->ClientAPIs = 0;
622b8e80941Smrg   if ((api_mask & (1 <<__DRI_API_OPENGL)) && _eglIsApiValid(EGL_OPENGL_API))
623848b8605Smrg      disp->ClientAPIs |= EGL_OPENGL_BIT;
624b8e80941Smrg   if ((api_mask & (1 << __DRI_API_GLES)) && _eglIsApiValid(EGL_OPENGL_ES_API))
625848b8605Smrg      disp->ClientAPIs |= EGL_OPENGL_ES_BIT;
626b8e80941Smrg   if ((api_mask & (1 << __DRI_API_GLES2)) && _eglIsApiValid(EGL_OPENGL_ES_API))
627848b8605Smrg      disp->ClientAPIs |= EGL_OPENGL_ES2_BIT;
628b8e80941Smrg   if ((api_mask & (1 << __DRI_API_GLES3)) && _eglIsApiValid(EGL_OPENGL_ES_API))
629848b8605Smrg      disp->ClientAPIs |= EGL_OPENGL_ES3_BIT_KHR;
630848b8605Smrg
631b8e80941Smrg   assert(dri2_dpy->image_driver || dri2_dpy->dri2 || dri2_dpy->swrast);
632b8e80941Smrg   disp->Extensions.KHR_no_config_context = EGL_TRUE;
633848b8605Smrg   disp->Extensions.KHR_surfaceless_context = EGL_TRUE;
634848b8605Smrg
635b8e80941Smrg   if (dri2_dpy->configOptions) {
636b8e80941Smrg       disp->Extensions.MESA_query_driver = EGL_TRUE;
637b8e80941Smrg   }
638b8e80941Smrg
639b8e80941Smrg   /* Report back to EGL the bitmask of priorities supported */
640b8e80941Smrg   disp->Extensions.IMG_context_priority =
641b8e80941Smrg      dri2_renderer_query_integer(dri2_dpy,
642b8e80941Smrg                                  __DRI2_RENDERER_HAS_CONTEXT_PRIORITY);
643b8e80941Smrg
644b8e80941Smrg   disp->Extensions.EXT_pixel_format_float = EGL_TRUE;
645b8e80941Smrg
646b8e80941Smrg   if (dri2_renderer_query_integer(dri2_dpy,
647b8e80941Smrg                                   __DRI2_RENDERER_HAS_FRAMEBUFFER_SRGB))
648b8e80941Smrg      disp->Extensions.KHR_gl_colorspace = EGL_TRUE;
649b8e80941Smrg
650b8e80941Smrg   if (dri2_dpy->image_driver ||
651b8e80941Smrg       (dri2_dpy->dri2 && dri2_dpy->dri2->base.version >= 3) ||
652b8e80941Smrg       (dri2_dpy->swrast && dri2_dpy->swrast->base.version >= 3)) {
653848b8605Smrg      disp->Extensions.KHR_create_context = EGL_TRUE;
654848b8605Smrg
655848b8605Smrg      if (dri2_dpy->robustness)
656848b8605Smrg         disp->Extensions.EXT_create_context_robustness = EGL_TRUE;
657848b8605Smrg   }
658848b8605Smrg
659b8e80941Smrg   if (dri2_dpy->no_error)
660b8e80941Smrg      disp->Extensions.KHR_create_context_no_error = EGL_TRUE;
661b8e80941Smrg
662b8e80941Smrg   if (dri2_dpy->fence) {
663b8e80941Smrg      disp->Extensions.KHR_fence_sync = EGL_TRUE;
664b8e80941Smrg      disp->Extensions.KHR_wait_sync = EGL_TRUE;
665b8e80941Smrg      if (dri2_dpy->fence->get_fence_from_cl_event)
666b8e80941Smrg         disp->Extensions.KHR_cl_event2 = EGL_TRUE;
667b8e80941Smrg      if (dri2_dpy->fence->base.version >= 2 &&
668b8e80941Smrg          dri2_dpy->fence->get_capabilities) {
669b8e80941Smrg         unsigned capabilities =
670b8e80941Smrg            dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen);
671b8e80941Smrg         disp->Extensions.ANDROID_native_fence_sync =
672b8e80941Smrg            (capabilities & __DRI_FENCE_CAP_NATIVE_FD) != 0;
673b8e80941Smrg      }
674b8e80941Smrg   }
675b8e80941Smrg
676b8e80941Smrg   if (dri2_dpy->blob)
677b8e80941Smrg      disp->Extensions.ANDROID_blob_cache = EGL_TRUE;
678b8e80941Smrg
679b8e80941Smrg   disp->Extensions.KHR_reusable_sync = EGL_TRUE;
680b8e80941Smrg
681848b8605Smrg   if (dri2_dpy->image) {
682848b8605Smrg      if (dri2_dpy->image->base.version >= 10 &&
683848b8605Smrg          dri2_dpy->image->getCapabilities != NULL) {
684848b8605Smrg         int capabilities;
685848b8605Smrg
686848b8605Smrg         capabilities = dri2_dpy->image->getCapabilities(dri2_dpy->dri_screen);
687848b8605Smrg         disp->Extensions.MESA_drm_image = (capabilities & __DRI_IMAGE_CAP_GLOBAL_NAMES) != 0;
688b8e80941Smrg
689b8e80941Smrg         if (dri2_dpy->image->base.version >= 11)
690b8e80941Smrg            disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
691b8e80941Smrg      } else {
692848b8605Smrg         disp->Extensions.MESA_drm_image = EGL_TRUE;
693b8e80941Smrg         if (dri2_dpy->image->base.version >= 11)
694b8e80941Smrg            disp->Extensions.MESA_image_dma_buf_export = EGL_TRUE;
695b8e80941Smrg      }
696848b8605Smrg
697848b8605Smrg      disp->Extensions.KHR_image_base = EGL_TRUE;
698848b8605Smrg      disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE;
699848b8605Smrg      if (dri2_dpy->image->base.version >= 5 &&
700848b8605Smrg          dri2_dpy->image->createImageFromTexture) {
701848b8605Smrg         disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE;
702848b8605Smrg         disp->Extensions.KHR_gl_texture_cubemap_image = EGL_TRUE;
703b8e80941Smrg
704b8e80941Smrg         if (dri2_renderer_query_integer(dri2_dpy,
705b8e80941Smrg                                         __DRI2_RENDERER_HAS_TEXTURE_3D))
706b8e80941Smrg             disp->Extensions.KHR_gl_texture_3D_image = EGL_TRUE;
707848b8605Smrg      }
708b8e80941Smrg#ifdef HAVE_LIBDRM
709848b8605Smrg      if (dri2_dpy->image->base.version >= 8 &&
710848b8605Smrg          dri2_dpy->image->createImageFromDmaBufs) {
711848b8605Smrg         disp->Extensions.EXT_image_dma_buf_import = EGL_TRUE;
712848b8605Smrg      }
713b8e80941Smrg      if (dri2_dpy->image->base.version >= 15 &&
714b8e80941Smrg          dri2_dpy->image->createImageFromDmaBufs2 &&
715b8e80941Smrg          dri2_dpy->image->queryDmaBufFormats &&
716b8e80941Smrg          dri2_dpy->image->queryDmaBufModifiers) {
717b8e80941Smrg         disp->Extensions.EXT_image_dma_buf_import_modifiers = EGL_TRUE;
718b8e80941Smrg      }
719848b8605Smrg#endif
720848b8605Smrg   }
721b8e80941Smrg
722b8e80941Smrg   if (dri2_dpy->flush_control)
723b8e80941Smrg      disp->Extensions.KHR_context_flush_control = EGL_TRUE;
724b8e80941Smrg}
725b8e80941Smrg
726b8e80941Smrgvoid
727b8e80941Smrgdri2_setup_swap_interval(_EGLDisplay *disp, int max_swap_interval)
728b8e80941Smrg{
729b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
730b8e80941Smrg   GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1;
731b8e80941Smrg
732b8e80941Smrg   /* Allow driconf to override applications.*/
733b8e80941Smrg   if (dri2_dpy->config)
734b8e80941Smrg      dri2_dpy->config->configQueryi(dri2_dpy->dri_screen,
735b8e80941Smrg                                     "vblank_mode", &vblank_mode);
736b8e80941Smrg   switch (vblank_mode) {
737b8e80941Smrg   case DRI_CONF_VBLANK_NEVER:
738b8e80941Smrg      dri2_dpy->min_swap_interval = 0;
739b8e80941Smrg      dri2_dpy->max_swap_interval = 0;
740b8e80941Smrg      dri2_dpy->default_swap_interval = 0;
741b8e80941Smrg      break;
742b8e80941Smrg   case DRI_CONF_VBLANK_ALWAYS_SYNC:
743b8e80941Smrg      dri2_dpy->min_swap_interval = 1;
744b8e80941Smrg      dri2_dpy->max_swap_interval = max_swap_interval;
745b8e80941Smrg      dri2_dpy->default_swap_interval = 1;
746b8e80941Smrg      break;
747b8e80941Smrg   case DRI_CONF_VBLANK_DEF_INTERVAL_0:
748b8e80941Smrg      dri2_dpy->min_swap_interval = 0;
749b8e80941Smrg      dri2_dpy->max_swap_interval = max_swap_interval;
750b8e80941Smrg      dri2_dpy->default_swap_interval = 0;
751b8e80941Smrg      break;
752b8e80941Smrg   default:
753b8e80941Smrg   case DRI_CONF_VBLANK_DEF_INTERVAL_1:
754b8e80941Smrg      dri2_dpy->min_swap_interval = 0;
755b8e80941Smrg      dri2_dpy->max_swap_interval = max_swap_interval;
756b8e80941Smrg      dri2_dpy->default_swap_interval = 1;
757b8e80941Smrg      break;
758b8e80941Smrg   }
759848b8605Smrg}
760848b8605Smrg
761b8e80941Smrg/* All platforms but DRM call this function to create the screen and populate
762b8e80941Smrg * the driver_configs. DRM inherits that information from its display - GBM.
763b8e80941Smrg */
764848b8605SmrgEGLBoolean
765848b8605Smrgdri2_create_screen(_EGLDisplay *disp)
766848b8605Smrg{
767b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
768848b8605Smrg
769b8e80941Smrg   if (dri2_dpy->image_driver) {
770b8e80941Smrg      dri2_dpy->dri_screen =
771b8e80941Smrg         dri2_dpy->image_driver->createNewScreen2(0, dri2_dpy->fd,
772b8e80941Smrg                                                  dri2_dpy->loader_extensions,
773b8e80941Smrg                                                  dri2_dpy->driver_extensions,
774b8e80941Smrg                                                  &dri2_dpy->driver_configs,
775b8e80941Smrg                                                  disp);
776b8e80941Smrg   } else if (dri2_dpy->dri2) {
777848b8605Smrg      if (dri2_dpy->dri2->base.version >= 4) {
778848b8605Smrg         dri2_dpy->dri_screen =
779848b8605Smrg            dri2_dpy->dri2->createNewScreen2(0, dri2_dpy->fd,
780b8e80941Smrg                                             dri2_dpy->loader_extensions,
781848b8605Smrg                                             dri2_dpy->driver_extensions,
782848b8605Smrg                                             &dri2_dpy->driver_configs, disp);
783848b8605Smrg      } else {
784848b8605Smrg         dri2_dpy->dri_screen =
785848b8605Smrg            dri2_dpy->dri2->createNewScreen(0, dri2_dpy->fd,
786b8e80941Smrg                                            dri2_dpy->loader_extensions,
787848b8605Smrg                                            &dri2_dpy->driver_configs, disp);
788848b8605Smrg      }
789848b8605Smrg   } else {
790848b8605Smrg      assert(dri2_dpy->swrast);
791848b8605Smrg      if (dri2_dpy->swrast->base.version >= 4) {
792848b8605Smrg         dri2_dpy->dri_screen =
793b8e80941Smrg            dri2_dpy->swrast->createNewScreen2(0, dri2_dpy->loader_extensions,
794848b8605Smrg                                               dri2_dpy->driver_extensions,
795848b8605Smrg                                               &dri2_dpy->driver_configs, disp);
796848b8605Smrg      } else {
797848b8605Smrg         dri2_dpy->dri_screen =
798b8e80941Smrg            dri2_dpy->swrast->createNewScreen(0, dri2_dpy->loader_extensions,
799848b8605Smrg                                              &dri2_dpy->driver_configs, disp);
800848b8605Smrg      }
801848b8605Smrg   }
802848b8605Smrg
803848b8605Smrg   if (dri2_dpy->dri_screen == NULL) {
804848b8605Smrg      _eglLog(_EGL_WARNING, "DRI2: failed to create dri screen");
805848b8605Smrg      return EGL_FALSE;
806848b8605Smrg   }
807848b8605Smrg
808b8e80941Smrg   dri2_dpy->own_dri_screen = true;
809b8e80941Smrg   return EGL_TRUE;
810b8e80941Smrg}
811b8e80941Smrg
812b8e80941SmrgEGLBoolean
813b8e80941Smrgdri2_setup_extensions(_EGLDisplay *disp)
814b8e80941Smrg{
815b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
816b8e80941Smrg   const struct dri2_extension_match *mandatory_core_extensions;
817b8e80941Smrg   const __DRIextension **extensions;
818848b8605Smrg
819848b8605Smrg   extensions = dri2_dpy->core->getExtensions(dri2_dpy->dri_screen);
820848b8605Smrg
821b8e80941Smrg   if (dri2_dpy->image_driver || dri2_dpy->dri2)
822b8e80941Smrg      mandatory_core_extensions = dri2_core_extensions;
823b8e80941Smrg   else
824b8e80941Smrg      mandatory_core_extensions = swrast_core_extensions;
825848b8605Smrg
826b8e80941Smrg   if (!dri2_bind_extensions(dri2_dpy, mandatory_core_extensions, extensions, false))
827b8e80941Smrg      return EGL_FALSE;
828848b8605Smrg
829b8e80941Smrg#ifdef HAVE_DRI3_MODIFIERS
830b8e80941Smrg   dri2_dpy->multibuffers_available =
831b8e80941Smrg      (dri2_dpy->dri3_major_version > 1 || (dri2_dpy->dri3_major_version == 1 &&
832b8e80941Smrg                                            dri2_dpy->dri3_minor_version >= 2)) &&
833b8e80941Smrg      (dri2_dpy->present_major_version > 1 || (dri2_dpy->present_major_version == 1 &&
834b8e80941Smrg                                               dri2_dpy->present_minor_version >= 2)) &&
835b8e80941Smrg      (dri2_dpy->image && dri2_dpy->image->base.version >= 15);
836b8e80941Smrg#endif
837848b8605Smrg
838b8e80941Smrg   dri2_bind_extensions(dri2_dpy, optional_core_extensions, extensions, true);
839b8e80941Smrg   return EGL_TRUE;
840848b8605Smrg}
841848b8605Smrg
842848b8605Smrg/**
843848b8605Smrg * Called via eglInitialize(), GLX_drv->API.Initialize().
844b8e80941Smrg *
845b8e80941Smrg * This must be guaranteed to be called exactly once, even if eglInitialize is
846b8e80941Smrg * called many times (without a eglTerminate in between).
847848b8605Smrg */
848848b8605Smrgstatic EGLBoolean
849848b8605Smrgdri2_initialize(_EGLDriver *drv, _EGLDisplay *disp)
850848b8605Smrg{
851b8e80941Smrg   EGLBoolean ret = EGL_FALSE;
852b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
853b8e80941Smrg
854b8e80941Smrg   /* In the case where the application calls eglMakeCurrent(context1),
855b8e80941Smrg    * eglTerminate, then eglInitialize again (without a call to eglReleaseThread
856b8e80941Smrg    * or eglMakeCurrent(NULL) before that), dri2_dpy structure is still
857b8e80941Smrg    * initialized, as we need it to be able to free context1 correctly.
858b8e80941Smrg    *
859b8e80941Smrg    * It would probably be safest to forcibly release the display with
860b8e80941Smrg    * dri2_display_release, to make sure the display is reinitialized correctly.
861b8e80941Smrg    * However, the EGL spec states that we need to keep a reference to the
862b8e80941Smrg    * current context (so we cannot call dri2_make_current(NULL)), and therefore
863b8e80941Smrg    * we would leak context1 as we would be missing the old display connection
864b8e80941Smrg    * to free it up correctly.
865b8e80941Smrg    */
866b8e80941Smrg   if (dri2_dpy) {
867b8e80941Smrg      dri2_dpy->ref_count++;
868b8e80941Smrg      return EGL_TRUE;
869b8e80941Smrg   }
870b8e80941Smrg
871b8e80941Smrg   loader_set_logger(_eglLog);
872848b8605Smrg
873848b8605Smrg   switch (disp->Platform) {
874b8e80941Smrg   case _EGL_PLATFORM_SURFACELESS:
875b8e80941Smrg      ret = dri2_initialize_surfaceless(drv, disp);
876b8e80941Smrg      break;
877848b8605Smrg   case _EGL_PLATFORM_X11:
878b8e80941Smrg      ret = dri2_initialize_x11(drv, disp);
879b8e80941Smrg      break;
880848b8605Smrg   case _EGL_PLATFORM_DRM:
881b8e80941Smrg      ret = dri2_initialize_drm(drv, disp);
882b8e80941Smrg      break;
883848b8605Smrg   case _EGL_PLATFORM_WAYLAND:
884b8e80941Smrg      ret = dri2_initialize_wayland(drv, disp);
885b8e80941Smrg      break;
886848b8605Smrg   case _EGL_PLATFORM_ANDROID:
887b8e80941Smrg      ret = dri2_initialize_android(drv, disp);
888b8e80941Smrg      break;
889848b8605Smrg   default:
890b8e80941Smrg      unreachable("Callers ensure we cannot get here.");
891848b8605Smrg      return EGL_FALSE;
892848b8605Smrg   }
893b8e80941Smrg
894b8e80941Smrg   if (!ret)
895b8e80941Smrg      return EGL_FALSE;
896b8e80941Smrg
897b8e80941Smrg   dri2_dpy = dri2_egl_display(disp);
898b8e80941Smrg   dri2_dpy->ref_count++;
899b8e80941Smrg
900b8e80941Smrg   return EGL_TRUE;
901848b8605Smrg}
902848b8605Smrg
903848b8605Smrg/**
904b8e80941Smrg * Decrement display reference count, and free up display if necessary.
905848b8605Smrg */
906b8e80941Smrgstatic void
907b8e80941Smrgdri2_display_release(_EGLDisplay *disp)
908848b8605Smrg{
909b8e80941Smrg   struct dri2_egl_display *dri2_dpy;
910b8e80941Smrg
911b8e80941Smrg   if (!disp)
912b8e80941Smrg      return;
913b8e80941Smrg
914b8e80941Smrg   dri2_dpy = dri2_egl_display(disp);
915b8e80941Smrg
916b8e80941Smrg   assert(dri2_dpy->ref_count > 0);
917b8e80941Smrg   dri2_dpy->ref_count--;
918b8e80941Smrg
919b8e80941Smrg   if (dri2_dpy->ref_count > 0)
920b8e80941Smrg      return;
921848b8605Smrg
922848b8605Smrg   _eglCleanupDisplay(disp);
923b8e80941Smrg   dri2_display_destroy(disp);
924b8e80941Smrg}
925b8e80941Smrg
926b8e80941Smrgvoid
927b8e80941Smrgdri2_display_destroy(_EGLDisplay *disp)
928b8e80941Smrg{
929b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
930848b8605Smrg
931b8e80941Smrg   if (dri2_dpy->own_dri_screen) {
932b8e80941Smrg      if (dri2_dpy->vtbl && dri2_dpy->vtbl->close_screen_notify)
933b8e80941Smrg         dri2_dpy->vtbl->close_screen_notify(disp);
934848b8605Smrg      dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
935b8e80941Smrg   }
936b8e80941Smrg   if (dri2_dpy->fd >= 0)
937848b8605Smrg      close(dri2_dpy->fd);
938848b8605Smrg   if (dri2_dpy->driver)
939848b8605Smrg      dlclose(dri2_dpy->driver);
940848b8605Smrg   free(dri2_dpy->driver_name);
941848b8605Smrg
942b8e80941Smrg#ifdef HAVE_WAYLAND_PLATFORM
943b8e80941Smrg   free(dri2_dpy->device_name);
944b8e80941Smrg#endif
945b8e80941Smrg
946848b8605Smrg   switch (disp->Platform) {
947848b8605Smrg   case _EGL_PLATFORM_X11:
948b8e80941Smrg      dri2_teardown_x11(dri2_dpy);
949848b8605Smrg      break;
950848b8605Smrg   case _EGL_PLATFORM_DRM:
951b8e80941Smrg      dri2_teardown_drm(dri2_dpy);
952848b8605Smrg      break;
953848b8605Smrg   case _EGL_PLATFORM_WAYLAND:
954b8e80941Smrg      dri2_teardown_wayland(dri2_dpy);
955848b8605Smrg      break;
956848b8605Smrg   default:
957b8e80941Smrg      /* TODO: add teardown for other platforms */
958848b8605Smrg      break;
959848b8605Smrg   }
960848b8605Smrg
961b8e80941Smrg   /* The drm platform does not create the screen/driver_configs but reuses
962b8e80941Smrg    * the ones from the gbm device. As such the gbm itself is responsible
963b8e80941Smrg    * for the cleanup.
964b8e80941Smrg    */
965b8e80941Smrg   if (disp->Platform != _EGL_PLATFORM_DRM && dri2_dpy->driver_configs) {
966b8e80941Smrg      for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++)
967b8e80941Smrg         free((__DRIconfig *) dri2_dpy->driver_configs[i]);
968b8e80941Smrg      free(dri2_dpy->driver_configs);
969b8e80941Smrg   }
970848b8605Smrg   free(dri2_dpy);
971848b8605Smrg   disp->DriverData = NULL;
972b8e80941Smrg}
973b8e80941Smrg
974b8e80941Smrg__DRIbuffer *
975b8e80941Smrgdri2_egl_surface_alloc_local_buffer(struct dri2_egl_surface *dri2_surf,
976b8e80941Smrg                                    unsigned int att, unsigned int format)
977b8e80941Smrg{
978b8e80941Smrg   struct dri2_egl_display *dri2_dpy =
979b8e80941Smrg      dri2_egl_display(dri2_surf->base.Resource.Display);
980b8e80941Smrg
981b8e80941Smrg   if (att >= ARRAY_SIZE(dri2_surf->local_buffers))
982b8e80941Smrg      return NULL;
983b8e80941Smrg
984b8e80941Smrg   if (!dri2_surf->local_buffers[att]) {
985b8e80941Smrg      dri2_surf->local_buffers[att] =
986b8e80941Smrg         dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format,
987b8e80941Smrg                                        dri2_surf->base.Width, dri2_surf->base.Height);
988b8e80941Smrg   }
989b8e80941Smrg
990b8e80941Smrg   return dri2_surf->local_buffers[att];
991b8e80941Smrg}
992b8e80941Smrg
993b8e80941Smrgvoid
994b8e80941Smrgdri2_egl_surface_free_local_buffers(struct dri2_egl_surface *dri2_surf)
995b8e80941Smrg{
996b8e80941Smrg   struct dri2_egl_display *dri2_dpy =
997b8e80941Smrg      dri2_egl_display(dri2_surf->base.Resource.Display);
998b8e80941Smrg
999b8e80941Smrg   for (int i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) {
1000b8e80941Smrg      if (dri2_surf->local_buffers[i]) {
1001b8e80941Smrg         dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
1002b8e80941Smrg                                       dri2_surf->local_buffers[i]);
1003b8e80941Smrg         dri2_surf->local_buffers[i] = NULL;
1004b8e80941Smrg      }
1005b8e80941Smrg   }
1006b8e80941Smrg}
1007b8e80941Smrg
1008b8e80941Smrg/**
1009b8e80941Smrg * Called via eglTerminate(), drv->API.Terminate().
1010b8e80941Smrg *
1011b8e80941Smrg * This must be guaranteed to be called exactly once, even if eglTerminate is
1012b8e80941Smrg * called many times (without a eglInitialize in between).
1013b8e80941Smrg */
1014b8e80941Smrgstatic EGLBoolean
1015b8e80941Smrgdri2_terminate(_EGLDriver *drv, _EGLDisplay *disp)
1016b8e80941Smrg{
1017b8e80941Smrg   /* Release all non-current Context/Surfaces. */
1018b8e80941Smrg   _eglReleaseDisplayResources(drv, disp);
1019b8e80941Smrg
1020b8e80941Smrg   dri2_display_release(disp);
1021848b8605Smrg
1022848b8605Smrg   return EGL_TRUE;
1023848b8605Smrg}
1024848b8605Smrg
1025848b8605Smrg/**
1026848b8605Smrg * Set the error code after a call to
1027848b8605Smrg * dri2_egl_display::dri2::createContextAttribs.
1028848b8605Smrg */
1029848b8605Smrgstatic void
1030848b8605Smrgdri2_create_context_attribs_error(int dri_error)
1031848b8605Smrg{
1032848b8605Smrg   EGLint egl_error;
1033848b8605Smrg
1034848b8605Smrg   switch (dri_error) {
1035848b8605Smrg   case __DRI_CTX_ERROR_SUCCESS:
1036848b8605Smrg      return;
1037848b8605Smrg
1038848b8605Smrg   case __DRI_CTX_ERROR_NO_MEMORY:
1039848b8605Smrg      egl_error = EGL_BAD_ALLOC;
1040848b8605Smrg      break;
1041848b8605Smrg
1042848b8605Smrg  /* From the EGL_KHR_create_context spec, section "Errors":
1043848b8605Smrg   *
1044848b8605Smrg   *   * If <config> does not support a client API context compatible
1045848b8605Smrg   *     with the requested API major and minor version, [...] context flags,
1046848b8605Smrg   *     and context reset notification behavior (for client API types where
1047848b8605Smrg   *     these attributes are supported), then an EGL_BAD_MATCH error is
1048848b8605Smrg   *     generated.
1049848b8605Smrg   *
1050848b8605Smrg   *   * If an OpenGL ES context is requested and the values for
1051848b8605Smrg   *     attributes EGL_CONTEXT_MAJOR_VERSION_KHR and
1052848b8605Smrg   *     EGL_CONTEXT_MINOR_VERSION_KHR specify an OpenGL ES version that
1053848b8605Smrg   *     is not defined, than an EGL_BAD_MATCH error is generated.
1054848b8605Smrg   *
1055848b8605Smrg   *   * If an OpenGL context is requested, the requested version is
1056848b8605Smrg   *     greater than 3.2, and the value for attribute
1057848b8605Smrg   *     EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR has no bits set; has any
1058848b8605Smrg   *     bits set other than EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR and
1059848b8605Smrg   *     EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR; has more than
1060848b8605Smrg   *     one of these bits set; or if the implementation does not support
1061848b8605Smrg   *     the requested profile, then an EGL_BAD_MATCH error is generated.
1062848b8605Smrg   */
1063848b8605Smrg   case __DRI_CTX_ERROR_BAD_API:
1064848b8605Smrg   case __DRI_CTX_ERROR_BAD_VERSION:
1065848b8605Smrg   case __DRI_CTX_ERROR_BAD_FLAG:
1066848b8605Smrg      egl_error = EGL_BAD_MATCH;
1067848b8605Smrg      break;
1068848b8605Smrg
1069848b8605Smrg  /* From the EGL_KHR_create_context spec, section "Errors":
1070848b8605Smrg   *
1071848b8605Smrg   *   * If an attribute name or attribute value in <attrib_list> is not
1072848b8605Smrg   *     recognized (including unrecognized bits in bitmask attributes),
1073848b8605Smrg   *     then an EGL_BAD_ATTRIBUTE error is generated."
1074848b8605Smrg   */
1075848b8605Smrg   case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE:
1076848b8605Smrg   case __DRI_CTX_ERROR_UNKNOWN_FLAG:
1077848b8605Smrg      egl_error = EGL_BAD_ATTRIBUTE;
1078848b8605Smrg      break;
1079848b8605Smrg
1080848b8605Smrg   default:
1081b8e80941Smrg      assert(!"unknown dri_error code");
1082848b8605Smrg      egl_error = EGL_BAD_MATCH;
1083848b8605Smrg      break;
1084848b8605Smrg   }
1085848b8605Smrg
1086848b8605Smrg   _eglError(egl_error, "dri2_create_context");
1087848b8605Smrg}
1088848b8605Smrg
1089b8e80941Smrgstatic bool
1090b8e80941Smrgdri2_fill_context_attribs(struct dri2_egl_context *dri2_ctx,
1091b8e80941Smrg                          struct dri2_egl_display *dri2_dpy,
1092b8e80941Smrg                          uint32_t *ctx_attribs,
1093b8e80941Smrg                          unsigned *num_attribs)
1094b8e80941Smrg{
1095b8e80941Smrg   int pos = 0;
1096b8e80941Smrg
1097b8e80941Smrg   assert(*num_attribs >= NUM_ATTRIBS);
1098b8e80941Smrg
1099b8e80941Smrg   ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
1100b8e80941Smrg   ctx_attribs[pos++] = dri2_ctx->base.ClientMajorVersion;
1101b8e80941Smrg   ctx_attribs[pos++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
1102b8e80941Smrg   ctx_attribs[pos++] = dri2_ctx->base.ClientMinorVersion;
1103b8e80941Smrg
1104b8e80941Smrg   if (dri2_ctx->base.Flags != 0 || dri2_ctx->base.NoError) {
1105b8e80941Smrg      /* If the implementation doesn't support the __DRI2_ROBUSTNESS
1106b8e80941Smrg       * extension, don't even try to send it the robust-access flag.
1107b8e80941Smrg       * It may explode.  Instead, generate the required EGL error here.
1108b8e80941Smrg       */
1109b8e80941Smrg      if ((dri2_ctx->base.Flags & EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR) != 0
1110b8e80941Smrg            && !dri2_dpy->robustness) {
1111b8e80941Smrg         _eglError(EGL_BAD_MATCH, "eglCreateContext");
1112b8e80941Smrg         return false;
1113b8e80941Smrg      }
1114b8e80941Smrg
1115b8e80941Smrg      ctx_attribs[pos++] = __DRI_CTX_ATTRIB_FLAGS;
1116b8e80941Smrg      ctx_attribs[pos++] = dri2_ctx->base.Flags |
1117b8e80941Smrg         (dri2_ctx->base.NoError ? __DRI_CTX_FLAG_NO_ERROR : 0);
1118b8e80941Smrg   }
1119b8e80941Smrg
1120b8e80941Smrg   if (dri2_ctx->base.ResetNotificationStrategy != EGL_NO_RESET_NOTIFICATION_KHR) {
1121b8e80941Smrg      /* If the implementation doesn't support the __DRI2_ROBUSTNESS
1122b8e80941Smrg       * extension, don't even try to send it a reset strategy.  It may
1123b8e80941Smrg       * explode.  Instead, generate the required EGL error here.
1124b8e80941Smrg       */
1125b8e80941Smrg      if (!dri2_dpy->robustness) {
1126b8e80941Smrg         _eglError(EGL_BAD_CONFIG, "eglCreateContext");
1127b8e80941Smrg         return false;
1128b8e80941Smrg      }
1129b8e80941Smrg
1130b8e80941Smrg      ctx_attribs[pos++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
1131b8e80941Smrg      ctx_attribs[pos++] = __DRI_CTX_RESET_LOSE_CONTEXT;
1132b8e80941Smrg   }
1133b8e80941Smrg
1134b8e80941Smrg   if (dri2_ctx->base.ContextPriority != EGL_CONTEXT_PRIORITY_MEDIUM_IMG) {
1135b8e80941Smrg      unsigned val;
1136b8e80941Smrg
1137b8e80941Smrg      switch (dri2_ctx->base.ContextPriority) {
1138b8e80941Smrg      case EGL_CONTEXT_PRIORITY_HIGH_IMG:
1139b8e80941Smrg         val = __DRI_CTX_PRIORITY_HIGH;
1140b8e80941Smrg         break;
1141b8e80941Smrg      case EGL_CONTEXT_PRIORITY_MEDIUM_IMG:
1142b8e80941Smrg         val = __DRI_CTX_PRIORITY_MEDIUM;
1143b8e80941Smrg         break;
1144b8e80941Smrg      case EGL_CONTEXT_PRIORITY_LOW_IMG:
1145b8e80941Smrg         val = __DRI_CTX_PRIORITY_LOW;
1146b8e80941Smrg         break;
1147b8e80941Smrg      default:
1148b8e80941Smrg         _eglError(EGL_BAD_CONFIG, "eglCreateContext");
1149b8e80941Smrg         return false;
1150b8e80941Smrg      }
1151b8e80941Smrg
1152b8e80941Smrg      ctx_attribs[pos++] = __DRI_CTX_ATTRIB_PRIORITY;
1153b8e80941Smrg      ctx_attribs[pos++] = val;
1154b8e80941Smrg   }
1155b8e80941Smrg
1156b8e80941Smrg   if (dri2_ctx->base.ReleaseBehavior == EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR) {
1157b8e80941Smrg      ctx_attribs[pos++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
1158b8e80941Smrg      ctx_attribs[pos++] = __DRI_CTX_RELEASE_BEHAVIOR_NONE;
1159b8e80941Smrg   }
1160b8e80941Smrg
1161b8e80941Smrg   *num_attribs = pos;
1162b8e80941Smrg
1163b8e80941Smrg   return true;
1164b8e80941Smrg}
1165b8e80941Smrg
1166848b8605Smrg/**
1167848b8605Smrg * Called via eglCreateContext(), drv->API.CreateContext().
1168848b8605Smrg */
1169848b8605Smrgstatic _EGLContext *
1170848b8605Smrgdri2_create_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLConfig *conf,
1171b8e80941Smrg                    _EGLContext *share_list, const EGLint *attrib_list)
1172848b8605Smrg{
1173848b8605Smrg   struct dri2_egl_context *dri2_ctx;
1174848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1175848b8605Smrg   struct dri2_egl_context *dri2_ctx_shared = dri2_egl_context(share_list);
1176848b8605Smrg   __DRIcontext *shared =
1177848b8605Smrg      dri2_ctx_shared ? dri2_ctx_shared->dri_context : NULL;
1178848b8605Smrg   struct dri2_egl_config *dri2_config = dri2_egl_config(conf);
1179848b8605Smrg   const __DRIconfig *dri_config;
1180848b8605Smrg   int api;
1181b8e80941Smrg   unsigned error;
1182b8e80941Smrg   unsigned num_attribs = NUM_ATTRIBS;
1183b8e80941Smrg   uint32_t ctx_attribs[NUM_ATTRIBS];
1184848b8605Smrg
1185848b8605Smrg   (void) drv;
1186848b8605Smrg
1187848b8605Smrg   dri2_ctx = malloc(sizeof *dri2_ctx);
1188848b8605Smrg   if (!dri2_ctx) {
1189848b8605Smrg      _eglError(EGL_BAD_ALLOC, "eglCreateContext");
1190848b8605Smrg      return NULL;
1191848b8605Smrg   }
1192848b8605Smrg
1193848b8605Smrg   if (!_eglInitContext(&dri2_ctx->base, disp, conf, attrib_list))
1194848b8605Smrg      goto cleanup;
1195848b8605Smrg
1196b8e80941Smrg   /* The EGL_EXT_create_context_robustness spec says:
1197b8e80941Smrg    *
1198b8e80941Smrg    *    "Add to the eglCreateContext context creation errors: [...]
1199b8e80941Smrg    *
1200b8e80941Smrg    *     * If the reset notification behavior of <share_context> and the
1201b8e80941Smrg    *       newly created context are different then an EGL_BAD_MATCH error is
1202b8e80941Smrg    *       generated."
1203b8e80941Smrg    */
1204b8e80941Smrg   if (share_list && share_list->ResetNotificationStrategy !=
1205b8e80941Smrg                     dri2_ctx->base.ResetNotificationStrategy) {
1206b8e80941Smrg      _eglError(EGL_BAD_MATCH, "eglCreateContext");
1207b8e80941Smrg      goto cleanup;
1208b8e80941Smrg   }
1209b8e80941Smrg
1210b8e80941Smrg   /* The EGL_KHR_create_context_no_error spec says:
1211b8e80941Smrg    *
1212b8e80941Smrg    *    "BAD_MATCH is generated if the value of EGL_CONTEXT_OPENGL_NO_ERROR_KHR
1213b8e80941Smrg    *    used to create <share_context> does not match the value of
1214b8e80941Smrg    *    EGL_CONTEXT_OPENGL_NO_ERROR_KHR for the context being created."
1215b8e80941Smrg    */
1216b8e80941Smrg   if (share_list && share_list->NoError != dri2_ctx->base.NoError) {
1217b8e80941Smrg      _eglError(EGL_BAD_MATCH, "eglCreateContext");
1218b8e80941Smrg      goto cleanup;
1219b8e80941Smrg   }
1220b8e80941Smrg
1221848b8605Smrg   switch (dri2_ctx->base.ClientAPI) {
1222848b8605Smrg   case EGL_OPENGL_ES_API:
1223848b8605Smrg      switch (dri2_ctx->base.ClientMajorVersion) {
1224848b8605Smrg      case 1:
1225848b8605Smrg         api = __DRI_API_GLES;
1226848b8605Smrg         break;
1227848b8605Smrg      case 2:
1228848b8605Smrg         api = __DRI_API_GLES2;
1229848b8605Smrg         break;
1230848b8605Smrg      case 3:
1231848b8605Smrg         api = __DRI_API_GLES3;
1232848b8605Smrg         break;
1233848b8605Smrg      default:
1234848b8605Smrg         _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
1235848b8605Smrg         free(dri2_ctx);
1236848b8605Smrg         return NULL;
1237848b8605Smrg      }
1238848b8605Smrg      break;
1239848b8605Smrg   case EGL_OPENGL_API:
1240848b8605Smrg      if ((dri2_ctx->base.ClientMajorVersion >= 4
1241848b8605Smrg           || (dri2_ctx->base.ClientMajorVersion == 3
1242848b8605Smrg               && dri2_ctx->base.ClientMinorVersion >= 2))
1243848b8605Smrg          && dri2_ctx->base.Profile == EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR)
1244848b8605Smrg         api = __DRI_API_OPENGL_CORE;
1245848b8605Smrg      else
1246848b8605Smrg         api = __DRI_API_OPENGL;
1247848b8605Smrg      break;
1248848b8605Smrg   default:
1249848b8605Smrg      _eglError(EGL_BAD_PARAMETER, "eglCreateContext");
1250848b8605Smrg      free(dri2_ctx);
1251848b8605Smrg      return NULL;
1252848b8605Smrg   }
1253848b8605Smrg
1254848b8605Smrg   if (conf != NULL) {
1255848b8605Smrg      /* The config chosen here isn't necessarily
1256848b8605Smrg       * used for surfaces later.
1257848b8605Smrg       * A pixmap surface will use the single config.
1258848b8605Smrg       * This opportunity depends on disabling the
1259848b8605Smrg       * doubleBufferMode check in
1260848b8605Smrg       * src/mesa/main/context.c:check_compatible()
1261848b8605Smrg       */
1262b8e80941Smrg      if (dri2_config->dri_config[1][0])
1263b8e80941Smrg         dri_config = dri2_config->dri_config[1][0];
1264848b8605Smrg      else
1265b8e80941Smrg         dri_config = dri2_config->dri_config[0][0];
1266848b8605Smrg   }
1267848b8605Smrg   else
1268848b8605Smrg      dri_config = NULL;
1269848b8605Smrg
1270b8e80941Smrg   if (!dri2_fill_context_attribs(dri2_ctx, dri2_dpy, ctx_attribs,
1271b8e80941Smrg                                  &num_attribs))
1272b8e80941Smrg      goto cleanup;
1273848b8605Smrg
1274b8e80941Smrg   if (dri2_dpy->image_driver) {
1275b8e80941Smrg      dri2_ctx->dri_context =
1276b8e80941Smrg         dri2_dpy->image_driver->createContextAttribs(dri2_dpy->dri_screen,
1277b8e80941Smrg                                                      api,
1278b8e80941Smrg                                                      dri_config,
1279b8e80941Smrg                                                      shared,
1280b8e80941Smrg                                                      num_attribs / 2,
1281b8e80941Smrg                                                      ctx_attribs,
1282b8e80941Smrg                                                      & error,
1283b8e80941Smrg                                                      dri2_ctx);
1284b8e80941Smrg      dri2_create_context_attribs_error(error);
1285b8e80941Smrg   } else if (dri2_dpy->dri2) {
1286b8e80941Smrg      if (dri2_dpy->dri2->base.version >= 3) {
1287b8e80941Smrg         dri2_ctx->dri_context =
1288b8e80941Smrg            dri2_dpy->dri2->createContextAttribs(dri2_dpy->dri_screen,
1289848b8605Smrg                                                 api,
1290848b8605Smrg                                                 dri_config,
1291848b8605Smrg                                                 shared,
1292848b8605Smrg                                                 num_attribs / 2,
1293848b8605Smrg                                                 ctx_attribs,
1294848b8605Smrg                                                 & error,
1295848b8605Smrg                                                 dri2_ctx);
1296b8e80941Smrg         dri2_create_context_attribs_error(error);
1297848b8605Smrg      } else {
1298b8e80941Smrg         dri2_ctx->dri_context =
1299b8e80941Smrg            dri2_dpy->dri2->createNewContextForAPI(dri2_dpy->dri_screen,
1300b8e80941Smrg                                                   api,
1301b8e80941Smrg                                                   dri_config,
1302848b8605Smrg                                                   shared,
1303b8e80941Smrg                                                   dri2_ctx);
1304848b8605Smrg      }
1305848b8605Smrg   } else {
1306848b8605Smrg      assert(dri2_dpy->swrast);
1307b8e80941Smrg      if (dri2_dpy->swrast->base.version >= 3) {
1308b8e80941Smrg         dri2_ctx->dri_context =
1309b8e80941Smrg            dri2_dpy->swrast->createContextAttribs(dri2_dpy->dri_screen,
1310b8e80941Smrg                                                   api,
1311b8e80941Smrg                                                   dri_config,
1312b8e80941Smrg                                                   shared,
1313b8e80941Smrg                                                   num_attribs / 2,
1314b8e80941Smrg                                                   ctx_attribs,
1315b8e80941Smrg                                                   & error,
1316b8e80941Smrg                                                   dri2_ctx);
1317b8e80941Smrg         dri2_create_context_attribs_error(error);
1318b8e80941Smrg      } else {
1319b8e80941Smrg         dri2_ctx->dri_context =
1320b8e80941Smrg            dri2_dpy->swrast->createNewContextForAPI(dri2_dpy->dri_screen,
1321b8e80941Smrg                                                     api,
1322b8e80941Smrg                                                     dri_config,
1323b8e80941Smrg                                                     shared,
1324b8e80941Smrg                                                     dri2_ctx);
1325b8e80941Smrg      }
1326848b8605Smrg   }
1327848b8605Smrg
1328848b8605Smrg   if (!dri2_ctx->dri_context)
1329848b8605Smrg      goto cleanup;
1330848b8605Smrg
1331848b8605Smrg   return &dri2_ctx->base;
1332848b8605Smrg
1333848b8605Smrg cleanup:
1334848b8605Smrg   free(dri2_ctx);
1335848b8605Smrg   return NULL;
1336848b8605Smrg}
1337848b8605Smrg
1338848b8605Smrg/**
1339848b8605Smrg * Called via eglDestroyContext(), drv->API.DestroyContext().
1340848b8605Smrg */
1341848b8605Smrgstatic EGLBoolean
1342848b8605Smrgdri2_destroy_context(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
1343848b8605Smrg{
1344848b8605Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1345848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1346848b8605Smrg
1347848b8605Smrg   if (_eglPutContext(ctx)) {
1348848b8605Smrg      dri2_dpy->core->destroyContext(dri2_ctx->dri_context);
1349848b8605Smrg      free(dri2_ctx);
1350848b8605Smrg   }
1351848b8605Smrg
1352848b8605Smrg   return EGL_TRUE;
1353848b8605Smrg}
1354848b8605Smrg
1355b8e80941SmrgEGLBoolean
1356b8e80941Smrgdri2_init_surface(_EGLSurface *surf, _EGLDisplay *disp, EGLint type,
1357b8e80941Smrg        _EGLConfig *conf, const EGLint *attrib_list, EGLBoolean enable_out_fence)
1358b8e80941Smrg{
1359b8e80941Smrg   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1360b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1361b8e80941Smrg
1362b8e80941Smrg   dri2_surf->out_fence_fd = -1;
1363b8e80941Smrg   dri2_surf->enable_out_fence = false;
1364b8e80941Smrg   if (dri2_dpy->fence && dri2_dpy->fence->base.version >= 2 &&
1365b8e80941Smrg       dri2_dpy->fence->get_capabilities &&
1366b8e80941Smrg       (dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen) &
1367b8e80941Smrg        __DRI_FENCE_CAP_NATIVE_FD)) {
1368b8e80941Smrg      dri2_surf->enable_out_fence = enable_out_fence;
1369b8e80941Smrg   }
1370b8e80941Smrg
1371b8e80941Smrg   return _eglInitSurface(surf, disp, type, conf, attrib_list);
1372b8e80941Smrg}
1373b8e80941Smrg
1374b8e80941Smrgstatic void
1375b8e80941Smrgdri2_surface_set_out_fence_fd( _EGLSurface *surf, int fence_fd)
1376b8e80941Smrg{
1377b8e80941Smrg   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1378b8e80941Smrg
1379b8e80941Smrg   if (dri2_surf->out_fence_fd >= 0)
1380b8e80941Smrg      close(dri2_surf->out_fence_fd);
1381b8e80941Smrg
1382b8e80941Smrg   dri2_surf->out_fence_fd = fence_fd;
1383b8e80941Smrg}
1384b8e80941Smrg
1385b8e80941Smrgvoid
1386b8e80941Smrgdri2_fini_surface(_EGLSurface *surf)
1387b8e80941Smrg{
1388b8e80941Smrg   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1389b8e80941Smrg
1390b8e80941Smrg   dri2_surface_set_out_fence_fd(surf, -1);
1391b8e80941Smrg   dri2_surf->enable_out_fence = false;
1392b8e80941Smrg}
1393b8e80941Smrg
1394b8e80941Smrgstatic EGLBoolean
1395b8e80941Smrgdri2_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
1396b8e80941Smrg{
1397b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1398b8e80941Smrg
1399b8e80941Smrg   if (!_eglPutSurface(surf))
1400b8e80941Smrg      return EGL_TRUE;
1401b8e80941Smrg
1402b8e80941Smrg   return dri2_dpy->vtbl->destroy_surface(drv, disp, surf);
1403b8e80941Smrg}
1404b8e80941Smrg
1405b8e80941Smrgstatic void
1406b8e80941Smrgdri2_surf_update_fence_fd(_EGLContext *ctx,
1407b8e80941Smrg                          _EGLDisplay *disp, _EGLSurface *surf)
1408b8e80941Smrg{
1409b8e80941Smrg   __DRIcontext *dri_ctx = dri2_egl_context(ctx)->dri_context;
1410b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1411b8e80941Smrg   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1412b8e80941Smrg   int fence_fd = -1;
1413b8e80941Smrg   void *fence;
1414b8e80941Smrg
1415b8e80941Smrg   if (!dri2_surf->enable_out_fence)
1416b8e80941Smrg      return;
1417b8e80941Smrg
1418b8e80941Smrg   fence = dri2_dpy->fence->create_fence_fd(dri_ctx, -1);
1419b8e80941Smrg   if (fence) {
1420b8e80941Smrg      fence_fd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen,
1421b8e80941Smrg                                               fence);
1422b8e80941Smrg      dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, fence);
1423b8e80941Smrg   }
1424b8e80941Smrg   dri2_surface_set_out_fence_fd(surf, fence_fd);
1425b8e80941Smrg}
1426b8e80941Smrg
1427b8e80941SmrgEGLBoolean
1428b8e80941Smrgdri2_create_drawable(struct dri2_egl_display *dri2_dpy,
1429b8e80941Smrg                     const __DRIconfig *config,
1430b8e80941Smrg                     struct dri2_egl_surface *dri2_surf)
1431b8e80941Smrg{
1432b8e80941Smrg   __DRIcreateNewDrawableFunc createNewDrawable;
1433b8e80941Smrg   void *loaderPrivate = dri2_surf;
1434b8e80941Smrg
1435b8e80941Smrg   if (dri2_dpy->image_driver)
1436b8e80941Smrg      createNewDrawable = dri2_dpy->image_driver->createNewDrawable;
1437b8e80941Smrg   else if (dri2_dpy->dri2)
1438b8e80941Smrg      createNewDrawable = dri2_dpy->dri2->createNewDrawable;
1439b8e80941Smrg   else if (dri2_dpy->swrast)
1440b8e80941Smrg      createNewDrawable = dri2_dpy->swrast->createNewDrawable;
1441b8e80941Smrg   else
1442b8e80941Smrg      return _eglError(EGL_BAD_ALLOC, "no createNewDrawable");
1443b8e80941Smrg
1444b8e80941Smrg   /* As always gbm is a bit special.. */
1445b8e80941Smrg#ifdef HAVE_DRM_PLATFORM
1446b8e80941Smrg   if (dri2_surf->gbm_surf)
1447b8e80941Smrg      loaderPrivate = dri2_surf->gbm_surf;
1448b8e80941Smrg#endif
1449b8e80941Smrg
1450b8e80941Smrg   dri2_surf->dri_drawable = (*createNewDrawable)(dri2_dpy->dri_screen,
1451b8e80941Smrg                                                  config, loaderPrivate);
1452b8e80941Smrg   if (dri2_surf->dri_drawable == NULL)
1453b8e80941Smrg      return _eglError(EGL_BAD_ALLOC, "createNewDrawable");
1454b8e80941Smrg
1455b8e80941Smrg   return EGL_TRUE;
1456b8e80941Smrg}
1457b8e80941Smrg
1458848b8605Smrg/**
1459848b8605Smrg * Called via eglMakeCurrent(), drv->API.MakeCurrent().
1460848b8605Smrg */
1461848b8605Smrgstatic EGLBoolean
1462848b8605Smrgdri2_make_current(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *dsurf,
1463b8e80941Smrg                  _EGLSurface *rsurf, _EGLContext *ctx)
1464848b8605Smrg{
1465848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1466848b8605Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1467b8e80941Smrg   _EGLDisplay *old_disp = NULL;
1468b8e80941Smrg   struct dri2_egl_display *old_dri2_dpy = NULL;
1469848b8605Smrg   _EGLContext *old_ctx;
1470848b8605Smrg   _EGLSurface *old_dsurf, *old_rsurf;
1471b8e80941Smrg   _EGLSurface *tmp_dsurf, *tmp_rsurf;
1472848b8605Smrg   __DRIdrawable *ddraw, *rdraw;
1473848b8605Smrg   __DRIcontext *cctx;
1474b8e80941Smrg   EGLBoolean unbind;
1475b8e80941Smrg
1476b8e80941Smrg   if (!dri2_dpy)
1477b8e80941Smrg      return _eglError(EGL_NOT_INITIALIZED, "eglMakeCurrent");
1478848b8605Smrg
1479848b8605Smrg   /* make new bindings */
1480b8e80941Smrg   if (!_eglBindContext(ctx, dsurf, rsurf, &old_ctx, &old_dsurf, &old_rsurf)) {
1481b8e80941Smrg      /* _eglBindContext already sets the EGL error (in _eglCheckMakeCurrent) */
1482848b8605Smrg      return EGL_FALSE;
1483b8e80941Smrg   }
1484b8e80941Smrg
1485b8e80941Smrg   if (old_ctx) {
1486b8e80941Smrg      old_disp = old_ctx->Resource.Display;
1487b8e80941Smrg      old_dri2_dpy = dri2_egl_display(old_disp);
1488b8e80941Smrg   }
1489848b8605Smrg
1490848b8605Smrg   /* flush before context switch */
1491b8e80941Smrg   if (old_ctx)
1492b8e80941Smrg      dri2_gl_flush();
1493848b8605Smrg
1494b8e80941Smrg   ddraw = (dsurf) ? dri2_dpy->vtbl->get_dri_drawable(dsurf) : NULL;
1495b8e80941Smrg   rdraw = (rsurf) ? dri2_dpy->vtbl->get_dri_drawable(rsurf) : NULL;
1496848b8605Smrg   cctx = (dri2_ctx) ? dri2_ctx->dri_context : NULL;
1497848b8605Smrg
1498848b8605Smrg   if (old_ctx) {
1499848b8605Smrg      __DRIcontext *old_cctx = dri2_egl_context(old_ctx)->dri_context;
1500b8e80941Smrg
1501b8e80941Smrg      if (old_dsurf)
1502b8e80941Smrg         dri2_surf_update_fence_fd(old_ctx, disp, old_dsurf);
1503b8e80941Smrg
1504b8e80941Smrg      /* Disable shared buffer mode */
1505b8e80941Smrg      if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
1506b8e80941Smrg          old_dri2_dpy->vtbl->set_shared_buffer_mode) {
1507b8e80941Smrg         old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, false);
1508b8e80941Smrg      }
1509b8e80941Smrg
1510848b8605Smrg      dri2_dpy->core->unbindContext(old_cctx);
1511848b8605Smrg   }
1512848b8605Smrg
1513b8e80941Smrg   unbind = (cctx == NULL && ddraw == NULL && rdraw == NULL);
1514848b8605Smrg
1515b8e80941Smrg   if (!unbind && !dri2_dpy->core->bindContext(cctx, ddraw, rdraw)) {
1516848b8605Smrg      /* undo the previous _eglBindContext */
1517b8e80941Smrg      _eglBindContext(old_ctx, old_dsurf, old_rsurf, &ctx, &tmp_dsurf, &tmp_rsurf);
1518848b8605Smrg      assert(&dri2_ctx->base == ctx &&
1519b8e80941Smrg             tmp_dsurf == dsurf &&
1520b8e80941Smrg             tmp_rsurf == rsurf);
1521b8e80941Smrg
1522b8e80941Smrg      if (old_dsurf && _eglSurfaceInSharedBufferMode(old_dsurf) &&
1523b8e80941Smrg          old_dri2_dpy->vtbl->set_shared_buffer_mode) {
1524b8e80941Smrg         old_dri2_dpy->vtbl->set_shared_buffer_mode(old_disp, old_dsurf, true);
1525b8e80941Smrg      }
1526848b8605Smrg
1527848b8605Smrg      _eglPutSurface(dsurf);
1528848b8605Smrg      _eglPutSurface(rsurf);
1529848b8605Smrg      _eglPutContext(ctx);
1530848b8605Smrg
1531848b8605Smrg      _eglPutSurface(old_dsurf);
1532848b8605Smrg      _eglPutSurface(old_rsurf);
1533848b8605Smrg      _eglPutContext(old_ctx);
1534848b8605Smrg
1535b8e80941Smrg      /* dri2_dpy->core->bindContext failed. We cannot tell for sure why, but
1536b8e80941Smrg       * setting the error to EGL_BAD_MATCH is surely better than leaving it
1537b8e80941Smrg       * as EGL_SUCCESS.
1538b8e80941Smrg       */
1539b8e80941Smrg      return _eglError(EGL_BAD_MATCH, "eglMakeCurrent");
1540b8e80941Smrg   }
1541b8e80941Smrg
1542b8e80941Smrg   dri2_destroy_surface(drv, disp, old_dsurf);
1543b8e80941Smrg   dri2_destroy_surface(drv, disp, old_rsurf);
1544b8e80941Smrg
1545b8e80941Smrg   if (!unbind)
1546b8e80941Smrg      dri2_dpy->ref_count++;
1547b8e80941Smrg
1548b8e80941Smrg   if (old_ctx) {
1549b8e80941Smrg      dri2_destroy_context(drv, disp, old_ctx);
1550b8e80941Smrg      dri2_display_release(old_disp);
1551b8e80941Smrg   }
1552b8e80941Smrg
1553b8e80941Smrg   if (dsurf && _eglSurfaceHasMutableRenderBuffer(dsurf) &&
1554b8e80941Smrg       dri2_dpy->vtbl->set_shared_buffer_mode) {
1555b8e80941Smrg      /* Always update the shared buffer mode. This is obviously needed when
1556b8e80941Smrg       * the active EGL_RENDER_BUFFER is EGL_SINGLE_BUFFER. When
1557b8e80941Smrg       * EGL_RENDER_BUFFER is EGL_BACK_BUFFER, the update protects us in the
1558b8e80941Smrg       * case where external non-EGL API may have changed window's shared
1559b8e80941Smrg       * buffer mode since we last saw it.
1560b8e80941Smrg       */
1561b8e80941Smrg      bool mode = (dsurf->ActiveRenderBuffer == EGL_SINGLE_BUFFER);
1562b8e80941Smrg      dri2_dpy->vtbl->set_shared_buffer_mode(disp, dsurf, mode);
1563848b8605Smrg   }
1564b8e80941Smrg
1565b8e80941Smrg   return EGL_TRUE;
1566b8e80941Smrg}
1567b8e80941Smrg
1568b8e80941Smrg__DRIdrawable *
1569b8e80941Smrgdri2_surface_get_dri_drawable(_EGLSurface *surf)
1570b8e80941Smrg{
1571b8e80941Smrg   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1572b8e80941Smrg
1573b8e80941Smrg   return dri2_surf->dri_drawable;
1574848b8605Smrg}
1575848b8605Smrg
1576848b8605Smrg/*
1577848b8605Smrg * Called from eglGetProcAddress() via drv->API.GetProcAddress().
1578848b8605Smrg */
1579848b8605Smrgstatic _EGLProc
1580848b8605Smrgdri2_get_proc_address(_EGLDriver *drv, const char *procname)
1581848b8605Smrg{
1582b8e80941Smrg   return _glapi_get_proc_address(procname);
1583848b8605Smrg}
1584848b8605Smrg
1585848b8605Smrgstatic _EGLSurface*
1586b8e80941Smrgdri2_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
1587848b8605Smrg                           _EGLConfig *conf, void *native_window,
1588848b8605Smrg                           const EGLint *attrib_list)
1589848b8605Smrg{
1590b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1591b8e80941Smrg   return dri2_dpy->vtbl->create_window_surface(drv, disp, conf, native_window,
1592848b8605Smrg                                                attrib_list);
1593848b8605Smrg}
1594848b8605Smrg
1595848b8605Smrgstatic _EGLSurface*
1596b8e80941Smrgdri2_create_pixmap_surface(_EGLDriver *drv, _EGLDisplay *disp,
1597848b8605Smrg                           _EGLConfig *conf, void *native_pixmap,
1598848b8605Smrg                           const EGLint *attrib_list)
1599848b8605Smrg{
1600b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1601b8e80941Smrg   return dri2_dpy->vtbl->create_pixmap_surface(drv, disp, conf, native_pixmap,
1602848b8605Smrg                                                attrib_list);
1603848b8605Smrg}
1604848b8605Smrg
1605848b8605Smrgstatic _EGLSurface*
1606b8e80941Smrgdri2_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
1607848b8605Smrg                           _EGLConfig *conf, const EGLint *attrib_list)
1608848b8605Smrg{
1609b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1610b8e80941Smrg   return dri2_dpy->vtbl->create_pbuffer_surface(drv, disp, conf, attrib_list);
1611848b8605Smrg}
1612848b8605Smrg
1613848b8605Smrgstatic EGLBoolean
1614b8e80941Smrgdri2_swap_interval(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
1615b8e80941Smrg                   EGLint interval)
1616848b8605Smrg{
1617b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1618b8e80941Smrg   if (!dri2_dpy->vtbl->swap_interval)
1619b8e80941Smrg      return EGL_TRUE;
1620b8e80941Smrg   return dri2_dpy->vtbl->swap_interval(drv, disp, surf, interval);
1621848b8605Smrg}
1622848b8605Smrg
1623b8e80941Smrg/**
1624b8e80941Smrg * Asks the client API to flush any rendering to the drawable so that we can
1625b8e80941Smrg * do our swapbuffers.
1626b8e80941Smrg */
1627b8e80941Smrgvoid
1628b8e80941Smrgdri2_flush_drawable_for_swapbuffers(_EGLDisplay *disp, _EGLSurface *draw)
1629848b8605Smrg{
1630b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1631b8e80941Smrg   __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(draw);
1632b8e80941Smrg
1633b8e80941Smrg   if (dri2_dpy->flush) {
1634b8e80941Smrg      if (dri2_dpy->flush->base.version >= 4) {
1635b8e80941Smrg         /* We know there's a current context because:
1636b8e80941Smrg          *
1637b8e80941Smrg          *     "If surface is not bound to the calling thread’s current
1638b8e80941Smrg          *      context, an EGL_BAD_SURFACE error is generated."
1639b8e80941Smrg         */
1640b8e80941Smrg         _EGLContext *ctx = _eglGetCurrentContext();
1641b8e80941Smrg         struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1642b8e80941Smrg
1643b8e80941Smrg         /* From the EGL 1.4 spec (page 52):
1644b8e80941Smrg          *
1645b8e80941Smrg          *     "The contents of ancillary buffers are always undefined
1646b8e80941Smrg          *      after calling eglSwapBuffers."
1647b8e80941Smrg          */
1648b8e80941Smrg         dri2_dpy->flush->flush_with_flags(dri2_ctx->dri_context,
1649b8e80941Smrg                                           dri_drawable,
1650b8e80941Smrg                                           __DRI2_FLUSH_DRAWABLE |
1651b8e80941Smrg                                           __DRI2_FLUSH_INVALIDATE_ANCILLARY,
1652b8e80941Smrg                                           __DRI2_THROTTLE_SWAPBUFFER);
1653b8e80941Smrg      } else {
1654b8e80941Smrg         dri2_dpy->flush->flush(dri_drawable);
1655b8e80941Smrg      }
1656b8e80941Smrg   }
1657848b8605Smrg}
1658848b8605Smrg
1659848b8605Smrgstatic EGLBoolean
1660b8e80941Smrgdri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
1661848b8605Smrg{
1662b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1663b8e80941Smrg   _EGLContext *ctx = _eglGetCurrentContext();
1664b8e80941Smrg
1665b8e80941Smrg   if (ctx && surf)
1666b8e80941Smrg      dri2_surf_update_fence_fd(ctx, disp, surf);
1667b8e80941Smrg   return dri2_dpy->vtbl->swap_buffers(drv, disp, surf);
1668848b8605Smrg}
1669848b8605Smrg
1670848b8605Smrgstatic EGLBoolean
1671b8e80941Smrgdri2_swap_buffers_with_damage(_EGLDriver *drv, _EGLDisplay *disp,
1672848b8605Smrg                              _EGLSurface *surf,
1673848b8605Smrg                              const EGLint *rects, EGLint n_rects)
1674848b8605Smrg{
1675b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1676b8e80941Smrg   _EGLContext *ctx = _eglGetCurrentContext();
1677b8e80941Smrg
1678b8e80941Smrg   if (ctx && surf)
1679b8e80941Smrg      dri2_surf_update_fence_fd(ctx, disp, surf);
1680b8e80941Smrg   return dri2_dpy->vtbl->swap_buffers_with_damage(drv, disp, surf,
1681848b8605Smrg                                                   rects, n_rects);
1682848b8605Smrg}
1683848b8605Smrg
1684848b8605Smrgstatic EGLBoolean
1685b8e80941Smrgdri2_swap_buffers_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
1686848b8605Smrg                         EGLint numRects, const EGLint *rects)
1687848b8605Smrg{
1688b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1689b8e80941Smrg   return dri2_dpy->vtbl->swap_buffers_region(drv, disp, surf, numRects, rects);
1690b8e80941Smrg}
1691b8e80941Smrg
1692b8e80941Smrgstatic EGLBoolean
1693b8e80941Smrgdri2_set_damage_region(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
1694b8e80941Smrg                       EGLint *rects, EGLint n_rects)
1695b8e80941Smrg{
1696b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1697b8e80941Smrg   return dri2_dpy->vtbl->set_damage_region(drv, disp, surf, rects, n_rects);
1698848b8605Smrg}
1699848b8605Smrg
1700848b8605Smrgstatic EGLBoolean
1701b8e80941Smrgdri2_post_sub_buffer(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
1702848b8605Smrg                     EGLint x, EGLint y, EGLint width, EGLint height)
1703848b8605Smrg{
1704b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1705b8e80941Smrg   return dri2_dpy->vtbl->post_sub_buffer(drv, disp, surf, x, y, width, height);
1706848b8605Smrg}
1707848b8605Smrg
1708848b8605Smrgstatic EGLBoolean
1709b8e80941Smrgdri2_copy_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
1710848b8605Smrg                  void *native_pixmap_target)
1711848b8605Smrg{
1712b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1713b8e80941Smrg   return dri2_dpy->vtbl->copy_buffers(drv, disp, surf, native_pixmap_target);
1714848b8605Smrg}
1715848b8605Smrg
1716848b8605Smrgstatic EGLint
1717b8e80941Smrgdri2_query_buffer_age(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
1718848b8605Smrg{
1719b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1720b8e80941Smrg   return dri2_dpy->vtbl->query_buffer_age(drv, disp, surf);
1721848b8605Smrg}
1722848b8605Smrg
1723848b8605Smrgstatic EGLBoolean
1724848b8605Smrgdri2_wait_client(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx)
1725848b8605Smrg{
1726848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1727b8e80941Smrg   _EGLSurface *surf = ctx->DrawSurface;
1728b8e80941Smrg   __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
1729848b8605Smrg
1730848b8605Smrg   (void) drv;
1731848b8605Smrg
1732848b8605Smrg   /* FIXME: If EGL allows frontbuffer rendering for window surfaces,
1733848b8605Smrg    * we need to copy fake to real here.*/
1734848b8605Smrg
1735848b8605Smrg   if (dri2_dpy->flush != NULL)
1736b8e80941Smrg      dri2_dpy->flush->flush(dri_drawable);
1737848b8605Smrg
1738848b8605Smrg   return EGL_TRUE;
1739848b8605Smrg}
1740848b8605Smrg
1741848b8605Smrgstatic EGLBoolean
1742848b8605Smrgdri2_wait_native(_EGLDriver *drv, _EGLDisplay *disp, EGLint engine)
1743848b8605Smrg{
1744848b8605Smrg   (void) drv;
1745848b8605Smrg   (void) disp;
1746848b8605Smrg
1747848b8605Smrg   if (engine != EGL_CORE_NATIVE_ENGINE)
1748848b8605Smrg      return _eglError(EGL_BAD_PARAMETER, "eglWaitNative");
1749848b8605Smrg   /* glXWaitX(); */
1750848b8605Smrg
1751848b8605Smrg   return EGL_TRUE;
1752848b8605Smrg}
1753848b8605Smrg
1754848b8605Smrgstatic EGLBoolean
1755848b8605Smrgdri2_bind_tex_image(_EGLDriver *drv,
1756b8e80941Smrg                    _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
1757848b8605Smrg{
1758848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1759848b8605Smrg   struct dri2_egl_context *dri2_ctx;
1760848b8605Smrg   _EGLContext *ctx;
1761848b8605Smrg   GLint format, target;
1762b8e80941Smrg   __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
1763848b8605Smrg
1764848b8605Smrg   ctx = _eglGetCurrentContext();
1765848b8605Smrg   dri2_ctx = dri2_egl_context(ctx);
1766848b8605Smrg
1767848b8605Smrg   if (!_eglBindTexImage(drv, disp, surf, buffer))
1768848b8605Smrg      return EGL_FALSE;
1769848b8605Smrg
1770b8e80941Smrg   switch (surf->TextureFormat) {
1771848b8605Smrg   case EGL_TEXTURE_RGB:
1772848b8605Smrg      format = __DRI_TEXTURE_FORMAT_RGB;
1773848b8605Smrg      break;
1774848b8605Smrg   case EGL_TEXTURE_RGBA:
1775848b8605Smrg      format = __DRI_TEXTURE_FORMAT_RGBA;
1776848b8605Smrg      break;
1777848b8605Smrg   default:
1778b8e80941Smrg      assert(!"Unexpected texture format in dri2_bind_tex_image()");
1779b8e80941Smrg      format = __DRI_TEXTURE_FORMAT_RGBA;
1780848b8605Smrg   }
1781848b8605Smrg
1782b8e80941Smrg   switch (surf->TextureTarget) {
1783848b8605Smrg   case EGL_TEXTURE_2D:
1784848b8605Smrg      target = GL_TEXTURE_2D;
1785848b8605Smrg      break;
1786848b8605Smrg   default:
1787b8e80941Smrg      target = GL_TEXTURE_2D;
1788b8e80941Smrg      assert(!"Unexpected texture target in dri2_bind_tex_image()");
1789848b8605Smrg   }
1790848b8605Smrg
1791b8e80941Smrg   dri2_dpy->tex_buffer->setTexBuffer2(dri2_ctx->dri_context,
1792b8e80941Smrg                                       target, format,
1793b8e80941Smrg                                       dri_drawable);
1794848b8605Smrg
1795848b8605Smrg   return EGL_TRUE;
1796848b8605Smrg}
1797848b8605Smrg
1798848b8605Smrgstatic EGLBoolean
1799848b8605Smrgdri2_release_tex_image(_EGLDriver *drv,
1800b8e80941Smrg                       _EGLDisplay *disp, _EGLSurface *surf, EGLint buffer)
1801848b8605Smrg{
1802848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1803848b8605Smrg   struct dri2_egl_context *dri2_ctx;
1804848b8605Smrg   _EGLContext *ctx;
1805848b8605Smrg   GLint  target;
1806b8e80941Smrg   __DRIdrawable *dri_drawable = dri2_dpy->vtbl->get_dri_drawable(surf);
1807848b8605Smrg
1808848b8605Smrg   ctx = _eglGetCurrentContext();
1809848b8605Smrg   dri2_ctx = dri2_egl_context(ctx);
1810848b8605Smrg
1811848b8605Smrg   if (!_eglReleaseTexImage(drv, disp, surf, buffer))
1812848b8605Smrg      return EGL_FALSE;
1813848b8605Smrg
1814b8e80941Smrg   switch (surf->TextureTarget) {
1815848b8605Smrg   case EGL_TEXTURE_2D:
1816848b8605Smrg      target = GL_TEXTURE_2D;
1817848b8605Smrg      break;
1818848b8605Smrg   default:
1819b8e80941Smrg      assert(!"missing texture target");
1820848b8605Smrg   }
1821848b8605Smrg
1822848b8605Smrg   if (dri2_dpy->tex_buffer->base.version >= 3 &&
1823848b8605Smrg       dri2_dpy->tex_buffer->releaseTexBuffer != NULL) {
1824b8e80941Smrg      dri2_dpy->tex_buffer->releaseTexBuffer(dri2_ctx->dri_context,
1825b8e80941Smrg                                             target, dri_drawable);
1826848b8605Smrg   }
1827848b8605Smrg
1828848b8605Smrg   return EGL_TRUE;
1829848b8605Smrg}
1830848b8605Smrg
1831848b8605Smrgstatic _EGLImage*
1832b8e80941Smrgdri2_create_image(_EGLDriver *drv, _EGLDisplay *disp, _EGLContext *ctx,
1833848b8605Smrg                  EGLenum target, EGLClientBuffer buffer,
1834848b8605Smrg                  const EGLint *attr_list)
1835848b8605Smrg{
1836b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1837b8e80941Smrg   return dri2_dpy->vtbl->create_image(drv, disp, ctx, target, buffer,
1838848b8605Smrg                                       attr_list);
1839848b8605Smrg}
1840848b8605Smrg
1841848b8605Smrgstatic _EGLImage *
1842848b8605Smrgdri2_create_image_from_dri(_EGLDisplay *disp, __DRIimage *dri_image)
1843848b8605Smrg{
1844848b8605Smrg   struct dri2_egl_image *dri2_img;
1845848b8605Smrg
1846848b8605Smrg   if (dri_image == NULL) {
1847848b8605Smrg      _eglError(EGL_BAD_ALLOC, "dri2_create_image");
1848848b8605Smrg      return NULL;
1849848b8605Smrg   }
1850848b8605Smrg
1851848b8605Smrg   dri2_img = malloc(sizeof *dri2_img);
1852848b8605Smrg   if (!dri2_img) {
1853848b8605Smrg      _eglError(EGL_BAD_ALLOC, "dri2_create_image");
1854848b8605Smrg      return NULL;
1855848b8605Smrg   }
1856848b8605Smrg
1857b8e80941Smrg   _eglInitImage(&dri2_img->base, disp);
1858848b8605Smrg
1859848b8605Smrg   dri2_img->dri_image = dri_image;
1860848b8605Smrg
1861848b8605Smrg   return &dri2_img->base;
1862848b8605Smrg}
1863848b8605Smrg
1864b8e80941Smrg/**
1865b8e80941Smrg * Translate a DRI Image extension error code into an EGL error code.
1866b8e80941Smrg */
1867b8e80941Smrgstatic EGLint
1868b8e80941Smrgegl_error_from_dri_image_error(int dri_error)
1869b8e80941Smrg{
1870b8e80941Smrg   switch (dri_error) {
1871b8e80941Smrg   case __DRI_IMAGE_ERROR_SUCCESS:
1872b8e80941Smrg      return EGL_SUCCESS;
1873b8e80941Smrg   case __DRI_IMAGE_ERROR_BAD_ALLOC:
1874b8e80941Smrg      return EGL_BAD_ALLOC;
1875b8e80941Smrg   case __DRI_IMAGE_ERROR_BAD_MATCH:
1876b8e80941Smrg      return EGL_BAD_MATCH;
1877b8e80941Smrg   case __DRI_IMAGE_ERROR_BAD_PARAMETER:
1878b8e80941Smrg      return EGL_BAD_PARAMETER;
1879b8e80941Smrg   case __DRI_IMAGE_ERROR_BAD_ACCESS:
1880b8e80941Smrg      return EGL_BAD_ACCESS;
1881b8e80941Smrg   default:
1882b8e80941Smrg      assert(!"unknown dri_error code");
1883b8e80941Smrg      return EGL_BAD_ALLOC;
1884b8e80941Smrg   }
1885b8e80941Smrg}
1886b8e80941Smrg
1887848b8605Smrgstatic _EGLImage *
1888848b8605Smrgdri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx,
1889b8e80941Smrg                                   EGLClientBuffer buffer,
1890b8e80941Smrg                                   const EGLint *attr_list)
1891848b8605Smrg{
1892848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1893848b8605Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
1894848b8605Smrg   GLuint renderbuffer = (GLuint) (uintptr_t) buffer;
1895848b8605Smrg   __DRIimage *dri_image;
1896848b8605Smrg
1897848b8605Smrg   if (renderbuffer == 0) {
1898848b8605Smrg      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
1899848b8605Smrg      return EGL_NO_IMAGE_KHR;
1900848b8605Smrg   }
1901848b8605Smrg
1902b8e80941Smrg   if (!disp->Extensions.KHR_gl_renderbuffer_image) {
1903b8e80941Smrg      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
1904b8e80941Smrg      return EGL_NO_IMAGE_KHR;
1905b8e80941Smrg   }
1906848b8605Smrg
1907b8e80941Smrg   if (dri2_dpy->image->base.version >= 17 &&
1908b8e80941Smrg       dri2_dpy->image->createImageFromRenderbuffer2) {
1909b8e80941Smrg      unsigned error = ~0;
1910848b8605Smrg
1911b8e80941Smrg      dri_image = dri2_dpy->image->createImageFromRenderbuffer2(
1912b8e80941Smrg               dri2_ctx->dri_context, renderbuffer, NULL, &error);
1913848b8605Smrg
1914b8e80941Smrg      assert(!!dri_image == (error == __DRI_IMAGE_ERROR_SUCCESS));
1915848b8605Smrg
1916b8e80941Smrg      if (!dri_image) {
1917b8e80941Smrg         _eglError(egl_error_from_dri_image_error(error), "dri2_create_image_khr");
1918b8e80941Smrg         return EGL_NO_IMAGE_KHR;
1919b8e80941Smrg      }
1920b8e80941Smrg   } else {
1921b8e80941Smrg      dri_image = dri2_dpy->image->createImageFromRenderbuffer(
1922b8e80941Smrg               dri2_ctx->dri_context, renderbuffer, NULL);
1923b8e80941Smrg      if (!dri_image) {
1924b8e80941Smrg         _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
1925b8e80941Smrg         return EGL_NO_IMAGE_KHR;
1926b8e80941Smrg      }
1927848b8605Smrg   }
1928848b8605Smrg
1929848b8605Smrg   return dri2_create_image_from_dri(disp, dri_image);
1930848b8605Smrg}
1931848b8605Smrg
1932848b8605Smrg#ifdef HAVE_WAYLAND_PLATFORM
1933848b8605Smrg
1934848b8605Smrg/* This structure describes how a wl_buffer maps to one or more
1935848b8605Smrg * __DRIimages.  A wl_drm_buffer stores the wl_drm format code and the
1936848b8605Smrg * offsets and strides of the planes in the buffer.  This table maps a
1937848b8605Smrg * wl_drm format code to a description of the planes in the buffer
1938848b8605Smrg * that lets us create a __DRIimage for each of the planes. */
1939848b8605Smrg
1940848b8605Smrgstatic const struct wl_drm_components_descriptor {
1941848b8605Smrg   uint32_t dri_components;
1942848b8605Smrg   EGLint components;
1943848b8605Smrg   int nplanes;
1944848b8605Smrg} wl_drm_components[] = {
1945848b8605Smrg   { __DRI_IMAGE_COMPONENTS_RGB, EGL_TEXTURE_RGB, 1 },
1946848b8605Smrg   { __DRI_IMAGE_COMPONENTS_RGBA, EGL_TEXTURE_RGBA, 1 },
1947848b8605Smrg   { __DRI_IMAGE_COMPONENTS_Y_U_V, EGL_TEXTURE_Y_U_V_WL, 3 },
1948848b8605Smrg   { __DRI_IMAGE_COMPONENTS_Y_UV, EGL_TEXTURE_Y_UV_WL, 2 },
1949848b8605Smrg   { __DRI_IMAGE_COMPONENTS_Y_XUXV, EGL_TEXTURE_Y_XUXV_WL, 2 },
1950848b8605Smrg};
1951848b8605Smrg
1952848b8605Smrgstatic _EGLImage *
1953848b8605Smrgdri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx,
1954b8e80941Smrg                                    EGLClientBuffer _buffer,
1955b8e80941Smrg                                    const EGLint *attr_list)
1956848b8605Smrg{
1957848b8605Smrg   struct wl_drm_buffer *buffer;
1958848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1959848b8605Smrg   const struct wl_drm_components_descriptor *f;
1960848b8605Smrg   __DRIimage *dri_image;
1961848b8605Smrg   _EGLImageAttribs attrs;
1962848b8605Smrg   int32_t plane;
1963848b8605Smrg
1964848b8605Smrg   buffer = wayland_drm_buffer_get(dri2_dpy->wl_server_drm,
1965848b8605Smrg                                   (struct wl_resource *) _buffer);
1966848b8605Smrg   if (!buffer)
1967848b8605Smrg       return NULL;
1968848b8605Smrg
1969b8e80941Smrg   if (!_eglParseImageAttribList(&attrs, disp, attr_list))
1970848b8605Smrg      return NULL;
1971848b8605Smrg
1972b8e80941Smrg   plane = attrs.PlaneWL;
1973848b8605Smrg   f = buffer->driver_format;
1974848b8605Smrg   if (plane < 0 || plane >= f->nplanes) {
1975848b8605Smrg      _eglError(EGL_BAD_PARAMETER,
1976848b8605Smrg                "dri2_create_image_wayland_wl_buffer (plane out of bounds)");
1977848b8605Smrg      return NULL;
1978848b8605Smrg   }
1979848b8605Smrg
1980848b8605Smrg   dri_image = dri2_dpy->image->fromPlanar(buffer->driver_buffer, plane, NULL);
1981b8e80941Smrg   if (dri_image == NULL && plane == 0)
1982b8e80941Smrg      dri_image = dri2_dpy->image->dupImage(buffer->driver_buffer, NULL);
1983848b8605Smrg   if (dri_image == NULL) {
1984848b8605Smrg      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer");
1985848b8605Smrg      return NULL;
1986848b8605Smrg   }
1987848b8605Smrg
1988848b8605Smrg   return dri2_create_image_from_dri(disp, dri_image);
1989848b8605Smrg}
1990848b8605Smrg#endif
1991848b8605Smrg
1992848b8605Smrgstatic EGLBoolean
1993b8e80941Smrgdri2_get_sync_values_chromium(_EGLDisplay *disp, _EGLSurface *surf,
1994848b8605Smrg                              EGLuint64KHR *ust, EGLuint64KHR *msc,
1995848b8605Smrg                              EGLuint64KHR *sbc)
1996848b8605Smrg{
1997b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1998b8e80941Smrg   return dri2_dpy->vtbl->get_sync_values(disp, surf, ust, msc, sbc);
1999848b8605Smrg}
2000848b8605Smrg
2001848b8605Smrg/**
2002848b8605Smrg * Set the error code after a call to
2003848b8605Smrg * dri2_egl_image::dri_image::createImageFromTexture.
2004848b8605Smrg */
2005848b8605Smrgstatic void
2006848b8605Smrgdri2_create_image_khr_texture_error(int dri_error)
2007848b8605Smrg{
2008b8e80941Smrg   EGLint egl_error = egl_error_from_dri_image_error(dri_error);
2009848b8605Smrg
2010b8e80941Smrg   if (egl_error != EGL_SUCCESS)
2011b8e80941Smrg      _eglError(egl_error, "dri2_create_image_khr_texture");
2012848b8605Smrg}
2013848b8605Smrg
2014848b8605Smrgstatic _EGLImage *
2015848b8605Smrgdri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx,
2016b8e80941Smrg                                   EGLenum target,
2017b8e80941Smrg                                   EGLClientBuffer buffer,
2018b8e80941Smrg                                   const EGLint *attr_list)
2019848b8605Smrg{
2020848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2021848b8605Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
2022848b8605Smrg   struct dri2_egl_image *dri2_img;
2023848b8605Smrg   GLuint texture = (GLuint) (uintptr_t) buffer;
2024848b8605Smrg   _EGLImageAttribs attrs;
2025848b8605Smrg   GLuint depth;
2026848b8605Smrg   GLenum gl_target;
2027848b8605Smrg   unsigned error;
2028848b8605Smrg
2029848b8605Smrg   if (texture == 0) {
2030848b8605Smrg      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
2031848b8605Smrg      return EGL_NO_IMAGE_KHR;
2032848b8605Smrg   }
2033848b8605Smrg
2034b8e80941Smrg   if (!_eglParseImageAttribList(&attrs, disp, attr_list))
2035848b8605Smrg      return EGL_NO_IMAGE_KHR;
2036848b8605Smrg
2037848b8605Smrg   switch (target) {
2038848b8605Smrg   case EGL_GL_TEXTURE_2D_KHR:
2039b8e80941Smrg      if (!disp->Extensions.KHR_gl_texture_2D_image) {
2040b8e80941Smrg         _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
2041b8e80941Smrg         return EGL_NO_IMAGE_KHR;
2042b8e80941Smrg      }
2043848b8605Smrg      depth = 0;
2044848b8605Smrg      gl_target = GL_TEXTURE_2D;
2045848b8605Smrg      break;
2046848b8605Smrg   case EGL_GL_TEXTURE_3D_KHR:
2047b8e80941Smrg      if (!disp->Extensions.KHR_gl_texture_3D_image) {
2048b8e80941Smrg         _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
2049b8e80941Smrg         return EGL_NO_IMAGE_KHR;
2050b8e80941Smrg      }
2051b8e80941Smrg
2052848b8605Smrg      depth = attrs.GLTextureZOffset;
2053848b8605Smrg      gl_target = GL_TEXTURE_3D;
2054848b8605Smrg      break;
2055848b8605Smrg   case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
2056848b8605Smrg   case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
2057848b8605Smrg   case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
2058848b8605Smrg   case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
2059848b8605Smrg   case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
2060848b8605Smrg   case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
2061b8e80941Smrg      if (!disp->Extensions.KHR_gl_texture_cubemap_image) {
2062b8e80941Smrg         _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
2063b8e80941Smrg         return EGL_NO_IMAGE_KHR;
2064b8e80941Smrg      }
2065b8e80941Smrg
2066848b8605Smrg      depth = target - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR;
2067848b8605Smrg      gl_target = GL_TEXTURE_CUBE_MAP;
2068848b8605Smrg      break;
2069848b8605Smrg   default:
2070b8e80941Smrg      unreachable("Unexpected target in dri2_create_image_khr_texture()");
2071848b8605Smrg      return EGL_NO_IMAGE_KHR;
2072848b8605Smrg   }
2073848b8605Smrg
2074848b8605Smrg   dri2_img = malloc(sizeof *dri2_img);
2075848b8605Smrg   if (!dri2_img) {
2076848b8605Smrg      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
2077848b8605Smrg      return EGL_NO_IMAGE_KHR;
2078848b8605Smrg   }
2079848b8605Smrg
2080b8e80941Smrg   _eglInitImage(&dri2_img->base, disp);
2081848b8605Smrg
2082848b8605Smrg   dri2_img->dri_image =
2083848b8605Smrg      dri2_dpy->image->createImageFromTexture(dri2_ctx->dri_context,
2084848b8605Smrg                                              gl_target,
2085848b8605Smrg                                              texture,
2086848b8605Smrg                                              depth,
2087848b8605Smrg                                              attrs.GLTextureLevel,
2088848b8605Smrg                                              &error,
2089848b8605Smrg                                              dri2_img);
2090848b8605Smrg   dri2_create_image_khr_texture_error(error);
2091848b8605Smrg
2092848b8605Smrg   if (!dri2_img->dri_image) {
2093848b8605Smrg      free(dri2_img);
2094848b8605Smrg      return EGL_NO_IMAGE_KHR;
2095848b8605Smrg   }
2096848b8605Smrg   return &dri2_img->base;
2097848b8605Smrg}
2098848b8605Smrg
2099b8e80941Smrgstatic EGLBoolean
2100b8e80941Smrgdri2_query_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf,
2101b8e80941Smrg                   EGLint attribute, EGLint *value)
2102b8e80941Smrg{
2103b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2104b8e80941Smrg   if (!dri2_dpy->vtbl->query_surface)
2105b8e80941Smrg      return _eglQuerySurface(drv, disp, surf, attribute, value);
2106b8e80941Smrg   return dri2_dpy->vtbl->query_surface(drv, disp, surf, attribute, value);
2107b8e80941Smrg}
2108b8e80941Smrg
2109848b8605Smrgstatic struct wl_buffer*
2110b8e80941Smrgdri2_create_wayland_buffer_from_image(_EGLDriver *drv, _EGLDisplay *disp,
2111848b8605Smrg                                      _EGLImage *img)
2112848b8605Smrg{
2113b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2114b8e80941Smrg   return dri2_dpy->vtbl->create_wayland_buffer_from_image(drv, disp, img);
2115b8e80941Smrg}
2116b8e80941Smrg
2117b8e80941Smrg#ifdef HAVE_LIBDRM
2118b8e80941Smrgstatic _EGLImage *
2119b8e80941Smrgdri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx,
2120b8e80941Smrg                                  EGLClientBuffer buffer, const EGLint *attr_list)
2121b8e80941Smrg{
2122b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2123b8e80941Smrg   EGLint format, name, pitch;
2124b8e80941Smrg   _EGLImageAttribs attrs;
2125b8e80941Smrg   __DRIimage *dri_image;
2126b8e80941Smrg
2127b8e80941Smrg   name = (EGLint) (uintptr_t) buffer;
2128b8e80941Smrg
2129b8e80941Smrg   if (!_eglParseImageAttribList(&attrs, disp, attr_list))
2130b8e80941Smrg      return NULL;
2131b8e80941Smrg
2132b8e80941Smrg   if (attrs.Width <= 0 || attrs.Height <= 0 ||
2133b8e80941Smrg       attrs.DRMBufferStrideMESA <= 0) {
2134b8e80941Smrg      _eglError(EGL_BAD_PARAMETER,
2135b8e80941Smrg                "bad width, height or stride");
2136b8e80941Smrg      return NULL;
2137b8e80941Smrg   }
2138b8e80941Smrg
2139b8e80941Smrg   switch (attrs.DRMBufferFormatMESA) {
2140b8e80941Smrg   case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
2141b8e80941Smrg      format = __DRI_IMAGE_FORMAT_ARGB8888;
2142b8e80941Smrg      pitch = attrs.DRMBufferStrideMESA;
2143b8e80941Smrg      break;
2144b8e80941Smrg   default:
2145b8e80941Smrg      _eglError(EGL_BAD_PARAMETER,
2146b8e80941Smrg                "dri2_create_image_khr: unsupported pixmap depth");
2147b8e80941Smrg      return NULL;
2148b8e80941Smrg   }
2149b8e80941Smrg
2150b8e80941Smrg   dri_image =
2151b8e80941Smrg      dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
2152b8e80941Smrg                                           attrs.Width,
2153b8e80941Smrg                                           attrs.Height,
2154b8e80941Smrg                                           format,
2155b8e80941Smrg                                           name,
2156b8e80941Smrg                                           pitch,
2157b8e80941Smrg                                           NULL);
2158b8e80941Smrg
2159b8e80941Smrg   return dri2_create_image_from_dri(disp, dri_image);
2160848b8605Smrg}
2161848b8605Smrg
2162848b8605Smrgstatic EGLBoolean
2163848b8605Smrgdri2_check_dma_buf_attribs(const _EGLImageAttribs *attrs)
2164848b8605Smrg{
2165848b8605Smrg   /**
2166848b8605Smrg     * The spec says:
2167848b8605Smrg     *
2168848b8605Smrg     * "Required attributes and their values are as follows:
2169848b8605Smrg     *
2170848b8605Smrg     *  * EGL_WIDTH & EGL_HEIGHT: The logical dimensions of the buffer in pixels
2171848b8605Smrg     *
2172848b8605Smrg     *  * EGL_LINUX_DRM_FOURCC_EXT: The pixel format of the buffer, as specified
2173848b8605Smrg     *    by drm_fourcc.h and used as the pixel_format parameter of the
2174848b8605Smrg     *    drm_mode_fb_cmd2 ioctl."
2175848b8605Smrg     *
2176848b8605Smrg     * and
2177848b8605Smrg     *
2178848b8605Smrg     * "* If <target> is EGL_LINUX_DMA_BUF_EXT, and the list of attributes is
2179848b8605Smrg     *    incomplete, EGL_BAD_PARAMETER is generated."
2180848b8605Smrg     */
2181848b8605Smrg   if (attrs->Width <= 0 || attrs->Height <= 0 ||
2182b8e80941Smrg       !attrs->DMABufFourCC.IsPresent)
2183b8e80941Smrg      return _eglError(EGL_BAD_PARAMETER, "attribute(s) missing");
2184848b8605Smrg
2185848b8605Smrg   /**
2186848b8605Smrg    * Also:
2187848b8605Smrg    *
2188848b8605Smrg    * "If <target> is EGL_LINUX_DMA_BUF_EXT and one or more of the values
2189848b8605Smrg    *  specified for a plane's pitch or offset isn't supported by EGL,
2190848b8605Smrg    *  EGL_BAD_ACCESS is generated."
2191848b8605Smrg    */
2192b8e80941Smrg   for (unsigned i = 0; i < ARRAY_SIZE(attrs->DMABufPlanePitches); ++i) {
2193848b8605Smrg      if (attrs->DMABufPlanePitches[i].IsPresent &&
2194b8e80941Smrg          attrs->DMABufPlanePitches[i].Value <= 0)
2195b8e80941Smrg         return _eglError(EGL_BAD_ACCESS, "invalid pitch");
2196b8e80941Smrg   }
2197b8e80941Smrg
2198b8e80941Smrg   /**
2199b8e80941Smrg    * If <target> is EGL_LINUX_DMA_BUF_EXT, both or neither of the following
2200b8e80941Smrg    * attribute values may be given.
2201b8e80941Smrg    *
2202b8e80941Smrg    * This is referring to EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT and
2203b8e80941Smrg    * EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT, and the same for other planes.
2204b8e80941Smrg    */
2205b8e80941Smrg   for (unsigned i = 0; i < DMA_BUF_MAX_PLANES; ++i) {
2206b8e80941Smrg      if (attrs->DMABufPlaneModifiersLo[i].IsPresent !=
2207b8e80941Smrg          attrs->DMABufPlaneModifiersHi[i].IsPresent)
2208b8e80941Smrg         return _eglError(EGL_BAD_PARAMETER, "modifier attribute lo or hi missing");
2209b8e80941Smrg   }
2210b8e80941Smrg
2211b8e80941Smrg   /* Although the EGL_EXT_image_dma_buf_import_modifiers spec doesn't
2212b8e80941Smrg    * mandate it, we only accept the same modifier across all planes. */
2213b8e80941Smrg   for (unsigned i = 1; i < DMA_BUF_MAX_PLANES; ++i) {
2214b8e80941Smrg      if (attrs->DMABufPlaneFds[i].IsPresent) {
2215b8e80941Smrg         if ((attrs->DMABufPlaneModifiersLo[0].IsPresent !=
2216b8e80941Smrg               attrs->DMABufPlaneModifiersLo[i].IsPresent) ||
2217b8e80941Smrg             (attrs->DMABufPlaneModifiersLo[0].Value !=
2218b8e80941Smrg               attrs->DMABufPlaneModifiersLo[i].Value) ||
2219b8e80941Smrg             (attrs->DMABufPlaneModifiersHi[0].Value !=
2220b8e80941Smrg               attrs->DMABufPlaneModifiersHi[i].Value))
2221b8e80941Smrg            return _eglError(EGL_BAD_PARAMETER, "modifier attributes not equal");
2222848b8605Smrg      }
2223848b8605Smrg   }
2224848b8605Smrg
2225848b8605Smrg   return EGL_TRUE;
2226848b8605Smrg}
2227848b8605Smrg
2228b8e80941Smrg/* Returns the total number of planes for the format or zero if it isn't a
2229b8e80941Smrg * valid fourcc format.
2230b8e80941Smrg */
2231848b8605Smrgstatic unsigned
2232b8e80941Smrgdri2_num_fourcc_format_planes(EGLint format)
2233848b8605Smrg{
2234b8e80941Smrg   switch (format) {
2235b8e80941Smrg   case DRM_FORMAT_R8:
2236b8e80941Smrg   case DRM_FORMAT_RG88:
2237b8e80941Smrg   case DRM_FORMAT_GR88:
2238b8e80941Smrg   case DRM_FORMAT_R16:
2239b8e80941Smrg   case DRM_FORMAT_GR1616:
2240848b8605Smrg   case DRM_FORMAT_RGB332:
2241848b8605Smrg   case DRM_FORMAT_BGR233:
2242848b8605Smrg   case DRM_FORMAT_XRGB4444:
2243848b8605Smrg   case DRM_FORMAT_XBGR4444:
2244848b8605Smrg   case DRM_FORMAT_RGBX4444:
2245848b8605Smrg   case DRM_FORMAT_BGRX4444:
2246848b8605Smrg   case DRM_FORMAT_ARGB4444:
2247848b8605Smrg   case DRM_FORMAT_ABGR4444:
2248848b8605Smrg   case DRM_FORMAT_RGBA4444:
2249848b8605Smrg   case DRM_FORMAT_BGRA4444:
2250848b8605Smrg   case DRM_FORMAT_XRGB1555:
2251848b8605Smrg   case DRM_FORMAT_XBGR1555:
2252848b8605Smrg   case DRM_FORMAT_RGBX5551:
2253848b8605Smrg   case DRM_FORMAT_BGRX5551:
2254848b8605Smrg   case DRM_FORMAT_ARGB1555:
2255848b8605Smrg   case DRM_FORMAT_ABGR1555:
2256848b8605Smrg   case DRM_FORMAT_RGBA5551:
2257848b8605Smrg   case DRM_FORMAT_BGRA5551:
2258848b8605Smrg   case DRM_FORMAT_RGB565:
2259848b8605Smrg   case DRM_FORMAT_BGR565:
2260848b8605Smrg   case DRM_FORMAT_RGB888:
2261848b8605Smrg   case DRM_FORMAT_BGR888:
2262848b8605Smrg   case DRM_FORMAT_XRGB8888:
2263848b8605Smrg   case DRM_FORMAT_XBGR8888:
2264848b8605Smrg   case DRM_FORMAT_RGBX8888:
2265848b8605Smrg   case DRM_FORMAT_BGRX8888:
2266848b8605Smrg   case DRM_FORMAT_ARGB8888:
2267848b8605Smrg   case DRM_FORMAT_ABGR8888:
2268848b8605Smrg   case DRM_FORMAT_RGBA8888:
2269848b8605Smrg   case DRM_FORMAT_BGRA8888:
2270848b8605Smrg   case DRM_FORMAT_XRGB2101010:
2271848b8605Smrg   case DRM_FORMAT_XBGR2101010:
2272848b8605Smrg   case DRM_FORMAT_RGBX1010102:
2273848b8605Smrg   case DRM_FORMAT_BGRX1010102:
2274848b8605Smrg   case DRM_FORMAT_ARGB2101010:
2275848b8605Smrg   case DRM_FORMAT_ABGR2101010:
2276848b8605Smrg   case DRM_FORMAT_RGBA1010102:
2277848b8605Smrg   case DRM_FORMAT_BGRA1010102:
2278848b8605Smrg   case DRM_FORMAT_YUYV:
2279848b8605Smrg   case DRM_FORMAT_YVYU:
2280848b8605Smrg   case DRM_FORMAT_UYVY:
2281848b8605Smrg   case DRM_FORMAT_VYUY:
2282b8e80941Smrg   case DRM_FORMAT_AYUV:
2283b8e80941Smrg   case DRM_FORMAT_XYUV8888:
2284b8e80941Smrg      return 1;
2285b8e80941Smrg
2286848b8605Smrg   case DRM_FORMAT_NV12:
2287848b8605Smrg   case DRM_FORMAT_NV21:
2288848b8605Smrg   case DRM_FORMAT_NV16:
2289848b8605Smrg   case DRM_FORMAT_NV61:
2290b8e80941Smrg   case DRM_FORMAT_P010:
2291b8e80941Smrg   case DRM_FORMAT_P012:
2292b8e80941Smrg   case DRM_FORMAT_P016:
2293b8e80941Smrg      return 2;
2294b8e80941Smrg
2295848b8605Smrg   case DRM_FORMAT_YUV410:
2296848b8605Smrg   case DRM_FORMAT_YVU410:
2297848b8605Smrg   case DRM_FORMAT_YUV411:
2298848b8605Smrg   case DRM_FORMAT_YVU411:
2299848b8605Smrg   case DRM_FORMAT_YUV420:
2300848b8605Smrg   case DRM_FORMAT_YVU420:
2301848b8605Smrg   case DRM_FORMAT_YUV422:
2302848b8605Smrg   case DRM_FORMAT_YVU422:
2303848b8605Smrg   case DRM_FORMAT_YUV444:
2304848b8605Smrg   case DRM_FORMAT_YVU444:
2305b8e80941Smrg      return 3;
2306b8e80941Smrg
2307848b8605Smrg   default:
2308848b8605Smrg      return 0;
2309848b8605Smrg   }
2310b8e80941Smrg}
2311b8e80941Smrg
2312b8e80941Smrg/* Returns the total number of file descriptors. Zero indicates an error. */
2313b8e80941Smrgstatic unsigned
2314b8e80941Smrgdri2_check_dma_buf_format(const _EGLImageAttribs *attrs)
2315b8e80941Smrg{
2316b8e80941Smrg   unsigned plane_n = dri2_num_fourcc_format_planes(attrs->DMABufFourCC.Value);
2317b8e80941Smrg   if (plane_n == 0) {
2318b8e80941Smrg      _eglError(EGL_BAD_MATCH, "unknown drm fourcc format");
2319b8e80941Smrg      return 0;
2320b8e80941Smrg   }
2321b8e80941Smrg
2322b8e80941Smrg   for (unsigned i = plane_n; i < DMA_BUF_MAX_PLANES; i++) {
2323b8e80941Smrg      /**
2324b8e80941Smrg       * The modifiers extension spec says:
2325b8e80941Smrg       *
2326b8e80941Smrg       * "Modifiers may modify any attribute of a buffer import, including
2327b8e80941Smrg       *  but not limited to adding extra planes to a format which
2328b8e80941Smrg       *  otherwise does not have those planes. As an example, a modifier
2329b8e80941Smrg       *  may add a plane for an external compression buffer to a
2330b8e80941Smrg       *  single-plane format. The exact meaning and effect of any
2331b8e80941Smrg       *  modifier is canonically defined by drm_fourcc.h, not as part of
2332b8e80941Smrg       *  this extension."
2333b8e80941Smrg       */
2334b8e80941Smrg      if (attrs->DMABufPlaneModifiersLo[i].IsPresent &&
2335b8e80941Smrg          attrs->DMABufPlaneModifiersHi[i].IsPresent) {
2336b8e80941Smrg         plane_n = i + 1;
2337b8e80941Smrg      }
2338b8e80941Smrg   }
2339848b8605Smrg
2340848b8605Smrg   /**
2341848b8605Smrg     * The spec says:
2342848b8605Smrg     *
2343848b8605Smrg     * "* If <target> is EGL_LINUX_DMA_BUF_EXT, and the list of attributes is
2344848b8605Smrg     *    incomplete, EGL_BAD_PARAMETER is generated."
2345848b8605Smrg     */
2346b8e80941Smrg   for (unsigned i = 0; i < plane_n; ++i) {
2347848b8605Smrg      if (!attrs->DMABufPlaneFds[i].IsPresent ||
2348848b8605Smrg          !attrs->DMABufPlaneOffsets[i].IsPresent ||
2349848b8605Smrg          !attrs->DMABufPlanePitches[i].IsPresent) {
2350848b8605Smrg         _eglError(EGL_BAD_PARAMETER, "plane attribute(s) missing");
2351848b8605Smrg         return 0;
2352848b8605Smrg      }
2353848b8605Smrg   }
2354848b8605Smrg
2355848b8605Smrg   /**
2356848b8605Smrg    * The spec also says:
2357848b8605Smrg    *
2358848b8605Smrg    * "If <target> is EGL_LINUX_DMA_BUF_EXT, and the EGL_LINUX_DRM_FOURCC_EXT
2359848b8605Smrg    *  attribute indicates a single-plane format, EGL_BAD_ATTRIBUTE is
2360848b8605Smrg    *  generated if any of the EGL_DMA_BUF_PLANE1_* or EGL_DMA_BUF_PLANE2_*
2361b8e80941Smrg    *  or EGL_DMA_BUF_PLANE3_* attributes are specified."
2362848b8605Smrg    */
2363b8e80941Smrg   for (unsigned i = plane_n; i < DMA_BUF_MAX_PLANES; ++i) {
2364848b8605Smrg      if (attrs->DMABufPlaneFds[i].IsPresent ||
2365848b8605Smrg          attrs->DMABufPlaneOffsets[i].IsPresent ||
2366848b8605Smrg          attrs->DMABufPlanePitches[i].IsPresent) {
2367848b8605Smrg         _eglError(EGL_BAD_ATTRIBUTE, "too many plane attributes");
2368848b8605Smrg         return 0;
2369848b8605Smrg      }
2370848b8605Smrg   }
2371848b8605Smrg
2372848b8605Smrg   return plane_n;
2373848b8605Smrg}
2374848b8605Smrg
2375b8e80941Smrgstatic EGLBoolean
2376b8e80941Smrgdri2_query_dma_buf_formats(_EGLDriver *drv, _EGLDisplay *disp,
2377b8e80941Smrg                            EGLint max, EGLint *formats, EGLint *count)
2378b8e80941Smrg{
2379b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2380b8e80941Smrg   if (max < 0 || (max > 0 && formats == NULL))
2381b8e80941Smrg      return _eglError(EGL_BAD_PARAMETER, "invalid value for max count of formats");
2382b8e80941Smrg
2383b8e80941Smrg   if (dri2_dpy->image->base.version < 15 ||
2384b8e80941Smrg       dri2_dpy->image->queryDmaBufFormats == NULL)
2385b8e80941Smrg      return EGL_FALSE;
2386b8e80941Smrg
2387b8e80941Smrg   if (!dri2_dpy->image->queryDmaBufFormats(dri2_dpy->dri_screen, max,
2388b8e80941Smrg                                            formats, count))
2389b8e80941Smrg      return EGL_FALSE;
2390b8e80941Smrg
2391b8e80941Smrg   if (max > 0) {
2392b8e80941Smrg      /* Assert that all of the formats returned are actually fourcc formats.
2393b8e80941Smrg       * Some day, if we want the internal interface function to be able to
2394b8e80941Smrg       * return the fake fourcc formats defined in dri_interface.h, we'll have
2395b8e80941Smrg       * to do something more clever here to pair the list down to just real
2396b8e80941Smrg       * fourcc formats so that we don't leak the fake internal ones.
2397b8e80941Smrg       */
2398b8e80941Smrg      for (int i = 0; i < *count; i++) {
2399b8e80941Smrg         assert(dri2_num_fourcc_format_planes(formats[i]) > 0);
2400b8e80941Smrg      }
2401b8e80941Smrg   }
2402b8e80941Smrg
2403b8e80941Smrg   return EGL_TRUE;
2404b8e80941Smrg}
2405b8e80941Smrg
2406b8e80941Smrgstatic EGLBoolean
2407b8e80941Smrgdri2_query_dma_buf_modifiers(_EGLDriver *drv, _EGLDisplay *disp, EGLint format,
2408b8e80941Smrg                             EGLint max, EGLuint64KHR *modifiers,
2409b8e80941Smrg                             EGLBoolean *external_only, EGLint *count)
2410b8e80941Smrg{
2411b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2412b8e80941Smrg
2413b8e80941Smrg   if (dri2_num_fourcc_format_planes(format) == 0)
2414b8e80941Smrg      return _eglError(EGL_BAD_PARAMETER, "invalid fourcc format");
2415b8e80941Smrg
2416b8e80941Smrg   if (max < 0)
2417b8e80941Smrg      return _eglError(EGL_BAD_PARAMETER, "invalid value for max count of formats");
2418b8e80941Smrg
2419b8e80941Smrg   if (max > 0 && modifiers == NULL)
2420b8e80941Smrg      return _eglError(EGL_BAD_PARAMETER, "invalid modifiers array");
2421b8e80941Smrg
2422b8e80941Smrg   if (dri2_dpy->image->base.version < 15 ||
2423b8e80941Smrg       dri2_dpy->image->queryDmaBufModifiers == NULL)
2424b8e80941Smrg      return EGL_FALSE;
2425b8e80941Smrg
2426b8e80941Smrg   if (dri2_dpy->image->queryDmaBufModifiers(dri2_dpy->dri_screen, format,
2427b8e80941Smrg                                             max, modifiers,
2428b8e80941Smrg                                             (unsigned int *) external_only,
2429b8e80941Smrg                                             count) == false)
2430b8e80941Smrg      return _eglError(EGL_BAD_PARAMETER, "invalid format");
2431b8e80941Smrg
2432b8e80941Smrg   return EGL_TRUE;
2433b8e80941Smrg}
2434b8e80941Smrg
2435848b8605Smrg/**
2436848b8605Smrg * The spec says:
2437848b8605Smrg *
2438848b8605Smrg * "If eglCreateImageKHR is successful for a EGL_LINUX_DMA_BUF_EXT target, the
2439848b8605Smrg *  EGL will take a reference to the dma_buf(s) which it will release at any
2440848b8605Smrg *  time while the EGLDisplay is initialized. It is the responsibility of the
2441848b8605Smrg *  application to close the dma_buf file descriptors."
2442848b8605Smrg *
2443848b8605Smrg * Therefore we must never close or otherwise modify the file descriptors.
2444848b8605Smrg */
2445b8e80941Smrg_EGLImage *
2446848b8605Smrgdri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx,
2447b8e80941Smrg                          EGLClientBuffer buffer, const EGLint *attr_list)
2448848b8605Smrg{
2449848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2450848b8605Smrg   _EGLImage *res;
2451848b8605Smrg   _EGLImageAttribs attrs;
2452848b8605Smrg   __DRIimage *dri_image;
2453848b8605Smrg   unsigned num_fds;
2454b8e80941Smrg   int fds[DMA_BUF_MAX_PLANES];
2455b8e80941Smrg   int pitches[DMA_BUF_MAX_PLANES];
2456b8e80941Smrg   int offsets[DMA_BUF_MAX_PLANES];
2457b8e80941Smrg   uint64_t modifier;
2458b8e80941Smrg   bool has_modifier = false;
2459848b8605Smrg   unsigned error;
2460848b8605Smrg
2461848b8605Smrg   /**
2462848b8605Smrg    * The spec says:
2463848b8605Smrg    *
2464848b8605Smrg    * ""* If <target> is EGL_LINUX_DMA_BUF_EXT and <buffer> is not NULL, the
2465848b8605Smrg    *     error EGL_BAD_PARAMETER is generated."
2466848b8605Smrg    */
2467848b8605Smrg   if (buffer != NULL) {
2468848b8605Smrg      _eglError(EGL_BAD_PARAMETER, "buffer not NULL");
2469848b8605Smrg      return NULL;
2470848b8605Smrg   }
2471848b8605Smrg
2472b8e80941Smrg   if (!_eglParseImageAttribList(&attrs, disp, attr_list))
2473848b8605Smrg      return NULL;
2474848b8605Smrg
2475848b8605Smrg   if (!dri2_check_dma_buf_attribs(&attrs))
2476848b8605Smrg      return NULL;
2477848b8605Smrg
2478848b8605Smrg   num_fds = dri2_check_dma_buf_format(&attrs);
2479848b8605Smrg   if (!num_fds)
2480848b8605Smrg      return NULL;
2481848b8605Smrg
2482b8e80941Smrg   for (unsigned i = 0; i < num_fds; ++i) {
2483848b8605Smrg      fds[i] = attrs.DMABufPlaneFds[i].Value;
2484848b8605Smrg      pitches[i] = attrs.DMABufPlanePitches[i].Value;
2485848b8605Smrg      offsets[i] = attrs.DMABufPlaneOffsets[i].Value;
2486848b8605Smrg   }
2487848b8605Smrg
2488b8e80941Smrg   /* dri2_check_dma_buf_attribs ensures that the modifier, if available,
2489b8e80941Smrg    * will be present in attrs.DMABufPlaneModifiersLo[0] and
2490b8e80941Smrg    * attrs.DMABufPlaneModifiersHi[0] */
2491b8e80941Smrg   if (attrs.DMABufPlaneModifiersLo[0].IsPresent) {
2492b8e80941Smrg      modifier = combine_u32_into_u64(attrs.DMABufPlaneModifiersHi[0].Value,
2493b8e80941Smrg                                      attrs.DMABufPlaneModifiersLo[0].Value);
2494b8e80941Smrg      has_modifier = true;
2495b8e80941Smrg   }
2496b8e80941Smrg
2497b8e80941Smrg   if (has_modifier) {
2498b8e80941Smrg      if (dri2_dpy->image->base.version < 15 ||
2499b8e80941Smrg          dri2_dpy->image->createImageFromDmaBufs2 == NULL) {
2500b8e80941Smrg         _eglError(EGL_BAD_MATCH, "unsupported dma_buf format modifier");
2501b8e80941Smrg         return EGL_NO_IMAGE_KHR;
2502b8e80941Smrg      }
2503b8e80941Smrg      dri_image =
2504b8e80941Smrg         dri2_dpy->image->createImageFromDmaBufs2(dri2_dpy->dri_screen,
2505b8e80941Smrg            attrs.Width, attrs.Height, attrs.DMABufFourCC.Value,
2506b8e80941Smrg            modifier, fds, num_fds, pitches, offsets,
2507b8e80941Smrg            attrs.DMABufYuvColorSpaceHint.Value,
2508b8e80941Smrg            attrs.DMABufSampleRangeHint.Value,
2509b8e80941Smrg            attrs.DMABufChromaHorizontalSiting.Value,
2510b8e80941Smrg            attrs.DMABufChromaVerticalSiting.Value,
2511b8e80941Smrg            &error,
2512b8e80941Smrg            NULL);
2513b8e80941Smrg   }
2514b8e80941Smrg   else {
2515b8e80941Smrg      dri_image =
2516b8e80941Smrg         dri2_dpy->image->createImageFromDmaBufs(dri2_dpy->dri_screen,
2517b8e80941Smrg            attrs.Width, attrs.Height, attrs.DMABufFourCC.Value,
2518b8e80941Smrg            fds, num_fds, pitches, offsets,
2519b8e80941Smrg            attrs.DMABufYuvColorSpaceHint.Value,
2520b8e80941Smrg            attrs.DMABufSampleRangeHint.Value,
2521b8e80941Smrg            attrs.DMABufChromaHorizontalSiting.Value,
2522b8e80941Smrg            attrs.DMABufChromaVerticalSiting.Value,
2523b8e80941Smrg            &error,
2524b8e80941Smrg            NULL);
2525b8e80941Smrg   }
2526848b8605Smrg   dri2_create_image_khr_texture_error(error);
2527848b8605Smrg
2528848b8605Smrg   if (!dri_image)
2529848b8605Smrg      return EGL_NO_IMAGE_KHR;
2530848b8605Smrg
2531848b8605Smrg   res = dri2_create_image_from_dri(disp, dri_image);
2532848b8605Smrg
2533848b8605Smrg   return res;
2534848b8605Smrg}
2535848b8605Smrgstatic _EGLImage *
2536848b8605Smrgdri2_create_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp,
2537b8e80941Smrg                           const EGLint *attr_list)
2538848b8605Smrg{
2539848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2540848b8605Smrg   struct dri2_egl_image *dri2_img;
2541848b8605Smrg   _EGLImageAttribs attrs;
2542848b8605Smrg   unsigned int dri_use, valid_mask;
2543848b8605Smrg   int format;
2544848b8605Smrg
2545848b8605Smrg   (void) drv;
2546848b8605Smrg
2547848b8605Smrg   if (!attr_list) {
2548b8e80941Smrg      _eglError(EGL_BAD_PARAMETER, __func__);
2549b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2550848b8605Smrg   }
2551848b8605Smrg
2552b8e80941Smrg   if (!_eglParseImageAttribList(&attrs, disp, attr_list))
2553b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2554848b8605Smrg
2555848b8605Smrg   if (attrs.Width <= 0 || attrs.Height <= 0) {
2556b8e80941Smrg      _eglError(EGL_BAD_PARAMETER, __func__);
2557b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2558848b8605Smrg   }
2559848b8605Smrg
2560848b8605Smrg   switch (attrs.DRMBufferFormatMESA) {
2561848b8605Smrg   case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA:
2562848b8605Smrg      format = __DRI_IMAGE_FORMAT_ARGB8888;
2563848b8605Smrg      break;
2564848b8605Smrg   default:
2565b8e80941Smrg      _eglError(EGL_BAD_PARAMETER, __func__);
2566b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2567848b8605Smrg   }
2568848b8605Smrg
2569848b8605Smrg   valid_mask =
2570848b8605Smrg      EGL_DRM_BUFFER_USE_SCANOUT_MESA |
2571848b8605Smrg      EGL_DRM_BUFFER_USE_SHARE_MESA |
2572848b8605Smrg      EGL_DRM_BUFFER_USE_CURSOR_MESA;
2573848b8605Smrg   if (attrs.DRMBufferUseMESA & ~valid_mask) {
2574b8e80941Smrg      _eglError(EGL_BAD_PARAMETER, __func__);
2575b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2576848b8605Smrg   }
2577848b8605Smrg
2578848b8605Smrg   dri_use = 0;
2579848b8605Smrg   if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SHARE_MESA)
2580848b8605Smrg      dri_use |= __DRI_IMAGE_USE_SHARE;
2581848b8605Smrg   if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_SCANOUT_MESA)
2582848b8605Smrg      dri_use |= __DRI_IMAGE_USE_SCANOUT;
2583848b8605Smrg   if (attrs.DRMBufferUseMESA & EGL_DRM_BUFFER_USE_CURSOR_MESA)
2584848b8605Smrg      dri_use |= __DRI_IMAGE_USE_CURSOR;
2585848b8605Smrg
2586b8e80941Smrg   dri2_img = malloc(sizeof *dri2_img);
2587b8e80941Smrg   if (!dri2_img) {
2588b8e80941Smrg      _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr");
2589b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2590b8e80941Smrg   }
2591b8e80941Smrg
2592b8e80941Smrg   _eglInitImage(&dri2_img->base, disp);
2593b8e80941Smrg
2594b8e80941Smrg   dri2_img->dri_image =
2595848b8605Smrg      dri2_dpy->image->createImage(dri2_dpy->dri_screen,
2596b8e80941Smrg                                   attrs.Width, attrs.Height,
2597848b8605Smrg                                   format, dri_use, dri2_img);
2598848b8605Smrg   if (dri2_img->dri_image == NULL) {
2599b8e80941Smrg      free(dri2_img);
2600b8e80941Smrg       _eglError(EGL_BAD_ALLOC, "dri2_create_drm_image_mesa");
2601b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2602848b8605Smrg   }
2603848b8605Smrg
2604848b8605Smrg   return &dri2_img->base;
2605848b8605Smrg}
2606848b8605Smrg
2607848b8605Smrgstatic EGLBoolean
2608848b8605Smrgdri2_export_drm_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
2609b8e80941Smrg                          EGLint *name, EGLint *handle, EGLint *stride)
2610848b8605Smrg{
2611848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2612848b8605Smrg   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
2613848b8605Smrg
2614848b8605Smrg   (void) drv;
2615848b8605Smrg
2616848b8605Smrg   if (name && !dri2_dpy->image->queryImage(dri2_img->dri_image,
2617b8e80941Smrg                                            __DRI_IMAGE_ATTRIB_NAME, name))
2618b8e80941Smrg      return _eglError(EGL_BAD_ALLOC, "dri2_export_drm_image_mesa");
2619848b8605Smrg
2620848b8605Smrg   if (handle)
2621848b8605Smrg      dri2_dpy->image->queryImage(dri2_img->dri_image,
2622b8e80941Smrg                                  __DRI_IMAGE_ATTRIB_HANDLE, handle);
2623848b8605Smrg
2624848b8605Smrg   if (stride)
2625848b8605Smrg      dri2_dpy->image->queryImage(dri2_img->dri_image,
2626b8e80941Smrg                                  __DRI_IMAGE_ATTRIB_STRIDE, stride);
2627848b8605Smrg
2628848b8605Smrg   return EGL_TRUE;
2629848b8605Smrg}
2630b8e80941Smrg
2631b8e80941Smrg/**
2632b8e80941Smrg * Checks if we can support EGL_MESA_image_dma_buf_export on this image.
2633b8e80941Smrg
2634b8e80941Smrg * The spec provides a boolean return for the driver to reject exporting for
2635b8e80941Smrg * basically any reason, but doesn't specify any particular error cases.  For
2636b8e80941Smrg * now, we just fail if we don't have a DRM fourcc for the format.
2637b8e80941Smrg */
2638b8e80941Smrgstatic bool
2639b8e80941Smrgdri2_can_export_dma_buf_image(_EGLDisplay *disp, _EGLImage *img)
2640b8e80941Smrg{
2641b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2642b8e80941Smrg   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
2643b8e80941Smrg   EGLint fourcc;
2644b8e80941Smrg
2645b8e80941Smrg   if (!dri2_dpy->image->queryImage(dri2_img->dri_image,
2646b8e80941Smrg                                    __DRI_IMAGE_ATTRIB_FOURCC, &fourcc)) {
2647b8e80941Smrg      return false;
2648b8e80941Smrg   }
2649b8e80941Smrg
2650b8e80941Smrg   return true;
2651b8e80941Smrg}
2652b8e80941Smrg
2653b8e80941Smrgstatic EGLBoolean
2654b8e80941Smrgdri2_export_dma_buf_image_query_mesa(_EGLDriver *drv, _EGLDisplay *disp,
2655b8e80941Smrg                                     _EGLImage *img,
2656b8e80941Smrg                                     EGLint *fourcc, EGLint *nplanes,
2657b8e80941Smrg                                     EGLuint64KHR *modifiers)
2658b8e80941Smrg{
2659b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2660b8e80941Smrg   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
2661b8e80941Smrg   int num_planes;
2662b8e80941Smrg
2663b8e80941Smrg   (void) drv;
2664b8e80941Smrg
2665b8e80941Smrg   if (!dri2_can_export_dma_buf_image(disp, img))
2666b8e80941Smrg      return EGL_FALSE;
2667b8e80941Smrg
2668b8e80941Smrg   dri2_dpy->image->queryImage(dri2_img->dri_image,
2669b8e80941Smrg                               __DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes);
2670b8e80941Smrg   if (nplanes)
2671b8e80941Smrg     *nplanes = num_planes;
2672b8e80941Smrg
2673b8e80941Smrg   if (fourcc)
2674b8e80941Smrg      dri2_dpy->image->queryImage(dri2_img->dri_image,
2675b8e80941Smrg                                  __DRI_IMAGE_ATTRIB_FOURCC, fourcc);
2676b8e80941Smrg
2677b8e80941Smrg   if (modifiers) {
2678b8e80941Smrg      int mod_hi, mod_lo;
2679b8e80941Smrg      uint64_t modifier = DRM_FORMAT_MOD_INVALID;
2680b8e80941Smrg      bool query;
2681b8e80941Smrg
2682b8e80941Smrg      query = dri2_dpy->image->queryImage(dri2_img->dri_image,
2683b8e80941Smrg                                          __DRI_IMAGE_ATTRIB_MODIFIER_UPPER,
2684b8e80941Smrg                                          &mod_hi);
2685b8e80941Smrg      query &= dri2_dpy->image->queryImage(dri2_img->dri_image,
2686b8e80941Smrg                                           __DRI_IMAGE_ATTRIB_MODIFIER_LOWER,
2687b8e80941Smrg                                           &mod_lo);
2688b8e80941Smrg      if (query)
2689b8e80941Smrg         modifier = combine_u32_into_u64 (mod_hi, mod_lo);
2690b8e80941Smrg
2691b8e80941Smrg      for (int i = 0; i < num_planes; i++)
2692b8e80941Smrg        modifiers[i] = modifier;
2693b8e80941Smrg   }
2694b8e80941Smrg
2695b8e80941Smrg   return EGL_TRUE;
2696b8e80941Smrg}
2697b8e80941Smrg
2698b8e80941Smrgstatic EGLBoolean
2699b8e80941Smrgdri2_export_dma_buf_image_mesa(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *img,
2700b8e80941Smrg                               int *fds, EGLint *strides, EGLint *offsets)
2701b8e80941Smrg{
2702b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2703b8e80941Smrg   struct dri2_egl_image *dri2_img = dri2_egl_image(img);
2704b8e80941Smrg   EGLint nplanes;
2705b8e80941Smrg
2706b8e80941Smrg   (void) drv;
2707b8e80941Smrg
2708b8e80941Smrg   if (!dri2_can_export_dma_buf_image(disp, img))
2709b8e80941Smrg      return EGL_FALSE;
2710b8e80941Smrg
2711b8e80941Smrg   /* EGL_MESA_image_dma_buf_export spec says:
2712b8e80941Smrg    *    "If the number of fds is less than the number of planes, then
2713b8e80941Smrg    *    subsequent fd slots should contain -1."
2714b8e80941Smrg    */
2715b8e80941Smrg   if (fds) {
2716b8e80941Smrg      /* Query nplanes so that we know how big the given array is. */
2717b8e80941Smrg      dri2_dpy->image->queryImage(dri2_img->dri_image,
2718b8e80941Smrg                                  __DRI_IMAGE_ATTRIB_NUM_PLANES, &nplanes);
2719b8e80941Smrg      memset(fds, -1, nplanes * sizeof(int));
2720b8e80941Smrg   }
2721b8e80941Smrg
2722b8e80941Smrg   /* rework later to provide multiple fds/strides/offsets */
2723b8e80941Smrg   if (fds)
2724b8e80941Smrg      dri2_dpy->image->queryImage(dri2_img->dri_image,
2725b8e80941Smrg                                  __DRI_IMAGE_ATTRIB_FD, fds);
2726b8e80941Smrg
2727b8e80941Smrg   if (strides)
2728b8e80941Smrg      dri2_dpy->image->queryImage(dri2_img->dri_image,
2729b8e80941Smrg                                  __DRI_IMAGE_ATTRIB_STRIDE, strides);
2730b8e80941Smrg
2731b8e80941Smrg   if (offsets) {
2732b8e80941Smrg      int img_offset;
2733b8e80941Smrg      bool ret = dri2_dpy->image->queryImage(dri2_img->dri_image,
2734b8e80941Smrg                     __DRI_IMAGE_ATTRIB_OFFSET, &img_offset);
2735b8e80941Smrg      if (ret)
2736b8e80941Smrg         offsets[0] = img_offset;
2737b8e80941Smrg      else
2738b8e80941Smrg         offsets[0] = 0;
2739b8e80941Smrg   }
2740b8e80941Smrg
2741b8e80941Smrg   return EGL_TRUE;
2742b8e80941Smrg}
2743b8e80941Smrg
2744848b8605Smrg#endif
2745848b8605Smrg
2746b8e80941Smrg_EGLImage *
2747b8e80941Smrgdri2_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
2748b8e80941Smrg                      _EGLContext *ctx, EGLenum target,
2749b8e80941Smrg                      EGLClientBuffer buffer, const EGLint *attr_list)
2750b8e80941Smrg{
2751b8e80941Smrg   (void) drv;
2752b8e80941Smrg
2753b8e80941Smrg   switch (target) {
2754b8e80941Smrg   case EGL_GL_TEXTURE_2D_KHR:
2755b8e80941Smrg   case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR:
2756b8e80941Smrg   case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR:
2757b8e80941Smrg   case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR:
2758b8e80941Smrg   case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR:
2759b8e80941Smrg   case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR:
2760b8e80941Smrg   case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR:
2761b8e80941Smrg   case EGL_GL_TEXTURE_3D_KHR:
2762b8e80941Smrg      return dri2_create_image_khr_texture(disp, ctx, target, buffer, attr_list);
2763b8e80941Smrg   case EGL_GL_RENDERBUFFER_KHR:
2764b8e80941Smrg      return dri2_create_image_khr_renderbuffer(disp, ctx, buffer, attr_list);
2765b8e80941Smrg#ifdef HAVE_LIBDRM
2766b8e80941Smrg   case EGL_DRM_BUFFER_MESA:
2767b8e80941Smrg      return dri2_create_image_mesa_drm_buffer(disp, ctx, buffer, attr_list);
2768b8e80941Smrg   case EGL_LINUX_DMA_BUF_EXT:
2769b8e80941Smrg      return dri2_create_image_dma_buf(disp, ctx, buffer, attr_list);
2770b8e80941Smrg#endif
2771b8e80941Smrg#ifdef HAVE_WAYLAND_PLATFORM
2772b8e80941Smrg   case EGL_WAYLAND_BUFFER_WL:
2773b8e80941Smrg      return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list);
2774b8e80941Smrg#endif
2775b8e80941Smrg   default:
2776b8e80941Smrg      _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr");
2777b8e80941Smrg      return EGL_NO_IMAGE_KHR;
2778b8e80941Smrg   }
2779b8e80941Smrg}
2780b8e80941Smrg
2781b8e80941Smrgstatic EGLBoolean
2782b8e80941Smrgdri2_destroy_image_khr(_EGLDriver *drv, _EGLDisplay *disp, _EGLImage *image)
2783b8e80941Smrg{
2784b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2785b8e80941Smrg   struct dri2_egl_image *dri2_img = dri2_egl_image(image);
2786b8e80941Smrg
2787b8e80941Smrg   (void) drv;
2788b8e80941Smrg
2789b8e80941Smrg   dri2_dpy->image->destroyImage(dri2_img->dri_image);
2790b8e80941Smrg   free(dri2_img);
2791b8e80941Smrg
2792b8e80941Smrg   return EGL_TRUE;
2793b8e80941Smrg}
2794b8e80941Smrg
2795848b8605Smrg#ifdef HAVE_WAYLAND_PLATFORM
2796848b8605Smrg
2797848b8605Smrgstatic void
2798848b8605Smrgdri2_wl_reference_buffer(void *user_data, uint32_t name, int fd,
2799848b8605Smrg                         struct wl_drm_buffer *buffer)
2800848b8605Smrg{
2801848b8605Smrg   _EGLDisplay *disp = user_data;
2802848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2803848b8605Smrg   __DRIimage *img;
2804b8e80941Smrg   int dri_components = 0;
2805848b8605Smrg
2806848b8605Smrg   if (fd == -1)
2807848b8605Smrg      img = dri2_dpy->image->createImageFromNames(dri2_dpy->dri_screen,
2808848b8605Smrg                                                  buffer->width,
2809848b8605Smrg                                                  buffer->height,
2810848b8605Smrg                                                  buffer->format,
2811848b8605Smrg                                                  (int*)&name, 1,
2812848b8605Smrg                                                  buffer->stride,
2813848b8605Smrg                                                  buffer->offset,
2814848b8605Smrg                                                  NULL);
2815848b8605Smrg   else
2816848b8605Smrg      img = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen,
2817848b8605Smrg                                                buffer->width,
2818848b8605Smrg                                                buffer->height,
2819848b8605Smrg                                                buffer->format,
2820848b8605Smrg                                                &fd, 1,
2821848b8605Smrg                                                buffer->stride,
2822848b8605Smrg                                                buffer->offset,
2823848b8605Smrg                                                NULL);
2824848b8605Smrg
2825848b8605Smrg   if (img == NULL)
2826848b8605Smrg      return;
2827848b8605Smrg
2828848b8605Smrg   dri2_dpy->image->queryImage(img, __DRI_IMAGE_ATTRIB_COMPONENTS, &dri_components);
2829848b8605Smrg
2830848b8605Smrg   buffer->driver_format = NULL;
2831b8e80941Smrg   for (int i = 0; i < ARRAY_SIZE(wl_drm_components); i++)
2832848b8605Smrg      if (wl_drm_components[i].dri_components == dri_components)
2833848b8605Smrg         buffer->driver_format = &wl_drm_components[i];
2834848b8605Smrg
2835848b8605Smrg   if (buffer->driver_format == NULL)
2836848b8605Smrg      dri2_dpy->image->destroyImage(img);
2837848b8605Smrg   else
2838848b8605Smrg      buffer->driver_buffer = img;
2839848b8605Smrg}
2840848b8605Smrg
2841848b8605Smrgstatic void
2842848b8605Smrgdri2_wl_release_buffer(void *user_data, struct wl_drm_buffer *buffer)
2843848b8605Smrg{
2844848b8605Smrg   _EGLDisplay *disp = user_data;
2845848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2846848b8605Smrg
2847848b8605Smrg   dri2_dpy->image->destroyImage(buffer->driver_buffer);
2848848b8605Smrg}
2849848b8605Smrg
2850848b8605Smrgstatic EGLBoolean
2851848b8605Smrgdri2_bind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
2852b8e80941Smrg                             struct wl_display *wl_dpy)
2853848b8605Smrg{
2854848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2855b8e80941Smrg   const struct wayland_drm_callbacks wl_drm_callbacks = {
2856b8e80941Smrg      .authenticate = (int(*)(void *, uint32_t)) dri2_dpy->vtbl->authenticate,
2857b8e80941Smrg      .reference_buffer = dri2_wl_reference_buffer,
2858b8e80941Smrg      .release_buffer = dri2_wl_release_buffer,
2859b8e80941Smrg      .is_format_supported = dri2_wl_is_format_supported
2860b8e80941Smrg   };
2861848b8605Smrg   int flags = 0;
2862848b8605Smrg   uint64_t cap;
2863848b8605Smrg
2864848b8605Smrg   (void) drv;
2865848b8605Smrg
2866848b8605Smrg   if (dri2_dpy->wl_server_drm)
2867b8e80941Smrg           return EGL_FALSE;
2868848b8605Smrg
2869848b8605Smrg   if (drmGetCap(dri2_dpy->fd, DRM_CAP_PRIME, &cap) == 0 &&
2870848b8605Smrg       cap == (DRM_PRIME_CAP_IMPORT | DRM_PRIME_CAP_EXPORT) &&
2871848b8605Smrg       dri2_dpy->image->base.version >= 7 &&
2872848b8605Smrg       dri2_dpy->image->createImageFromFds != NULL)
2873848b8605Smrg      flags |= WAYLAND_DRM_PRIME;
2874848b8605Smrg
2875848b8605Smrg   dri2_dpy->wl_server_drm =
2876b8e80941Smrg           wayland_drm_init(wl_dpy, dri2_dpy->device_name,
2877848b8605Smrg                            &wl_drm_callbacks, disp, flags);
2878848b8605Smrg
2879848b8605Smrg   if (!dri2_dpy->wl_server_drm)
2880b8e80941Smrg           return EGL_FALSE;
2881848b8605Smrg
2882848b8605Smrg#ifdef HAVE_DRM_PLATFORM
2883848b8605Smrg   /* We have to share the wl_drm instance with gbm, so gbm can convert
2884848b8605Smrg    * wl_buffers to gbm bos. */
2885848b8605Smrg   if (dri2_dpy->gbm_dri)
2886848b8605Smrg      dri2_dpy->gbm_dri->wl_drm = dri2_dpy->wl_server_drm;
2887848b8605Smrg#endif
2888848b8605Smrg
2889848b8605Smrg   return EGL_TRUE;
2890848b8605Smrg}
2891848b8605Smrg
2892848b8605Smrgstatic EGLBoolean
2893848b8605Smrgdri2_unbind_wayland_display_wl(_EGLDriver *drv, _EGLDisplay *disp,
2894b8e80941Smrg                               struct wl_display *wl_dpy)
2895848b8605Smrg{
2896848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2897848b8605Smrg
2898848b8605Smrg   (void) drv;
2899848b8605Smrg
2900848b8605Smrg   if (!dri2_dpy->wl_server_drm)
2901b8e80941Smrg           return EGL_FALSE;
2902848b8605Smrg
2903848b8605Smrg   wayland_drm_uninit(dri2_dpy->wl_server_drm);
2904848b8605Smrg   dri2_dpy->wl_server_drm = NULL;
2905848b8605Smrg
2906848b8605Smrg   return EGL_TRUE;
2907848b8605Smrg}
2908848b8605Smrg
2909848b8605Smrgstatic EGLBoolean
2910848b8605Smrgdri2_query_wayland_buffer_wl(_EGLDriver *drv, _EGLDisplay *disp,
2911848b8605Smrg                             struct wl_resource *buffer_resource,
2912848b8605Smrg                             EGLint attribute, EGLint *value)
2913848b8605Smrg{
2914848b8605Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2915848b8605Smrg   struct wl_drm_buffer *buffer;
2916848b8605Smrg   const struct wl_drm_components_descriptor *format;
2917848b8605Smrg
2918848b8605Smrg   buffer = wayland_drm_buffer_get(dri2_dpy->wl_server_drm, buffer_resource);
2919848b8605Smrg   if (!buffer)
2920848b8605Smrg      return EGL_FALSE;
2921848b8605Smrg
2922848b8605Smrg   format = buffer->driver_format;
2923848b8605Smrg   switch (attribute) {
2924848b8605Smrg   case EGL_TEXTURE_FORMAT:
2925848b8605Smrg      *value = format->components;
2926848b8605Smrg      return EGL_TRUE;
2927848b8605Smrg   case EGL_WIDTH:
2928848b8605Smrg      *value = buffer->width;
2929848b8605Smrg      return EGL_TRUE;
2930848b8605Smrg   case EGL_HEIGHT:
2931848b8605Smrg      *value = buffer->height;
2932848b8605Smrg      return EGL_TRUE;
2933848b8605Smrg   }
2934848b8605Smrg
2935848b8605Smrg   return EGL_FALSE;
2936848b8605Smrg}
2937848b8605Smrg#endif
2938848b8605Smrg
2939848b8605Smrgstatic void
2940b8e80941Smrgdri2_egl_ref_sync(struct dri2_egl_sync *sync)
2941848b8605Smrg{
2942b8e80941Smrg   p_atomic_inc(&sync->refcount);
2943b8e80941Smrg}
2944b8e80941Smrg
2945b8e80941Smrgstatic void
2946b8e80941Smrgdri2_egl_unref_sync(struct dri2_egl_display *dri2_dpy,
2947b8e80941Smrg                    struct dri2_egl_sync *dri2_sync)
2948b8e80941Smrg{
2949b8e80941Smrg   if (p_atomic_dec_zero(&dri2_sync->refcount)) {
2950b8e80941Smrg      switch (dri2_sync->base.Type) {
2951b8e80941Smrg      case EGL_SYNC_REUSABLE_KHR:
2952b8e80941Smrg         cnd_destroy(&dri2_sync->cond);
2953b8e80941Smrg         break;
2954b8e80941Smrg      case EGL_SYNC_NATIVE_FENCE_ANDROID:
2955b8e80941Smrg         if (dri2_sync->base.SyncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID)
2956b8e80941Smrg            close(dri2_sync->base.SyncFd);
2957b8e80941Smrg         break;
2958b8e80941Smrg      default:
2959b8e80941Smrg         break;
2960b8e80941Smrg      }
2961b8e80941Smrg
2962b8e80941Smrg      if (dri2_sync->fence)
2963b8e80941Smrg         dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence);
2964b8e80941Smrg
2965b8e80941Smrg      free(dri2_sync);
2966b8e80941Smrg   }
2967b8e80941Smrg}
2968b8e80941Smrg
2969b8e80941Smrgstatic _EGLSync *
2970b8e80941Smrgdri2_create_sync(_EGLDriver *drv, _EGLDisplay *disp,
2971b8e80941Smrg                 EGLenum type, const EGLAttrib *attrib_list)
2972b8e80941Smrg{
2973b8e80941Smrg   _EGLContext *ctx = _eglGetCurrentContext();
2974b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
2975b8e80941Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
2976b8e80941Smrg   struct dri2_egl_sync *dri2_sync;
2977b8e80941Smrg   EGLint ret;
2978b8e80941Smrg   pthread_condattr_t attr;
2979b8e80941Smrg
2980b8e80941Smrg   dri2_sync = calloc(1, sizeof(struct dri2_egl_sync));
2981b8e80941Smrg   if (!dri2_sync) {
2982b8e80941Smrg      _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
2983b8e80941Smrg      return NULL;
2984b8e80941Smrg   }
2985b8e80941Smrg
2986b8e80941Smrg   if (!_eglInitSync(&dri2_sync->base, disp, type, attrib_list)) {
2987b8e80941Smrg      free(dri2_sync);
2988b8e80941Smrg      return NULL;
2989b8e80941Smrg   }
2990b8e80941Smrg
2991b8e80941Smrg   switch (type) {
2992b8e80941Smrg   case EGL_SYNC_FENCE_KHR:
2993b8e80941Smrg      dri2_sync->fence = dri2_dpy->fence->create_fence(dri2_ctx->dri_context);
2994b8e80941Smrg      if (!dri2_sync->fence) {
2995b8e80941Smrg         /* Why did it fail? DRI doesn't return an error code, so we emit
2996b8e80941Smrg          * a generic EGL error that doesn't communicate user error.
2997b8e80941Smrg          */
2998b8e80941Smrg         _eglError(EGL_BAD_ALLOC, "eglCreateSyncKHR");
2999b8e80941Smrg         free(dri2_sync);
3000b8e80941Smrg         return NULL;
3001b8e80941Smrg      }
3002b8e80941Smrg      break;
3003b8e80941Smrg
3004b8e80941Smrg   case EGL_SYNC_CL_EVENT_KHR:
3005b8e80941Smrg      dri2_sync->fence = dri2_dpy->fence->get_fence_from_cl_event(
3006b8e80941Smrg                                 dri2_dpy->dri_screen,
3007b8e80941Smrg                                 dri2_sync->base.CLEvent);
3008b8e80941Smrg      /* this can only happen if the cl_event passed in is invalid. */
3009b8e80941Smrg      if (!dri2_sync->fence) {
3010b8e80941Smrg         _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
3011b8e80941Smrg         free(dri2_sync);
3012b8e80941Smrg         return NULL;
3013b8e80941Smrg      }
3014b8e80941Smrg
3015b8e80941Smrg      /* the initial status must be "signaled" if the cl_event is signaled */
3016b8e80941Smrg      if (dri2_dpy->fence->client_wait_sync(dri2_ctx->dri_context,
3017b8e80941Smrg                                            dri2_sync->fence, 0, 0))
3018b8e80941Smrg         dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
3019b8e80941Smrg      break;
3020b8e80941Smrg
3021b8e80941Smrg   case EGL_SYNC_REUSABLE_KHR:
3022b8e80941Smrg      /* intialize attr */
3023b8e80941Smrg      ret = pthread_condattr_init(&attr);
3024b8e80941Smrg
3025b8e80941Smrg      if (ret) {
3026b8e80941Smrg         _eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR");
3027b8e80941Smrg         free(dri2_sync);
3028b8e80941Smrg         return NULL;
3029b8e80941Smrg      }
3030b8e80941Smrg
3031b8e80941Smrg      /* change clock attribute to CLOCK_MONOTONIC */
3032b8e80941Smrg      ret = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
3033b8e80941Smrg
3034b8e80941Smrg      if (ret) {
3035b8e80941Smrg         _eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR");
3036b8e80941Smrg         free(dri2_sync);
3037b8e80941Smrg         return NULL;
3038b8e80941Smrg      }
3039b8e80941Smrg
3040b8e80941Smrg      ret = pthread_cond_init(&dri2_sync->cond, &attr);
3041b8e80941Smrg
3042b8e80941Smrg      if (ret) {
3043b8e80941Smrg         _eglError(EGL_BAD_ACCESS, "eglCreateSyncKHR");
3044b8e80941Smrg         free(dri2_sync);
3045b8e80941Smrg         return NULL;
3046b8e80941Smrg      }
3047b8e80941Smrg
3048b8e80941Smrg      /* initial status of reusable sync must be "unsignaled" */
3049b8e80941Smrg      dri2_sync->base.SyncStatus = EGL_UNSIGNALED_KHR;
3050b8e80941Smrg      break;
3051848b8605Smrg
3052b8e80941Smrg   case EGL_SYNC_NATIVE_FENCE_ANDROID:
3053b8e80941Smrg      if (dri2_dpy->fence->create_fence_fd) {
3054b8e80941Smrg         dri2_sync->fence = dri2_dpy->fence->create_fence_fd(
3055b8e80941Smrg                                    dri2_ctx->dri_context,
3056b8e80941Smrg                                    dri2_sync->base.SyncFd);
3057b8e80941Smrg      }
3058b8e80941Smrg      if (!dri2_sync->fence) {
3059b8e80941Smrg         _eglError(EGL_BAD_ATTRIBUTE, "eglCreateSyncKHR");
3060b8e80941Smrg         free(dri2_sync);
3061b8e80941Smrg         return NULL;
3062b8e80941Smrg      }
3063b8e80941Smrg      break;
3064b8e80941Smrg   }
3065b8e80941Smrg
3066b8e80941Smrg   p_atomic_set(&dri2_sync->refcount, 1);
3067b8e80941Smrg   return &dri2_sync->base;
3068848b8605Smrg}
3069848b8605Smrg
3070848b8605Smrgstatic EGLBoolean
3071b8e80941Smrgdri2_destroy_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync)
3072b8e80941Smrg{
3073b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
3074b8e80941Smrg   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
3075b8e80941Smrg   EGLint ret = EGL_TRUE;
3076b8e80941Smrg   EGLint err;
3077b8e80941Smrg
3078b8e80941Smrg   /* if type of sync is EGL_SYNC_REUSABLE_KHR and it is not signaled yet,
3079b8e80941Smrg    * then unlock all threads possibly blocked by the reusable sync before
3080b8e80941Smrg    * destroying it.
3081848b8605Smrg    */
3082b8e80941Smrg   if (dri2_sync->base.Type == EGL_SYNC_REUSABLE_KHR &&
3083b8e80941Smrg       dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR) {
3084b8e80941Smrg      dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
3085b8e80941Smrg      /* unblock all threads currently blocked by sync */
3086b8e80941Smrg      err = cnd_broadcast(&dri2_sync->cond);
3087b8e80941Smrg
3088b8e80941Smrg      if (err) {
3089b8e80941Smrg         _eglError(EGL_BAD_ACCESS, "eglDestroySyncKHR");
3090b8e80941Smrg         ret = EGL_FALSE;
3091848b8605Smrg      }
3092848b8605Smrg   }
3093848b8605Smrg
3094b8e80941Smrg   dri2_egl_unref_sync(dri2_dpy, dri2_sync);
3095b8e80941Smrg
3096b8e80941Smrg   return ret;
3097b8e80941Smrg}
3098b8e80941Smrg
3099b8e80941Smrgstatic EGLint
3100b8e80941Smrgdri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync)
3101b8e80941Smrg{
3102b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
3103b8e80941Smrg   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
3104b8e80941Smrg
3105b8e80941Smrg   assert(sync->Type == EGL_SYNC_NATIVE_FENCE_ANDROID);
3106b8e80941Smrg
3107b8e80941Smrg   if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
3108b8e80941Smrg      /* try to retrieve the actual native fence fd.. if rendering is
3109b8e80941Smrg       * not flushed this will just return -1, aka NO_NATIVE_FENCE_FD:
3110b8e80941Smrg       */
3111b8e80941Smrg      sync->SyncFd = dri2_dpy->fence->get_fence_fd(dri2_dpy->dri_screen,
3112b8e80941Smrg                                                   dri2_sync->fence);
3113848b8605Smrg   }
3114848b8605Smrg
3115b8e80941Smrg   if (sync->SyncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
3116b8e80941Smrg      /* if native fence fd still not created, return an error: */
3117b8e80941Smrg      _eglError(EGL_BAD_PARAMETER, "eglDupNativeFenceFDANDROID");
3118b8e80941Smrg      return EGL_NO_NATIVE_FENCE_FD_ANDROID;
3119b8e80941Smrg   }
3120848b8605Smrg
3121b8e80941Smrg   return dup(sync->SyncFd);
3122b8e80941Smrg}
3123848b8605Smrg
3124b8e80941Smrgstatic void
3125b8e80941Smrgdri2_set_blob_cache_funcs(_EGLDriver *drv, _EGLDisplay *disp,
3126b8e80941Smrg                          EGLSetBlobFuncANDROID set,
3127b8e80941Smrg                          EGLGetBlobFuncANDROID get)
3128b8e80941Smrg{
3129b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
3130b8e80941Smrg   dri2_dpy->blob->set_cache_funcs(dri2_dpy->dri_screen,
3131b8e80941Smrg                                   disp->BlobCacheSet,
3132b8e80941Smrg                                   disp->BlobCacheGet);
3133848b8605Smrg}
3134848b8605Smrg
3135b8e80941Smrgstatic EGLint
3136b8e80941Smrgdri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync,
3137b8e80941Smrg                      EGLint flags, EGLTime timeout)
3138848b8605Smrg{
3139b8e80941Smrg   _EGLContext *ctx = _eglGetCurrentContext();
3140b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
3141b8e80941Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
3142b8e80941Smrg   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
3143b8e80941Smrg   unsigned wait_flags = 0;
3144848b8605Smrg
3145b8e80941Smrg   EGLint ret = EGL_CONDITION_SATISFIED_KHR;
3146848b8605Smrg
3147b8e80941Smrg   /* The EGL_KHR_fence_sync spec states:
3148b8e80941Smrg    *
3149b8e80941Smrg    *    "If no context is current for the bound API,
3150b8e80941Smrg    *     the EGL_SYNC_FLUSH_COMMANDS_BIT_KHR bit is ignored.
3151b8e80941Smrg    */
3152b8e80941Smrg   if (dri2_ctx && flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)
3153b8e80941Smrg      wait_flags |= __DRI2_FENCE_FLAG_FLUSH_COMMANDS;
3154b8e80941Smrg
3155b8e80941Smrg   /* the sync object should take a reference while waiting */
3156b8e80941Smrg   dri2_egl_ref_sync(dri2_sync);
3157b8e80941Smrg
3158b8e80941Smrg   switch (sync->Type) {
3159b8e80941Smrg   case EGL_SYNC_FENCE_KHR:
3160b8e80941Smrg   case EGL_SYNC_NATIVE_FENCE_ANDROID:
3161b8e80941Smrg   case EGL_SYNC_CL_EVENT_KHR:
3162b8e80941Smrg      if (dri2_dpy->fence->client_wait_sync(dri2_ctx ? dri2_ctx->dri_context : NULL,
3163b8e80941Smrg                                         dri2_sync->fence, wait_flags,
3164b8e80941Smrg                                         timeout))
3165b8e80941Smrg         dri2_sync->base.SyncStatus = EGL_SIGNALED_KHR;
3166b8e80941Smrg      else
3167b8e80941Smrg         ret = EGL_TIMEOUT_EXPIRED_KHR;
3168b8e80941Smrg      break;
3169848b8605Smrg
3170b8e80941Smrg   case EGL_SYNC_REUSABLE_KHR:
3171b8e80941Smrg      if (dri2_ctx && dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR &&
3172b8e80941Smrg          (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)) {
3173b8e80941Smrg         /* flush context if EGL_SYNC_FLUSH_COMMANDS_BIT_KHR is set */
3174b8e80941Smrg         dri2_gl_flush();
3175b8e80941Smrg      }
3176b8e80941Smrg
3177b8e80941Smrg      /* if timeout is EGL_FOREVER_KHR, it should wait without any timeout.*/
3178b8e80941Smrg      if (timeout == EGL_FOREVER_KHR) {
3179b8e80941Smrg         mtx_lock(&dri2_sync->mutex);
3180b8e80941Smrg         cnd_wait(&dri2_sync->cond, &dri2_sync->mutex);
3181b8e80941Smrg         mtx_unlock(&dri2_sync->mutex);
3182b8e80941Smrg      } else {
3183b8e80941Smrg         /* if reusable sync has not been yet signaled */
3184b8e80941Smrg         if (dri2_sync->base.SyncStatus != EGL_SIGNALED_KHR) {
3185b8e80941Smrg            /* timespecs for cnd_timedwait */
3186b8e80941Smrg            struct timespec current;
3187b8e80941Smrg            struct timespec expire;
3188b8e80941Smrg
3189b8e80941Smrg            /* We override the clock to monotonic when creating the condition
3190b8e80941Smrg             * variable. */
3191b8e80941Smrg            clock_gettime(CLOCK_MONOTONIC, &current);
3192b8e80941Smrg
3193b8e80941Smrg            /* calculating when to expire */
3194b8e80941Smrg            expire.tv_nsec = timeout % 1000000000L;
3195b8e80941Smrg            expire.tv_sec = timeout / 1000000000L;
3196b8e80941Smrg
3197b8e80941Smrg            expire.tv_nsec += current.tv_nsec;
3198b8e80941Smrg            expire.tv_sec += current.tv_sec;
3199b8e80941Smrg
3200b8e80941Smrg            /* expire.nsec now is a number between 0 and 1999999998 */
3201b8e80941Smrg            if (expire.tv_nsec > 999999999L) {
3202b8e80941Smrg               expire.tv_sec++;
3203b8e80941Smrg               expire.tv_nsec -= 1000000000L;
3204b8e80941Smrg            }
3205b8e80941Smrg
3206b8e80941Smrg            mtx_lock(&dri2_sync->mutex);
3207b8e80941Smrg            ret = cnd_timedwait(&dri2_sync->cond, &dri2_sync->mutex, &expire);
3208b8e80941Smrg            mtx_unlock(&dri2_sync->mutex);
3209b8e80941Smrg
3210b8e80941Smrg            if (ret == thrd_busy) {
3211b8e80941Smrg               if (dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR) {
3212b8e80941Smrg                  ret = EGL_TIMEOUT_EXPIRED_KHR;
3213b8e80941Smrg               } else {
3214b8e80941Smrg                  _eglError(EGL_BAD_ACCESS, "eglClientWaitSyncKHR");
3215b8e80941Smrg                  ret = EGL_FALSE;
3216b8e80941Smrg               }
3217b8e80941Smrg            }
3218b8e80941Smrg         }
3219b8e80941Smrg      }
3220b8e80941Smrg      break;
3221b8e80941Smrg  }
3222b8e80941Smrg  dri2_egl_unref_sync(dri2_dpy, dri2_sync);
3223b8e80941Smrg
3224b8e80941Smrg  return ret;
3225b8e80941Smrg}
3226b8e80941Smrg
3227b8e80941Smrgstatic EGLBoolean
3228b8e80941Smrgdri2_signal_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync,
3229b8e80941Smrg                      EGLenum mode)
3230b8e80941Smrg{
3231b8e80941Smrg   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
3232b8e80941Smrg   EGLint ret;
3233b8e80941Smrg
3234b8e80941Smrg   if (sync->Type != EGL_SYNC_REUSABLE_KHR)
3235b8e80941Smrg      return _eglError(EGL_BAD_MATCH, "eglSignalSyncKHR");
3236b8e80941Smrg
3237b8e80941Smrg   if (mode != EGL_SIGNALED_KHR && mode != EGL_UNSIGNALED_KHR)
3238b8e80941Smrg      return _eglError(EGL_BAD_ATTRIBUTE, "eglSignalSyncKHR");
3239b8e80941Smrg
3240b8e80941Smrg   dri2_sync->base.SyncStatus = mode;
3241b8e80941Smrg
3242b8e80941Smrg   if (mode == EGL_SIGNALED_KHR) {
3243b8e80941Smrg      ret = cnd_broadcast(&dri2_sync->cond);
3244b8e80941Smrg
3245b8e80941Smrg      /* fail to broadcast */
3246b8e80941Smrg      if (ret)
3247b8e80941Smrg         return _eglError(EGL_BAD_ACCESS, "eglSignalSyncKHR");
3248848b8605Smrg   }
3249848b8605Smrg
3250b8e80941Smrg   return EGL_TRUE;
3251b8e80941Smrg}
3252b8e80941Smrg
3253b8e80941Smrgstatic EGLint
3254b8e80941Smrgdri2_server_wait_sync(_EGLDriver *drv, _EGLDisplay *disp, _EGLSync *sync)
3255b8e80941Smrg{
3256b8e80941Smrg   _EGLContext *ctx = _eglGetCurrentContext();
3257b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
3258b8e80941Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
3259b8e80941Smrg   struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
3260b8e80941Smrg
3261b8e80941Smrg   dri2_dpy->fence->server_wait_sync(dri2_ctx->dri_context,
3262b8e80941Smrg                                     dri2_sync->fence, 0);
3263b8e80941Smrg   return EGL_TRUE;
3264b8e80941Smrg}
3265b8e80941Smrg
3266b8e80941Smrgstatic int
3267b8e80941Smrgdri2_interop_query_device_info(_EGLDisplay *disp, _EGLContext *ctx,
3268b8e80941Smrg                               struct mesa_glinterop_device_info *out)
3269b8e80941Smrg{
3270b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
3271b8e80941Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
3272b8e80941Smrg
3273b8e80941Smrg   if (!dri2_dpy->interop)
3274b8e80941Smrg      return MESA_GLINTEROP_UNSUPPORTED;
3275b8e80941Smrg
3276b8e80941Smrg   return dri2_dpy->interop->query_device_info(dri2_ctx->dri_context, out);
3277b8e80941Smrg}
3278b8e80941Smrg
3279b8e80941Smrgstatic int
3280b8e80941Smrgdri2_interop_export_object(_EGLDisplay *disp, _EGLContext *ctx,
3281b8e80941Smrg                           struct mesa_glinterop_export_in *in,
3282b8e80941Smrg                           struct mesa_glinterop_export_out *out)
3283b8e80941Smrg{
3284b8e80941Smrg   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
3285b8e80941Smrg   struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
3286b8e80941Smrg
3287b8e80941Smrg   if (!dri2_dpy->interop)
3288b8e80941Smrg      return MESA_GLINTEROP_UNSUPPORTED;
3289b8e80941Smrg
3290b8e80941Smrg   return dri2_dpy->interop->export_object(dri2_ctx->dri_context, in, out);
3291b8e80941Smrg}
3292b8e80941Smrg
3293b8e80941Smrg/**
3294b8e80941Smrg * This is the main entrypoint into the driver, called by libEGL.
3295b8e80941Smrg * Gets an _EGLDriver object and init its dispatch table.
3296b8e80941Smrg */
3297b8e80941Smrgvoid
3298b8e80941Smrg_eglInitDriver(_EGLDriver *dri2_drv)
3299b8e80941Smrg{
3300b8e80941Smrg   dri2_drv->API.Initialize = dri2_initialize;
3301b8e80941Smrg   dri2_drv->API.Terminate = dri2_terminate;
3302b8e80941Smrg   dri2_drv->API.CreateContext = dri2_create_context;
3303b8e80941Smrg   dri2_drv->API.DestroyContext = dri2_destroy_context;
3304b8e80941Smrg   dri2_drv->API.MakeCurrent = dri2_make_current;
3305b8e80941Smrg   dri2_drv->API.CreateWindowSurface = dri2_create_window_surface;
3306b8e80941Smrg   dri2_drv->API.CreatePixmapSurface = dri2_create_pixmap_surface;
3307b8e80941Smrg   dri2_drv->API.CreatePbufferSurface = dri2_create_pbuffer_surface;
3308b8e80941Smrg   dri2_drv->API.DestroySurface = dri2_destroy_surface;
3309b8e80941Smrg   dri2_drv->API.GetProcAddress = dri2_get_proc_address;
3310b8e80941Smrg   dri2_drv->API.WaitClient = dri2_wait_client;
3311b8e80941Smrg   dri2_drv->API.WaitNative = dri2_wait_native;
3312b8e80941Smrg   dri2_drv->API.BindTexImage = dri2_bind_tex_image;
3313b8e80941Smrg   dri2_drv->API.ReleaseTexImage = dri2_release_tex_image;
3314b8e80941Smrg   dri2_drv->API.SwapInterval = dri2_swap_interval;
3315b8e80941Smrg   dri2_drv->API.SwapBuffers = dri2_swap_buffers;
3316b8e80941Smrg   dri2_drv->API.SwapBuffersWithDamageEXT = dri2_swap_buffers_with_damage;
3317b8e80941Smrg   dri2_drv->API.SwapBuffersRegionNOK = dri2_swap_buffers_region;
3318b8e80941Smrg   dri2_drv->API.SetDamageRegion = dri2_set_damage_region;
3319b8e80941Smrg   dri2_drv->API.PostSubBufferNV = dri2_post_sub_buffer;
3320b8e80941Smrg   dri2_drv->API.CopyBuffers = dri2_copy_buffers,
3321b8e80941Smrg   dri2_drv->API.QueryBufferAge = dri2_query_buffer_age;
3322b8e80941Smrg   dri2_drv->API.CreateImageKHR = dri2_create_image;
3323b8e80941Smrg   dri2_drv->API.DestroyImageKHR = dri2_destroy_image_khr;
3324b8e80941Smrg   dri2_drv->API.CreateWaylandBufferFromImageWL = dri2_create_wayland_buffer_from_image;
3325b8e80941Smrg   dri2_drv->API.QuerySurface = dri2_query_surface;
3326b8e80941Smrg   dri2_drv->API.QueryDriverName = dri2_query_driver_name;
3327b8e80941Smrg   dri2_drv->API.QueryDriverConfig = dri2_query_driver_config;
3328b8e80941Smrg#ifdef HAVE_LIBDRM
3329b8e80941Smrg   dri2_drv->API.CreateDRMImageMESA = dri2_create_drm_image_mesa;
3330b8e80941Smrg   dri2_drv->API.ExportDRMImageMESA = dri2_export_drm_image_mesa;
3331b8e80941Smrg   dri2_drv->API.ExportDMABUFImageQueryMESA = dri2_export_dma_buf_image_query_mesa;
3332b8e80941Smrg   dri2_drv->API.ExportDMABUFImageMESA = dri2_export_dma_buf_image_mesa;
3333b8e80941Smrg   dri2_drv->API.QueryDmaBufFormatsEXT = dri2_query_dma_buf_formats;
3334b8e80941Smrg   dri2_drv->API.QueryDmaBufModifiersEXT = dri2_query_dma_buf_modifiers;
3335848b8605Smrg#endif
3336848b8605Smrg#ifdef HAVE_WAYLAND_PLATFORM
3337b8e80941Smrg   dri2_drv->API.BindWaylandDisplayWL = dri2_bind_wayland_display_wl;
3338b8e80941Smrg   dri2_drv->API.UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl;
3339b8e80941Smrg   dri2_drv->API.QueryWaylandBufferWL = dri2_query_wayland_buffer_wl;
3340848b8605Smrg#endif
3341b8e80941Smrg   dri2_drv->API.GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium;
3342b8e80941Smrg   dri2_drv->API.CreateSyncKHR = dri2_create_sync;
3343b8e80941Smrg   dri2_drv->API.ClientWaitSyncKHR = dri2_client_wait_sync;
3344b8e80941Smrg   dri2_drv->API.SignalSyncKHR = dri2_signal_sync;
3345b8e80941Smrg   dri2_drv->API.WaitSyncKHR = dri2_server_wait_sync;
3346b8e80941Smrg   dri2_drv->API.DestroySyncKHR = dri2_destroy_sync;
3347b8e80941Smrg   dri2_drv->API.GLInteropQueryDeviceInfo = dri2_interop_query_device_info;
3348b8e80941Smrg   dri2_drv->API.GLInteropExportObject = dri2_interop_export_object;
3349b8e80941Smrg   dri2_drv->API.DupNativeFenceFDANDROID = dri2_dup_native_fence_fd;
3350b8e80941Smrg   dri2_drv->API.SetBlobCacheFuncsANDROID = dri2_set_blob_cache_funcs;
3351848b8605Smrg}
3352