1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
3bf215546Sopenharmony_ci * Copyright © 2008 Red Hat, Inc.
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
6bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Soft-
7bf215546Sopenharmony_ci * ware"), to deal in the Software without restriction, including without
8bf215546Sopenharmony_ci * limitation the rights to use, copy, modify, merge, publish, distribute,
9bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
10bf215546Sopenharmony_ci * Software is furnished to do so, provided that the above copyright
11bf215546Sopenharmony_ci * notice(s) and this permission notice appear in all copies of the Soft-
12bf215546Sopenharmony_ci * ware and that both the above copyright notice(s) and this permission
13bf215546Sopenharmony_ci * notice appear in supporting documentation.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
17bf215546Sopenharmony_ci * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
18bf215546Sopenharmony_ci * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
19bf215546Sopenharmony_ci * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
20bf215546Sopenharmony_ci * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21bf215546Sopenharmony_ci * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22bf215546Sopenharmony_ci * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
23bf215546Sopenharmony_ci * MANCE OF THIS SOFTWARE.
24bf215546Sopenharmony_ci *
25bf215546Sopenharmony_ci * Except as contained in this notice, the name of a copyright holder shall
26bf215546Sopenharmony_ci * not be used in advertising or otherwise to promote the sale, use or
27bf215546Sopenharmony_ci * other dealings in this Software without prior written authorization of
28bf215546Sopenharmony_ci * the copyright holder.
29bf215546Sopenharmony_ci *
30bf215546Sopenharmony_ci * Authors:
31bf215546Sopenharmony_ci *   Kevin E. Martin <kevin@precisioninsight.com>
32bf215546Sopenharmony_ci *   Brian Paul <brian@precisioninsight.com>
33bf215546Sopenharmony_ci *   Kristian Høgsberg (krh@redhat.com)
34bf215546Sopenharmony_ci */
35bf215546Sopenharmony_ci
36bf215546Sopenharmony_ci#if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
37bf215546Sopenharmony_ci
38bf215546Sopenharmony_ci#include <unistd.h>
39bf215546Sopenharmony_ci#include <dlfcn.h>
40bf215546Sopenharmony_ci#include <stdarg.h>
41bf215546Sopenharmony_ci#include "glxclient.h"
42bf215546Sopenharmony_ci#include "dri_common.h"
43bf215546Sopenharmony_ci#include "loader.h"
44bf215546Sopenharmony_ci#include <X11/Xlib-xcb.h>
45bf215546Sopenharmony_ci#include <xcb/xproto.h>
46bf215546Sopenharmony_ci
47bf215546Sopenharmony_ci#ifndef RTLD_NOW
48bf215546Sopenharmony_ci#define RTLD_NOW 0
49bf215546Sopenharmony_ci#endif
50bf215546Sopenharmony_ci#ifndef RTLD_GLOBAL
51bf215546Sopenharmony_ci#define RTLD_GLOBAL 0
52bf215546Sopenharmony_ci#endif
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci#ifndef GL_LIB_NAME
55bf215546Sopenharmony_ci#define GL_LIB_NAME "libGL.so.1"
56bf215546Sopenharmony_ci#endif
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci/**
59bf215546Sopenharmony_ci * Try to \c dlopen the named driver.
60bf215546Sopenharmony_ci *
61bf215546Sopenharmony_ci * This function adds the "_dri.so" suffix to the driver name and searches the
62bf215546Sopenharmony_ci * directories specified by the \c LIBGL_DRIVERS_PATH environment variable in
63bf215546Sopenharmony_ci * order to find the driver.
64bf215546Sopenharmony_ci *
65bf215546Sopenharmony_ci * \param driverName - a name like "i965", "radeon", "nouveau", etc.
66bf215546Sopenharmony_ci * \param out_driver_handle - Address to return the resulting dlopen() handle.
67bf215546Sopenharmony_ci *
68bf215546Sopenharmony_ci * \returns
69bf215546Sopenharmony_ci * The __DRIextension entrypoint table for the driver, or \c NULL if driver
70bf215546Sopenharmony_ci * file not found.
71bf215546Sopenharmony_ci */
72bf215546Sopenharmony_ci_X_HIDDEN const __DRIextension **
73bf215546Sopenharmony_cidriOpenDriver(const char *driverName, void **out_driver_handle)
74bf215546Sopenharmony_ci{
75bf215546Sopenharmony_ci   void *glhandle;
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci   /* Attempt to make sure libGL symbols will be visible to the driver */
78bf215546Sopenharmony_ci   glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL);
79bf215546Sopenharmony_ci
80bf215546Sopenharmony_ci   static const char *search_path_vars[] = {
81bf215546Sopenharmony_ci      "LIBGL_DRIVERS_PATH",
82bf215546Sopenharmony_ci      "LIBGL_DRIVERS_DIR", /* deprecated */
83bf215546Sopenharmony_ci      NULL
84bf215546Sopenharmony_ci   };
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci   const __DRIextension **extensions =
87bf215546Sopenharmony_ci      loader_open_driver(driverName, out_driver_handle, search_path_vars);
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci   if (glhandle)
90bf215546Sopenharmony_ci      dlclose(glhandle);
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_ci   return extensions;
93bf215546Sopenharmony_ci}
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci#define __ATTRIB(attrib, field) \
96bf215546Sopenharmony_ci    { attrib, offsetof(struct glx_config, field) }
97bf215546Sopenharmony_ci
98bf215546Sopenharmony_cistatic const struct
99bf215546Sopenharmony_ci{
100bf215546Sopenharmony_ci   unsigned int attrib, offset;
101bf215546Sopenharmony_ci} attribMap[] = {
102bf215546Sopenharmony_ci   __ATTRIB(__DRI_ATTRIB_BUFFER_SIZE, rgbBits),
103bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_LEVEL, level),
104bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_RED_SIZE, redBits),
105bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_GREEN_SIZE, greenBits),
106bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_BLUE_SIZE, blueBits),
107bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_ALPHA_SIZE, alphaBits),
108bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_DEPTH_SIZE, depthBits),
109bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_STENCIL_SIZE, stencilBits),
110bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_ACCUM_RED_SIZE, accumRedBits),
111bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_ACCUM_GREEN_SIZE, accumGreenBits),
112bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_ACCUM_BLUE_SIZE, accumBlueBits),
113bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_ACCUM_ALPHA_SIZE, accumAlphaBits),
114bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_SAMPLE_BUFFERS, sampleBuffers),
115bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_SAMPLES, samples),
116bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_DOUBLE_BUFFER, doubleBufferMode),
117bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_STEREO, stereoMode),
118bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_AUX_BUFFERS, numAuxBuffers),
119bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_SWAP_METHOD, swapMethod),
120bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGB, bindToTextureRgb),
121bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_BIND_TO_TEXTURE_RGBA, bindToTextureRgba),
122bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE, bindToMipmapTexture),
123bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_YINVERTED, yInverted),
124bf215546Sopenharmony_ci      __ATTRIB(__DRI_ATTRIB_FRAMEBUFFER_SRGB_CAPABLE, sRGBCapable)
125bf215546Sopenharmony_ci};
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_cistatic int
128bf215546Sopenharmony_ciscalarEqual(struct glx_config *mode, unsigned int attrib, unsigned int value)
129bf215546Sopenharmony_ci{
130bf215546Sopenharmony_ci   unsigned glxValue, i;
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   for (i = 0; i < ARRAY_SIZE(attribMap); i++)
133bf215546Sopenharmony_ci      if (attribMap[i].attrib == attrib) {
134bf215546Sopenharmony_ci         glxValue = *(unsigned int *) ((char *) mode + attribMap[i].offset);
135bf215546Sopenharmony_ci         return glxValue == GLX_DONT_CARE || glxValue == value;
136bf215546Sopenharmony_ci      }
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   return GL_TRUE;              /* Is a non-existing attribute equal to value? */
139bf215546Sopenharmony_ci}
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_cistatic int
142bf215546Sopenharmony_cidriConfigEqual(const __DRIcoreExtension *core,
143bf215546Sopenharmony_ci               struct glx_config *config, const __DRIconfig *driConfig)
144bf215546Sopenharmony_ci{
145bf215546Sopenharmony_ci   unsigned int attrib, value, glxValue;
146bf215546Sopenharmony_ci   int i;
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci   i = 0;
149bf215546Sopenharmony_ci   while (core->indexConfigAttrib(driConfig, i++, &attrib, &value)) {
150bf215546Sopenharmony_ci      switch (attrib) {
151bf215546Sopenharmony_ci      case __DRI_ATTRIB_RENDER_TYPE:
152bf215546Sopenharmony_ci         glxValue = 0;
153bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_RGBA_BIT) {
154bf215546Sopenharmony_ci            glxValue |= GLX_RGBA_BIT;
155bf215546Sopenharmony_ci         }
156bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_COLOR_INDEX_BIT) {
157bf215546Sopenharmony_ci            glxValue |= GLX_COLOR_INDEX_BIT;
158bf215546Sopenharmony_ci         }
159bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_FLOAT_BIT) {
160bf215546Sopenharmony_ci            glxValue |= GLX_RGBA_FLOAT_BIT_ARB;
161bf215546Sopenharmony_ci         }
162bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_UNSIGNED_FLOAT_BIT) {
163bf215546Sopenharmony_ci            glxValue |= GLX_RGBA_UNSIGNED_FLOAT_BIT_EXT;
164bf215546Sopenharmony_ci         }
165bf215546Sopenharmony_ci         if (glxValue != config->renderType)
166bf215546Sopenharmony_ci            return GL_FALSE;
167bf215546Sopenharmony_ci         break;
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci      case __DRI_ATTRIB_BIND_TO_TEXTURE_TARGETS:
170bf215546Sopenharmony_ci         glxValue = 0;
171bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_TEXTURE_1D_BIT)
172bf215546Sopenharmony_ci            glxValue |= GLX_TEXTURE_1D_BIT_EXT;
173bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_TEXTURE_2D_BIT)
174bf215546Sopenharmony_ci            glxValue |= GLX_TEXTURE_2D_BIT_EXT;
175bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_TEXTURE_RECTANGLE_BIT)
176bf215546Sopenharmony_ci            glxValue |= GLX_TEXTURE_RECTANGLE_BIT_EXT;
177bf215546Sopenharmony_ci         if (config->bindToTextureTargets != GLX_DONT_CARE &&
178bf215546Sopenharmony_ci             glxValue != config->bindToTextureTargets)
179bf215546Sopenharmony_ci            return GL_FALSE;
180bf215546Sopenharmony_ci         break;
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci      case __DRI_ATTRIB_SWAP_METHOD:
183bf215546Sopenharmony_ci         if (value == __DRI_ATTRIB_SWAP_EXCHANGE)
184bf215546Sopenharmony_ci            glxValue = GLX_SWAP_EXCHANGE_OML;
185bf215546Sopenharmony_ci         else if (value == __DRI_ATTRIB_SWAP_COPY)
186bf215546Sopenharmony_ci            glxValue = GLX_SWAP_COPY_OML;
187bf215546Sopenharmony_ci         else
188bf215546Sopenharmony_ci            glxValue = GLX_SWAP_UNDEFINED_OML;
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci         if (!scalarEqual(config, attrib, glxValue))
191bf215546Sopenharmony_ci            return GL_FALSE;
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci         break;
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci      /* Nerf some attributes we can safely ignore if the server claims to
196bf215546Sopenharmony_ci       * support them but the driver does not.
197bf215546Sopenharmony_ci       */
198bf215546Sopenharmony_ci      case __DRI_ATTRIB_CONFIG_CAVEAT:
199bf215546Sopenharmony_ci         if (value & __DRI_ATTRIB_NON_CONFORMANT_CONFIG)
200bf215546Sopenharmony_ci            glxValue = GLX_NON_CONFORMANT_CONFIG;
201bf215546Sopenharmony_ci         else if (value & __DRI_ATTRIB_SLOW_BIT)
202bf215546Sopenharmony_ci            glxValue = GLX_SLOW_CONFIG;
203bf215546Sopenharmony_ci         else
204bf215546Sopenharmony_ci            glxValue = GLX_NONE;
205bf215546Sopenharmony_ci         if (glxValue != config->visualRating) {
206bf215546Sopenharmony_ci            if (config->visualRating == GLX_NONE) {
207bf215546Sopenharmony_ci               static int warned;
208bf215546Sopenharmony_ci               if (!warned) {
209bf215546Sopenharmony_ci                  DebugMessageF("Not downgrading visual rating\n");
210bf215546Sopenharmony_ci                  warned = 1;
211bf215546Sopenharmony_ci               }
212bf215546Sopenharmony_ci            } else {
213bf215546Sopenharmony_ci               return GL_FALSE;
214bf215546Sopenharmony_ci            }
215bf215546Sopenharmony_ci         }
216bf215546Sopenharmony_ci         break;
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci      case __DRI_ATTRIB_AUX_BUFFERS:
219bf215546Sopenharmony_ci         if (!scalarEqual(config, attrib, value)) {
220bf215546Sopenharmony_ci            static int warned;
221bf215546Sopenharmony_ci            if (!warned) {
222bf215546Sopenharmony_ci               DebugMessageF("Disabling server's aux buffer support\n");
223bf215546Sopenharmony_ci               warned = 1;
224bf215546Sopenharmony_ci            }
225bf215546Sopenharmony_ci            config->numAuxBuffers = 0;
226bf215546Sopenharmony_ci         }
227bf215546Sopenharmony_ci         break;
228bf215546Sopenharmony_ci
229bf215546Sopenharmony_ci      case __DRI_ATTRIB_BIND_TO_MIPMAP_TEXTURE:
230bf215546Sopenharmony_ci         if (!scalarEqual(config, attrib, value)) {
231bf215546Sopenharmony_ci            static int warned;
232bf215546Sopenharmony_ci            if (!warned) {
233bf215546Sopenharmony_ci               DebugMessageF("Disabling server's tfp mipmap support\n");
234bf215546Sopenharmony_ci               warned = 1;
235bf215546Sopenharmony_ci            }
236bf215546Sopenharmony_ci            config->bindToMipmapTexture = 0;
237bf215546Sopenharmony_ci         }
238bf215546Sopenharmony_ci         break;
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci      default:
241bf215546Sopenharmony_ci         if (!scalarEqual(config, attrib, value))
242bf215546Sopenharmony_ci            return GL_FALSE;
243bf215546Sopenharmony_ci      }
244bf215546Sopenharmony_ci   }
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ci   return GL_TRUE;
247bf215546Sopenharmony_ci}
248bf215546Sopenharmony_ci
249bf215546Sopenharmony_cistatic struct glx_config *
250bf215546Sopenharmony_cicreateDriMode(const __DRIcoreExtension * core,
251bf215546Sopenharmony_ci	      struct glx_config *config, const __DRIconfig **driConfigs)
252bf215546Sopenharmony_ci{
253bf215546Sopenharmony_ci   __GLXDRIconfigPrivate *driConfig;
254bf215546Sopenharmony_ci   int i;
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci   for (i = 0; driConfigs[i]; i++) {
257bf215546Sopenharmony_ci      if (driConfigEqual(core, config, driConfigs[i]))
258bf215546Sopenharmony_ci         break;
259bf215546Sopenharmony_ci   }
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci   if (driConfigs[i] == NULL)
262bf215546Sopenharmony_ci      return NULL;
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci   driConfig = malloc(sizeof *driConfig);
265bf215546Sopenharmony_ci   if (driConfig == NULL)
266bf215546Sopenharmony_ci      return NULL;
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci   driConfig->base = *config;
269bf215546Sopenharmony_ci   driConfig->driConfig = driConfigs[i];
270bf215546Sopenharmony_ci
271bf215546Sopenharmony_ci   return &driConfig->base;
272bf215546Sopenharmony_ci}
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci_X_HIDDEN struct glx_config *
275bf215546Sopenharmony_cidriConvertConfigs(const __DRIcoreExtension * core,
276bf215546Sopenharmony_ci                  struct glx_config *configs, const __DRIconfig **driConfigs)
277bf215546Sopenharmony_ci{
278bf215546Sopenharmony_ci   struct glx_config head, *tail, *m;
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   tail = &head;
281bf215546Sopenharmony_ci   head.next = NULL;
282bf215546Sopenharmony_ci   for (m = configs; m; m = m->next) {
283bf215546Sopenharmony_ci      tail->next = createDriMode(core, m, driConfigs);
284bf215546Sopenharmony_ci      if (tail->next == NULL) {
285bf215546Sopenharmony_ci         /* no matching dri config for m */
286bf215546Sopenharmony_ci         continue;
287bf215546Sopenharmony_ci      }
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_ci      tail = tail->next;
291bf215546Sopenharmony_ci   }
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_ci   return head.next;
294bf215546Sopenharmony_ci}
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_ci_X_HIDDEN void
297bf215546Sopenharmony_cidriDestroyConfigs(const __DRIconfig **configs)
298bf215546Sopenharmony_ci{
299bf215546Sopenharmony_ci   int i;
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   for (i = 0; configs[i]; i++)
302bf215546Sopenharmony_ci      free((__DRIconfig *) configs[i]);
303bf215546Sopenharmony_ci   free(configs);
304bf215546Sopenharmony_ci}
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_cistatic struct glx_config *
307bf215546Sopenharmony_cidriInferDrawableConfig(struct glx_screen *psc, GLXDrawable draw)
308bf215546Sopenharmony_ci{
309bf215546Sopenharmony_ci   unsigned int fbconfig = 0;
310bf215546Sopenharmony_ci   xcb_get_window_attributes_cookie_t cookie = { 0 };
311bf215546Sopenharmony_ci   xcb_get_window_attributes_reply_t *attr = NULL;
312bf215546Sopenharmony_ci   xcb_connection_t *conn = XGetXCBConnection(psc->dpy);
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci   /* In practice here, either the XID is a bare Window or it was created
315bf215546Sopenharmony_ci    * by some other client. First let's see if the X server can tell us
316bf215546Sopenharmony_ci    * the answer. Xorg first added GLX_EXT_no_config_context in 1.20, where
317bf215546Sopenharmony_ci    * this usually works except for bare Windows that haven't been made
318bf215546Sopenharmony_ci    * current yet.
319bf215546Sopenharmony_ci    */
320bf215546Sopenharmony_ci   if (__glXGetDrawableAttribute(psc->dpy, draw, GLX_FBCONFIG_ID, &fbconfig)) {
321bf215546Sopenharmony_ci      return glx_config_find_fbconfig(psc->configs, fbconfig);
322bf215546Sopenharmony_ci   }
323bf215546Sopenharmony_ci
324bf215546Sopenharmony_ci   /* Well this had better be a Window then. Figure out its visual and
325bf215546Sopenharmony_ci    * then find the corresponding GLX visual.
326bf215546Sopenharmony_ci    */
327bf215546Sopenharmony_ci   cookie = xcb_get_window_attributes(conn, draw);
328bf215546Sopenharmony_ci   attr = xcb_get_window_attributes_reply(conn, cookie, NULL);
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   if (attr) {
331bf215546Sopenharmony_ci      uint32_t vid = attr->visual;
332bf215546Sopenharmony_ci      free(attr);
333bf215546Sopenharmony_ci      return glx_config_find_visual(psc->visuals, vid);
334bf215546Sopenharmony_ci   }
335bf215546Sopenharmony_ci
336bf215546Sopenharmony_ci   return NULL;
337bf215546Sopenharmony_ci}
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci_X_HIDDEN __GLXDRIdrawable *
340bf215546Sopenharmony_cidriFetchDrawable(struct glx_context *gc, GLXDrawable glxDrawable)
341bf215546Sopenharmony_ci{
342bf215546Sopenharmony_ci   Display *dpy = gc->psc->dpy;
343bf215546Sopenharmony_ci   struct glx_display *const priv = __glXInitialize(dpy);
344bf215546Sopenharmony_ci   __GLXDRIdrawable *pdraw;
345bf215546Sopenharmony_ci   struct glx_screen *psc;
346bf215546Sopenharmony_ci   struct glx_config *config = gc->config;
347bf215546Sopenharmony_ci   unsigned int type;
348bf215546Sopenharmony_ci
349bf215546Sopenharmony_ci   if (priv == NULL)
350bf215546Sopenharmony_ci      return NULL;
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci   if (glxDrawable == None)
353bf215546Sopenharmony_ci      return NULL;
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   psc = priv->screens[gc->screen];
356bf215546Sopenharmony_ci   if (priv->drawHash == NULL)
357bf215546Sopenharmony_ci      return NULL;
358bf215546Sopenharmony_ci
359bf215546Sopenharmony_ci   if (__glxHashLookup(priv->drawHash, glxDrawable, (void *) &pdraw) == 0) {
360bf215546Sopenharmony_ci      /* Resurrected, so remove from the alive-query-set if exist. */
361bf215546Sopenharmony_ci      _mesa_set_remove_key(priv->zombieGLXDrawable, pdraw);
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci      pdraw->refcount ++;
364bf215546Sopenharmony_ci      return pdraw;
365bf215546Sopenharmony_ci   }
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci   /* if this is a no-config context, infer the fbconfig from the drawable */
368bf215546Sopenharmony_ci   if (config == NULL)
369bf215546Sopenharmony_ci      config = driInferDrawableConfig(gc->psc, glxDrawable);
370bf215546Sopenharmony_ci   if (config == NULL)
371bf215546Sopenharmony_ci      return NULL;
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   /* We can't find this GLX drawable above because it's either:
374bf215546Sopenharmony_ci    *
375bf215546Sopenharmony_ci    * 1. An X window ID instead of a GLX window ID. This could happend when
376bf215546Sopenharmony_ci    *    glXMakeCurrent() is passed an X window directly instead of creating
377bf215546Sopenharmony_ci    *    GLXWindow with glXCreateWindow() first.
378bf215546Sopenharmony_ci    *
379bf215546Sopenharmony_ci    * 2. A GLXPbuffer created on other display:
380bf215546Sopenharmony_ci    *
381bf215546Sopenharmony_ci    *    From the GLX spec:
382bf215546Sopenharmony_ci    *
383bf215546Sopenharmony_ci    *      Like other drawable types, GLXPbuffers are shared; any client which
384bf215546Sopenharmony_ci    *      knows the associated XID can use a GLXPbuffer.
385bf215546Sopenharmony_ci    *
386bf215546Sopenharmony_ci    *    So client other than the creator of this GLXPbuffer could use its
387bf215546Sopenharmony_ci    *    XID to do something like glXMakeCurrent(). I can't find explicite
388bf215546Sopenharmony_ci    *    statement in GLX spec that also allow GLXWindow and GLXPixmap.
389bf215546Sopenharmony_ci    *
390bf215546Sopenharmony_ci    *    But even GLXWindow and GLXPixmap is allowed, currently client other
391bf215546Sopenharmony_ci    *    than the GLX drawable creator has no way to find which X drawable
392bf215546Sopenharmony_ci    *    (window or pixmap) this GLX drawable uses, except the GLXPbuffer
393bf215546Sopenharmony_ci    *    case which use the same XID for both X pixmap and GLX drawable.
394bf215546Sopenharmony_ci    */
395bf215546Sopenharmony_ci
396bf215546Sopenharmony_ci   /* Infer the GLX drawable type. */
397bf215546Sopenharmony_ci   if (__glXGetDrawableAttribute(dpy, glxDrawable, GLX_DRAWABLE_TYPE, &type)) {
398bf215546Sopenharmony_ci      /* Xserver may support query with raw X11 window. */
399bf215546Sopenharmony_ci      if (type == GLX_PIXMAP_BIT) {
400bf215546Sopenharmony_ci         ErrorMessageF("GLXPixmap drawable type is not supported\n");
401bf215546Sopenharmony_ci         return NULL;
402bf215546Sopenharmony_ci      }
403bf215546Sopenharmony_ci   } else {
404bf215546Sopenharmony_ci      /* Xserver may not implement GLX_DRAWABLE_TYPE query yet. */
405bf215546Sopenharmony_ci      type = GLX_PBUFFER_BIT | GLX_WINDOW_BIT;
406bf215546Sopenharmony_ci   }
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci   pdraw = psc->driScreen->createDrawable(psc, glxDrawable, glxDrawable,
409bf215546Sopenharmony_ci                                          type, config);
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   if (pdraw == NULL) {
412bf215546Sopenharmony_ci      ErrorMessageF("failed to create drawable\n");
413bf215546Sopenharmony_ci      return NULL;
414bf215546Sopenharmony_ci   }
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci   if (__glxHashInsert(priv->drawHash, glxDrawable, pdraw)) {
417bf215546Sopenharmony_ci      (*pdraw->destroyDrawable) (pdraw);
418bf215546Sopenharmony_ci      return NULL;
419bf215546Sopenharmony_ci   }
420bf215546Sopenharmony_ci   /* This sure does look suspicious, doesn't it? We're on this path because
421bf215546Sopenharmony_ci    * this is a naked Window. GLX 1.3 drawables have an explicit creation
422bf215546Sopenharmony_ci    * step (setting refcount to 1), and those we would have found in the
423bf215546Sopenharmony_ci    * hash lookup above, bumped their refcount for the bind_context we're
424bf215546Sopenharmony_ci    * being called for, and then returned. But since we just created the
425bf215546Sopenharmony_ci    * internal naked-Window state, we need to account for both here.
426bf215546Sopenharmony_ci    */
427bf215546Sopenharmony_ci   pdraw->refcount = 2;
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   return pdraw;
430bf215546Sopenharmony_ci}
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_cistatic int
433bf215546Sopenharmony_cidiscardGLXBadDrawableHandler(Display *display, xError *err, XExtCodes *codes,
434bf215546Sopenharmony_ci                             int *ret_code)
435bf215546Sopenharmony_ci{
436bf215546Sopenharmony_ci   int code = codes->first_error + GLXBadDrawable;
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   /* Only discard error which is expected. */
439bf215546Sopenharmony_ci   if (err->majorCode == codes->major_opcode &&
440bf215546Sopenharmony_ci       err->minorCode == X_GLXGetDrawableAttributes &&
441bf215546Sopenharmony_ci       /* newer xserver use GLXBadDrawable, old one use BadDrawable */
442bf215546Sopenharmony_ci       (err->errorCode == code || err->errorCode == BadDrawable)) {
443bf215546Sopenharmony_ci      *ret_code = 1;
444bf215546Sopenharmony_ci      return 1;
445bf215546Sopenharmony_ci   }
446bf215546Sopenharmony_ci
447bf215546Sopenharmony_ci   return 0;
448bf215546Sopenharmony_ci}
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_cistatic void
451bf215546Sopenharmony_cicheckServerGLXDrawableAlive(const struct glx_display *priv)
452bf215546Sopenharmony_ci{
453bf215546Sopenharmony_ci   ErrorType old = XESetError(priv->dpy, priv->codes.extension,
454bf215546Sopenharmony_ci                              discardGLXBadDrawableHandler);
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ci   set_foreach(priv->zombieGLXDrawable, entry) {
457bf215546Sopenharmony_ci      __GLXDRIdrawable *pdraw = (__GLXDRIdrawable *)entry->key;
458bf215546Sopenharmony_ci      GLXDrawable drawable = pdraw->drawable;
459bf215546Sopenharmony_ci      unsigned int dummy;
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci      /* Fail to query, so the window has been closed. Release the GLXDrawable. */
462bf215546Sopenharmony_ci      if (!__glXGetDrawableAttribute(priv->dpy, drawable, GLX_WIDTH, &dummy)) {
463bf215546Sopenharmony_ci         pdraw->destroyDrawable(pdraw);
464bf215546Sopenharmony_ci         __glxHashDelete(priv->drawHash, drawable);
465bf215546Sopenharmony_ci         _mesa_set_remove(priv->zombieGLXDrawable, entry);
466bf215546Sopenharmony_ci      }
467bf215546Sopenharmony_ci   }
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ci   XESetError(priv->dpy, priv->codes.extension, old);
470bf215546Sopenharmony_ci}
471bf215546Sopenharmony_ci
472bf215546Sopenharmony_cistatic void
473bf215546Sopenharmony_cireleaseDrawable(const struct glx_display *priv, GLXDrawable drawable)
474bf215546Sopenharmony_ci{
475bf215546Sopenharmony_ci   __GLXDRIdrawable *pdraw;
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci   if (__glxHashLookup(priv->drawHash, drawable, (void *) &pdraw) == 0) {
478bf215546Sopenharmony_ci      /* Only native window and pbuffer have same GLX and X11 drawable ID. */
479bf215546Sopenharmony_ci      if (pdraw->drawable == pdraw->xDrawable) {
480bf215546Sopenharmony_ci         pdraw->refcount --;
481bf215546Sopenharmony_ci         /* If pbuffer's refcount reaches 0, it must be imported from other
482bf215546Sopenharmony_ci          * display. Because pbuffer created from this display will always
483bf215546Sopenharmony_ci          * hold the last refcount until destroy the GLXPbuffer object.
484bf215546Sopenharmony_ci          */
485bf215546Sopenharmony_ci         if (pdraw->refcount == 0) {
486bf215546Sopenharmony_ci            if (pdraw->psc->keep_native_window_glx_drawable) {
487bf215546Sopenharmony_ci               checkServerGLXDrawableAlive(priv);
488bf215546Sopenharmony_ci               _mesa_set_add(priv->zombieGLXDrawable, pdraw);
489bf215546Sopenharmony_ci            } else {
490bf215546Sopenharmony_ci               pdraw->destroyDrawable(pdraw);
491bf215546Sopenharmony_ci               __glxHashDelete(priv->drawHash, drawable);
492bf215546Sopenharmony_ci            }
493bf215546Sopenharmony_ci         }
494bf215546Sopenharmony_ci      }
495bf215546Sopenharmony_ci   }
496bf215546Sopenharmony_ci}
497bf215546Sopenharmony_ci
498bf215546Sopenharmony_ci_X_HIDDEN void
499bf215546Sopenharmony_cidriReleaseDrawables(struct glx_context *gc)
500bf215546Sopenharmony_ci{
501bf215546Sopenharmony_ci   const struct glx_display *priv = (gc && gc->psc) ? gc->psc->display : NULL;
502bf215546Sopenharmony_ci
503bf215546Sopenharmony_ci   if (priv == NULL)
504bf215546Sopenharmony_ci      return;
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_ci   releaseDrawable(priv, gc->currentDrawable);
507bf215546Sopenharmony_ci   releaseDrawable(priv, gc->currentReadable);
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci   gc->currentDrawable = None;
510bf215546Sopenharmony_ci   gc->currentReadable = None;
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_ci}
513bf215546Sopenharmony_ci
514bf215546Sopenharmony_ci_X_HIDDEN int
515bf215546Sopenharmony_cidri_convert_glx_attribs(unsigned num_attribs, const uint32_t *attribs,
516bf215546Sopenharmony_ci                        struct dri_ctx_attribs *dca)
517bf215546Sopenharmony_ci{
518bf215546Sopenharmony_ci   unsigned i;
519bf215546Sopenharmony_ci   uint32_t profile = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
520bf215546Sopenharmony_ci
521bf215546Sopenharmony_ci   dca->major_ver = 1;
522bf215546Sopenharmony_ci   dca->minor_ver = 0;
523bf215546Sopenharmony_ci   dca->render_type = GLX_RGBA_TYPE;
524bf215546Sopenharmony_ci   dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION;
525bf215546Sopenharmony_ci   dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
526bf215546Sopenharmony_ci   dca->flags = 0;
527bf215546Sopenharmony_ci   dca->api = __DRI_API_OPENGL;
528bf215546Sopenharmony_ci   dca->no_error = 0;
529bf215546Sopenharmony_ci
530bf215546Sopenharmony_ci   if (num_attribs == 0)
531bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_SUCCESS;
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci   /* This is actually an internal error, but what the heck. */
534bf215546Sopenharmony_ci   if (attribs == NULL)
535bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
536bf215546Sopenharmony_ci
537bf215546Sopenharmony_ci   for (i = 0; i < num_attribs; i++) {
538bf215546Sopenharmony_ci      switch (attribs[i * 2]) {
539bf215546Sopenharmony_ci      case GLX_CONTEXT_MAJOR_VERSION_ARB:
540bf215546Sopenharmony_ci	 dca->major_ver = attribs[i * 2 + 1];
541bf215546Sopenharmony_ci	 break;
542bf215546Sopenharmony_ci      case GLX_CONTEXT_MINOR_VERSION_ARB:
543bf215546Sopenharmony_ci	 dca->minor_ver = attribs[i * 2 + 1];
544bf215546Sopenharmony_ci	 break;
545bf215546Sopenharmony_ci      case GLX_CONTEXT_FLAGS_ARB:
546bf215546Sopenharmony_ci	 dca->flags = attribs[i * 2 + 1];
547bf215546Sopenharmony_ci	 break;
548bf215546Sopenharmony_ci      case GLX_CONTEXT_OPENGL_NO_ERROR_ARB:
549bf215546Sopenharmony_ci	 dca->no_error = attribs[i * 2 + 1];
550bf215546Sopenharmony_ci	 break;
551bf215546Sopenharmony_ci      case GLX_CONTEXT_PROFILE_MASK_ARB:
552bf215546Sopenharmony_ci	 profile = attribs[i * 2 + 1];
553bf215546Sopenharmony_ci	 break;
554bf215546Sopenharmony_ci      case GLX_RENDER_TYPE:
555bf215546Sopenharmony_ci         dca->render_type = attribs[i * 2 + 1];
556bf215546Sopenharmony_ci	 break;
557bf215546Sopenharmony_ci      case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB:
558bf215546Sopenharmony_ci         switch (attribs[i * 2 + 1]) {
559bf215546Sopenharmony_ci         case GLX_NO_RESET_NOTIFICATION_ARB:
560bf215546Sopenharmony_ci            dca->reset = __DRI_CTX_RESET_NO_NOTIFICATION;
561bf215546Sopenharmony_ci            break;
562bf215546Sopenharmony_ci         case GLX_LOSE_CONTEXT_ON_RESET_ARB:
563bf215546Sopenharmony_ci            dca->reset = __DRI_CTX_RESET_LOSE_CONTEXT;
564bf215546Sopenharmony_ci            break;
565bf215546Sopenharmony_ci         default:
566bf215546Sopenharmony_ci            return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
567bf215546Sopenharmony_ci         }
568bf215546Sopenharmony_ci         break;
569bf215546Sopenharmony_ci      case GLX_CONTEXT_RELEASE_BEHAVIOR_ARB:
570bf215546Sopenharmony_ci         switch (attribs[i * 2 + 1]) {
571bf215546Sopenharmony_ci         case GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB:
572bf215546Sopenharmony_ci            dca->release = __DRI_CTX_RELEASE_BEHAVIOR_NONE;
573bf215546Sopenharmony_ci            break;
574bf215546Sopenharmony_ci         case GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB:
575bf215546Sopenharmony_ci            dca->release = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH;
576bf215546Sopenharmony_ci            break;
577bf215546Sopenharmony_ci         default:
578bf215546Sopenharmony_ci            return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
579bf215546Sopenharmony_ci         }
580bf215546Sopenharmony_ci         break;
581bf215546Sopenharmony_ci      case GLX_SCREEN:
582bf215546Sopenharmony_ci         /* Implies GLX_EXT_no_config_context */
583bf215546Sopenharmony_ci         dca->render_type = GLX_DONT_CARE;
584bf215546Sopenharmony_ci         break;
585bf215546Sopenharmony_ci      default:
586bf215546Sopenharmony_ci	 /* If an unknown attribute is received, fail.
587bf215546Sopenharmony_ci	  */
588bf215546Sopenharmony_ci	 return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
589bf215546Sopenharmony_ci      }
590bf215546Sopenharmony_ci   }
591bf215546Sopenharmony_ci
592bf215546Sopenharmony_ci   switch (profile) {
593bf215546Sopenharmony_ci   case GLX_CONTEXT_CORE_PROFILE_BIT_ARB:
594bf215546Sopenharmony_ci      /* This is the default value, but there are no profiles before OpenGL
595bf215546Sopenharmony_ci       * 3.2. The GLX_ARB_create_context_profile spec says:
596bf215546Sopenharmony_ci       *
597bf215546Sopenharmony_ci       *     "If the requested OpenGL version is less than 3.2,
598bf215546Sopenharmony_ci       *     GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
599bf215546Sopenharmony_ci       *     of the context is determined solely by the requested version."
600bf215546Sopenharmony_ci       */
601bf215546Sopenharmony_ci      dca->api = (dca->major_ver > 3 || (dca->major_ver == 3 && dca->minor_ver >= 2))
602bf215546Sopenharmony_ci         ? __DRI_API_OPENGL_CORE : __DRI_API_OPENGL;
603bf215546Sopenharmony_ci      break;
604bf215546Sopenharmony_ci   case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB:
605bf215546Sopenharmony_ci      dca->api = __DRI_API_OPENGL;
606bf215546Sopenharmony_ci      break;
607bf215546Sopenharmony_ci   case GLX_CONTEXT_ES_PROFILE_BIT_EXT:
608bf215546Sopenharmony_ci      if (dca->major_ver >= 3)
609bf215546Sopenharmony_ci         dca->api = __DRI_API_GLES3;
610bf215546Sopenharmony_ci      else if (dca->major_ver == 2 && dca->minor_ver == 0)
611bf215546Sopenharmony_ci         dca->api = __DRI_API_GLES2;
612bf215546Sopenharmony_ci      else if (dca->major_ver == 1 && dca->minor_ver < 2)
613bf215546Sopenharmony_ci         dca->api = __DRI_API_GLES;
614bf215546Sopenharmony_ci      else {
615bf215546Sopenharmony_ci         return __DRI_CTX_ERROR_BAD_API;
616bf215546Sopenharmony_ci      }
617bf215546Sopenharmony_ci      break;
618bf215546Sopenharmony_ci   default:
619bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_BAD_API;
620bf215546Sopenharmony_ci   }
621bf215546Sopenharmony_ci
622bf215546Sopenharmony_ci   /* Unknown flag value */
623bf215546Sopenharmony_ci   if (dca->flags & ~(__DRI_CTX_FLAG_DEBUG |
624bf215546Sopenharmony_ci                      __DRI_CTX_FLAG_FORWARD_COMPATIBLE |
625bf215546Sopenharmony_ci                      __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS |
626bf215546Sopenharmony_ci                      __DRI_CTX_FLAG_RESET_ISOLATION))
627bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_UNKNOWN_FLAG;
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_ci   /* There are no forward-compatible contexts before OpenGL 3.0.  The
630bf215546Sopenharmony_ci    * GLX_ARB_create_context spec says:
631bf215546Sopenharmony_ci    *
632bf215546Sopenharmony_ci    *     "Forward-compatible contexts are defined only for OpenGL versions
633bf215546Sopenharmony_ci    *     3.0 and later."
634bf215546Sopenharmony_ci    */
635bf215546Sopenharmony_ci   if (dca->major_ver < 3 && (dca->flags & __DRI_CTX_FLAG_FORWARD_COMPATIBLE) != 0)
636bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_BAD_FLAG;
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_ci   if (dca->major_ver >= 3 && dca->render_type == GLX_COLOR_INDEX_TYPE)
639bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_BAD_FLAG;
640bf215546Sopenharmony_ci
641bf215546Sopenharmony_ci   /* The KHR_no_error specs say:
642bf215546Sopenharmony_ci    *
643bf215546Sopenharmony_ci    *    Requires OpenGL ES 2.0 or OpenGL 2.0.
644bf215546Sopenharmony_ci    */
645bf215546Sopenharmony_ci   if (dca->no_error && dca->major_ver < 2)
646bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE;
647bf215546Sopenharmony_ci
648bf215546Sopenharmony_ci   /* The GLX_ARB_create_context_no_error specs say:
649bf215546Sopenharmony_ci    *
650bf215546Sopenharmony_ci    *    BadMatch is generated if the GLX_CONTEXT_OPENGL_NO_ERROR_ARB is TRUE at
651bf215546Sopenharmony_ci    *    the same time as a debug or robustness context is specified.
652bf215546Sopenharmony_ci    *
653bf215546Sopenharmony_ci    */
654bf215546Sopenharmony_ci   if (dca->no_error && ((dca->flags & __DRI_CTX_FLAG_DEBUG) ||
655bf215546Sopenharmony_ci                         (dca->flags & __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS)))
656bf215546Sopenharmony_ci      return __DRI_CTX_ERROR_BAD_FLAG;
657bf215546Sopenharmony_ci
658bf215546Sopenharmony_ci   return __DRI_CTX_ERROR_SUCCESS;
659bf215546Sopenharmony_ci}
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_cistruct glx_context *
662bf215546Sopenharmony_cidri_common_create_context(struct glx_screen *base,
663bf215546Sopenharmony_ci                          struct glx_config *config_base,
664bf215546Sopenharmony_ci                          struct glx_context *shareList,
665bf215546Sopenharmony_ci                          int renderType)
666bf215546Sopenharmony_ci{
667bf215546Sopenharmony_ci   unsigned int error;
668bf215546Sopenharmony_ci   uint32_t attribs[2] = { GLX_RENDER_TYPE, renderType };
669bf215546Sopenharmony_ci
670bf215546Sopenharmony_ci   return base->vtable->create_context_attribs(base, config_base, shareList,
671bf215546Sopenharmony_ci                                               1, attribs, &error);
672bf215546Sopenharmony_ci}
673bf215546Sopenharmony_ci
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci/*
676bf215546Sopenharmony_ci * Given a display pointer and screen number, determine the name of
677bf215546Sopenharmony_ci * the DRI driver for the screen (i.e., "i965", "radeon", "nouveau", etc).
678bf215546Sopenharmony_ci * Return True for success, False for failure.
679bf215546Sopenharmony_ci */
680bf215546Sopenharmony_cistatic Bool
681bf215546Sopenharmony_cidriGetDriverName(Display * dpy, int scrNum, char **driverName)
682bf215546Sopenharmony_ci{
683bf215546Sopenharmony_ci   struct glx_screen *glx_screen = GetGLXScreenConfigs(dpy, scrNum);
684bf215546Sopenharmony_ci
685bf215546Sopenharmony_ci   if (!glx_screen || !glx_screen->vtable->get_driver_name)
686bf215546Sopenharmony_ci      return False;
687bf215546Sopenharmony_ci
688bf215546Sopenharmony_ci   *driverName = glx_screen->vtable->get_driver_name(glx_screen);
689bf215546Sopenharmony_ci   return True;
690bf215546Sopenharmony_ci}
691bf215546Sopenharmony_ci
692bf215546Sopenharmony_ci/*
693bf215546Sopenharmony_ci * Exported function for querying the DRI driver for a given screen.
694bf215546Sopenharmony_ci *
695bf215546Sopenharmony_ci * The returned char pointer points to a static array that will be
696bf215546Sopenharmony_ci * overwritten by subsequent calls.
697bf215546Sopenharmony_ci */
698bf215546Sopenharmony_ci_GLX_PUBLIC const char *
699bf215546Sopenharmony_ciglXGetScreenDriver(Display * dpy, int scrNum)
700bf215546Sopenharmony_ci{
701bf215546Sopenharmony_ci   static char ret[32];
702bf215546Sopenharmony_ci   char *driverName;
703bf215546Sopenharmony_ci
704bf215546Sopenharmony_ci   if (driGetDriverName(dpy, scrNum, &driverName)) {
705bf215546Sopenharmony_ci      int len;
706bf215546Sopenharmony_ci      if (!driverName)
707bf215546Sopenharmony_ci         return NULL;
708bf215546Sopenharmony_ci      len = strlen(driverName);
709bf215546Sopenharmony_ci      if (len >= 31)
710bf215546Sopenharmony_ci         return NULL;
711bf215546Sopenharmony_ci      memcpy(ret, driverName, len + 1);
712bf215546Sopenharmony_ci      free(driverName);
713bf215546Sopenharmony_ci      return ret;
714bf215546Sopenharmony_ci   }
715bf215546Sopenharmony_ci   return NULL;
716bf215546Sopenharmony_ci}
717bf215546Sopenharmony_ci
718bf215546Sopenharmony_ci/* glXGetDriverConfig must return a pointer with a static lifetime. To avoid
719bf215546Sopenharmony_ci * keeping drivers loaded and other leaks, we keep a cache of results here that
720bf215546Sopenharmony_ci * is cleared by an atexit handler.
721bf215546Sopenharmony_ci */
722bf215546Sopenharmony_cistruct driver_config_entry {
723bf215546Sopenharmony_ci   struct driver_config_entry *next;
724bf215546Sopenharmony_ci   char *driverName;
725bf215546Sopenharmony_ci   char *config;
726bf215546Sopenharmony_ci};
727bf215546Sopenharmony_ci
728bf215546Sopenharmony_cistatic pthread_mutex_t driver_config_mutex = PTHREAD_MUTEX_INITIALIZER;
729bf215546Sopenharmony_cistatic struct driver_config_entry *driver_config_cache = NULL;
730bf215546Sopenharmony_ci
731bf215546Sopenharmony_ci/* Called as an atexit function. Otherwise, this would have to be called with
732bf215546Sopenharmony_ci * driver_config_mutex locked.
733bf215546Sopenharmony_ci */
734bf215546Sopenharmony_cistatic void
735bf215546Sopenharmony_ciclear_driver_config_cache()
736bf215546Sopenharmony_ci{
737bf215546Sopenharmony_ci   while (driver_config_cache) {
738bf215546Sopenharmony_ci      struct driver_config_entry *e = driver_config_cache;
739bf215546Sopenharmony_ci      driver_config_cache = e->next;
740bf215546Sopenharmony_ci
741bf215546Sopenharmony_ci      free(e->driverName);
742bf215546Sopenharmony_ci      free(e->config);
743bf215546Sopenharmony_ci      free(e);
744bf215546Sopenharmony_ci   }
745bf215546Sopenharmony_ci}
746bf215546Sopenharmony_ci
747bf215546Sopenharmony_cistatic char *
748bf215546Sopenharmony_ciget_driver_config(const char *driverName)
749bf215546Sopenharmony_ci{
750bf215546Sopenharmony_ci   void *handle;
751bf215546Sopenharmony_ci   char *config = NULL;
752bf215546Sopenharmony_ci   const __DRIextension **extensions = driOpenDriver(driverName, &handle);
753bf215546Sopenharmony_ci   if (extensions) {
754bf215546Sopenharmony_ci      for (int i = 0; extensions[i]; i++) {
755bf215546Sopenharmony_ci         if (strcmp(extensions[i]->name, __DRI_CONFIG_OPTIONS) != 0)
756bf215546Sopenharmony_ci            continue;
757bf215546Sopenharmony_ci
758bf215546Sopenharmony_ci         __DRIconfigOptionsExtension *ext =
759bf215546Sopenharmony_ci            (__DRIconfigOptionsExtension *)extensions[i];
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci         if (ext->base.version >= 2)
762bf215546Sopenharmony_ci            config = ext->getXml(driverName);
763bf215546Sopenharmony_ci         else
764bf215546Sopenharmony_ci            config = strdup(ext->xml);
765bf215546Sopenharmony_ci
766bf215546Sopenharmony_ci         break;
767bf215546Sopenharmony_ci      }
768bf215546Sopenharmony_ci   }
769bf215546Sopenharmony_ci
770bf215546Sopenharmony_ci   if (!config) {
771bf215546Sopenharmony_ci      /* Fall back to the old method */
772bf215546Sopenharmony_ci      config = dlsym(handle, "__driConfigOptions");
773bf215546Sopenharmony_ci      if (config)
774bf215546Sopenharmony_ci         config = strdup(config);
775bf215546Sopenharmony_ci   }
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci   dlclose(handle);
778bf215546Sopenharmony_ci
779bf215546Sopenharmony_ci   return config;
780bf215546Sopenharmony_ci}
781bf215546Sopenharmony_ci
782bf215546Sopenharmony_ci/*
783bf215546Sopenharmony_ci * Exported function for obtaining a driver's option list (UTF-8 encoded XML).
784bf215546Sopenharmony_ci *
785bf215546Sopenharmony_ci * The returned char pointer points directly into the driver. Therefore
786bf215546Sopenharmony_ci * it should be treated as a constant.
787bf215546Sopenharmony_ci *
788bf215546Sopenharmony_ci * If the driver was not found or does not support configuration NULL is
789bf215546Sopenharmony_ci * returned.
790bf215546Sopenharmony_ci */
791bf215546Sopenharmony_ci_GLX_PUBLIC const char *
792bf215546Sopenharmony_ciglXGetDriverConfig(const char *driverName)
793bf215546Sopenharmony_ci{
794bf215546Sopenharmony_ci   struct driver_config_entry *e;
795bf215546Sopenharmony_ci
796bf215546Sopenharmony_ci   pthread_mutex_lock(&driver_config_mutex);
797bf215546Sopenharmony_ci
798bf215546Sopenharmony_ci   for (e = driver_config_cache; e; e = e->next) {
799bf215546Sopenharmony_ci      if (strcmp(e->driverName, driverName) == 0)
800bf215546Sopenharmony_ci         goto out;
801bf215546Sopenharmony_ci   }
802bf215546Sopenharmony_ci
803bf215546Sopenharmony_ci   e = malloc(sizeof(*e));
804bf215546Sopenharmony_ci   if (!e)
805bf215546Sopenharmony_ci      goto out;
806bf215546Sopenharmony_ci
807bf215546Sopenharmony_ci   e->config = get_driver_config(driverName);
808bf215546Sopenharmony_ci   e->driverName = strdup(driverName);
809bf215546Sopenharmony_ci   if (!e->config || !e->driverName) {
810bf215546Sopenharmony_ci      free(e->config);
811bf215546Sopenharmony_ci      free(e->driverName);
812bf215546Sopenharmony_ci      free(e);
813bf215546Sopenharmony_ci      e = NULL;
814bf215546Sopenharmony_ci      goto out;
815bf215546Sopenharmony_ci   }
816bf215546Sopenharmony_ci
817bf215546Sopenharmony_ci   e->next = driver_config_cache;
818bf215546Sopenharmony_ci   driver_config_cache = e;
819bf215546Sopenharmony_ci
820bf215546Sopenharmony_ci   if (!e->next)
821bf215546Sopenharmony_ci      atexit(clear_driver_config_cache);
822bf215546Sopenharmony_ci
823bf215546Sopenharmony_ciout:
824bf215546Sopenharmony_ci   pthread_mutex_unlock(&driver_config_mutex);
825bf215546Sopenharmony_ci
826bf215546Sopenharmony_ci   return e ? e->config : NULL;
827bf215546Sopenharmony_ci}
828bf215546Sopenharmony_ci
829bf215546Sopenharmony_ci#endif /* GLX_DIRECT_RENDERING */
830