dri: unify __DriverAPIRec
[mesa.git] / src / mesa / drivers / dri / common / dri_util.c
1 /**
2 * \file dri_util.c
3 * DRI utility functions.
4 *
5 * This module acts as glue between GLX and the actual hardware driver. A DRI
6 * driver doesn't really \e have to use any of this - it's optional. But, some
7 * useful stuff is done here that otherwise would have to be duplicated in most
8 * drivers.
9 *
10 * Basically, these utility functions take care of some of the dirty details of
11 * screen initialization, context creation, context binding, DRM setup, etc.
12 *
13 * These functions are compiled into each DRI driver so libGL.so knows nothing
14 * about them.
15 */
16
17
18 #include <assert.h>
19 #include <stdarg.h>
20 #include <stdio.h>
21
22 #include "main/imports.h"
23
24 #include <drm.h>
25 #include <xf86drm.h>
26 #include "dri_util.h"
27 #include "utils.h"
28 #include "xmlpool.h"
29 #include "../glsl/glsl_parser_extras.h"
30
31 PUBLIC const char __dri2ConfigOptions[] =
32 DRI_CONF_BEGIN
33 DRI_CONF_SECTION_PERFORMANCE
34 DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_1)
35 DRI_CONF_SECTION_END
36 DRI_CONF_END;
37
38 static const uint __dri2NConfigOptions = 1;
39
40 #ifndef GLX_OML_sync_control
41 typedef GLboolean ( * PFNGLXGETMSCRATEOMLPROC) (__DRIdrawable *drawable, int32_t *numerator, int32_t *denominator);
42 #endif
43
44 static void dri_get_drawable(__DRIdrawable *pdp);
45 static void dri_put_drawable(__DRIdrawable *pdp);
46
47 /*****************************************************************/
48 /** \name Context (un)binding functions */
49 /*****************************************************************/
50 /*@{*/
51
52 /**
53 * Unbind context.
54 *
55 * \param scrn the screen.
56 * \param gc context.
57 *
58 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
59 *
60 * \internal
61 * This function calls __DriverAPIRec::UnbindContext, and then decrements
62 * __DRIdrawableRec::refcount which must be non-zero for a successful
63 * return.
64 *
65 * While casting the opaque private pointers associated with the parameters
66 * into their respective real types it also assures they are not \c NULL.
67 */
68 static int driUnbindContext(__DRIcontext *pcp)
69 {
70 __DRIscreen *psp;
71 __DRIdrawable *pdp;
72 __DRIdrawable *prp;
73
74 /*
75 ** Assume error checking is done properly in glXMakeCurrent before
76 ** calling driUnbindContext.
77 */
78
79 if (pcp == NULL)
80 return GL_FALSE;
81
82 psp = pcp->driScreenPriv;
83 pdp = pcp->driDrawablePriv;
84 prp = pcp->driReadablePriv;
85
86 /* already unbound */
87 if (!pdp && !prp)
88 return GL_TRUE;
89 /* Let driver unbind drawable from context */
90 (*psp->DriverAPI.UnbindContext)(pcp);
91
92 assert(pdp);
93 if (pdp->refcount == 0) {
94 /* ERROR!!! */
95 return GL_FALSE;
96 }
97
98 dri_put_drawable(pdp);
99
100 if (prp != pdp) {
101 if (prp->refcount == 0) {
102 /* ERROR!!! */
103 return GL_FALSE;
104 }
105
106 dri_put_drawable(prp);
107 }
108
109
110 /* XXX this is disabled so that if we call SwapBuffers on an unbound
111 * window we can determine the last context bound to the window and
112 * use that context's lock. (BrianP, 2-Dec-2000)
113 */
114 pcp->driDrawablePriv = pcp->driReadablePriv = NULL;
115
116 return GL_TRUE;
117 }
118
119 /**
120 * This function takes both a read buffer and a draw buffer. This is needed
121 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
122 * function.
123 */
124 static int driBindContext(__DRIcontext *pcp,
125 __DRIdrawable *pdp,
126 __DRIdrawable *prp)
127 {
128 __DRIscreen *psp = NULL;
129
130 /*
131 ** Assume error checking is done properly in glXMakeCurrent before
132 ** calling driUnbindContext.
133 */
134
135 if (!pcp)
136 return GL_FALSE;
137
138 /* Bind the drawable to the context */
139 psp = pcp->driScreenPriv;
140 pcp->driDrawablePriv = pdp;
141 pcp->driReadablePriv = prp;
142 if (pdp) {
143 pdp->driContextPriv = pcp;
144 dri_get_drawable(pdp);
145 }
146 if (prp && pdp != prp) {
147 dri_get_drawable(prp);
148 }
149
150 /* Call device-specific MakeCurrent */
151 return (*psp->DriverAPI.MakeCurrent)(pcp, pdp, prp);
152 }
153
154 static __DRIdrawable *
155 dri2CreateNewDrawable(__DRIscreen *screen,
156 const __DRIconfig *config,
157 void *loaderPrivate)
158 {
159 __DRIdrawable *pdraw;
160
161 pdraw = malloc(sizeof *pdraw);
162 if (!pdraw)
163 return NULL;
164
165 pdraw->driContextPriv = NULL;
166 pdraw->loaderPrivate = loaderPrivate;
167 pdraw->refcount = 1;
168 pdraw->lastStamp = 0;
169 pdraw->w = 0;
170 pdraw->h = 0;
171 pdraw->driScreenPriv = screen;
172
173 if (!(*screen->DriverAPI.CreateBuffer)(screen, pdraw, &config->modes, 0)) {
174 free(pdraw);
175 return NULL;
176 }
177
178 pdraw->dri2.stamp = pdraw->lastStamp + 1;
179
180 return pdraw;
181 }
182
183 static __DRIbuffer *
184 dri2AllocateBuffer(__DRIscreen *screen,
185 unsigned int attachment, unsigned int format,
186 int width, int height)
187 {
188 return (*screen->DriverAPI.AllocateBuffer)(screen, attachment, format,
189 width, height);
190 }
191
192 static void
193 dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
194 {
195 (*screen->DriverAPI.ReleaseBuffer)(screen, buffer);
196 }
197
198
199 static int
200 dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val)
201 {
202 if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
203 return -1;
204
205 *val = driQueryOptionb(&screen->optionCache, var);
206
207 return 0;
208 }
209
210 static int
211 dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val)
212 {
213 if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
214 !driCheckOption(&screen->optionCache, var, DRI_ENUM))
215 return -1;
216
217 *val = driQueryOptioni(&screen->optionCache, var);
218
219 return 0;
220 }
221
222 static int
223 dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val)
224 {
225 if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
226 return -1;
227
228 *val = driQueryOptionf(&screen->optionCache, var);
229
230 return 0;
231 }
232
233
234 static void dri_get_drawable(__DRIdrawable *pdp)
235 {
236 pdp->refcount++;
237 }
238
239 static void dri_put_drawable(__DRIdrawable *pdp)
240 {
241 __DRIscreen *psp;
242
243 if (pdp) {
244 pdp->refcount--;
245 if (pdp->refcount)
246 return;
247
248 psp = pdp->driScreenPriv;
249 (*psp->DriverAPI.DestroyBuffer)(pdp);
250 free(pdp);
251 }
252 }
253
254 static void
255 driDestroyDrawable(__DRIdrawable *pdp)
256 {
257 dri_put_drawable(pdp);
258 }
259
260 /*@}*/
261
262
263 /*****************************************************************/
264 /** \name Context handling functions */
265 /*****************************************************************/
266 /*@{*/
267
268 /**
269 * Destroy the per-context private information.
270 *
271 * \internal
272 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
273 * drmDestroyContext(), and finally frees \p contextPrivate.
274 */
275 static void
276 driDestroyContext(__DRIcontext *pcp)
277 {
278 if (pcp) {
279 (*pcp->driScreenPriv->DriverAPI.DestroyContext)(pcp);
280 free(pcp);
281 }
282 }
283
284 static unsigned int
285 dri2GetAPIMask(__DRIscreen *screen)
286 {
287 return screen->api_mask;
288 }
289
290 static __DRIcontext *
291 dri2CreateNewContextForAPI(__DRIscreen *screen, int api,
292 const __DRIconfig *config,
293 __DRIcontext *shared, void *data)
294 {
295 __DRIcontext *context;
296 const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
297 void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
298 gl_api mesa_api;
299
300 if (!(screen->api_mask & (1 << api)))
301 return NULL;
302
303 switch (api) {
304 case __DRI_API_OPENGL:
305 mesa_api = API_OPENGL;
306 break;
307 case __DRI_API_GLES:
308 mesa_api = API_OPENGLES;
309 break;
310 case __DRI_API_GLES2:
311 mesa_api = API_OPENGLES2;
312 break;
313 default:
314 return NULL;
315 }
316
317 context = malloc(sizeof *context);
318 if (!context)
319 return NULL;
320
321 context->driScreenPriv = screen;
322 context->driDrawablePriv = NULL;
323 context->loaderPrivate = data;
324
325 if (!(*screen->DriverAPI.CreateContext)(mesa_api, modes,
326 context, shareCtx) ) {
327 free(context);
328 return NULL;
329 }
330
331 return context;
332 }
333
334
335 static __DRIcontext *
336 dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
337 __DRIcontext *shared, void *data)
338 {
339 return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL,
340 config, shared, data);
341 }
342
343 static int
344 driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
345 {
346 (void) dest;
347 (void) src;
348 (void) mask;
349 return GL_FALSE;
350 }
351
352 /*@}*/
353
354
355 /*****************************************************************/
356 /** \name Screen handling functions */
357 /*****************************************************************/
358 /*@{*/
359
360 /**
361 * Destroy the per-screen private information.
362 *
363 * \internal
364 * This function calls __DriverAPIRec::DestroyScreen on \p screenPrivate, calls
365 * drmClose(), and finally frees \p screenPrivate.
366 */
367 static void driDestroyScreen(__DRIscreen *psp)
368 {
369 if (psp) {
370 /* No interaction with the X-server is possible at this point. This
371 * routine is called after XCloseDisplay, so there is no protocol
372 * stream open to the X-server anymore.
373 */
374
375 _mesa_destroy_shader_compiler();
376
377 if (psp->DriverAPI.DestroyScreen)
378 (*psp->DriverAPI.DestroyScreen)(psp);
379
380 driDestroyOptionCache(&psp->optionCache);
381 driDestroyOptionInfo(&psp->optionInfo);
382
383 free(psp);
384 }
385 }
386
387 static void
388 setupLoaderExtensions(__DRIscreen *psp,
389 const __DRIextension **extensions)
390 {
391 int i;
392
393 for (i = 0; extensions[i]; i++) {
394 if (strcmp(extensions[i]->name, __DRI_DRI2_LOADER) == 0)
395 psp->dri2.loader = (__DRIdri2LoaderExtension *) extensions[i];
396 if (strcmp(extensions[i]->name, __DRI_IMAGE_LOOKUP) == 0)
397 psp->dri2.image = (__DRIimageLookupExtension *) extensions[i];
398 if (strcmp(extensions[i]->name, __DRI_USE_INVALIDATE) == 0)
399 psp->dri2.useInvalidate = (__DRIuseInvalidateExtension *) extensions[i];
400 }
401 }
402
403 /**
404 * DRI2
405 */
406 static __DRIscreen *
407 dri2CreateNewScreen(int scrn, int fd,
408 const __DRIextension **extensions,
409 const __DRIconfig ***driver_configs, void *data)
410 {
411 static const __DRIextension *emptyExtensionList[] = { NULL };
412 __DRIscreen *psp;
413 drmVersionPtr version;
414
415 psp = calloc(1, sizeof(*psp));
416 if (!psp)
417 return NULL;
418
419 setupLoaderExtensions(psp, extensions);
420
421 version = drmGetVersion(fd);
422 if (version) {
423 psp->drm_version.major = version->version_major;
424 psp->drm_version.minor = version->version_minor;
425 psp->drm_version.patch = version->version_patchlevel;
426 drmFreeVersion(version);
427 }
428
429 psp->extensions = emptyExtensionList;
430 psp->fd = fd;
431 psp->myNum = scrn;
432
433 psp->DriverAPI = driDriverAPI;
434 psp->api_mask = (1 << __DRI_API_OPENGL);
435 *driver_configs = driDriverAPI.InitScreen(psp);
436 if (*driver_configs == NULL) {
437 free(psp);
438 return NULL;
439 }
440
441 psp->DriverAPI = driDriverAPI;
442 psp->loaderPrivate = data;
443
444 driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions,
445 __dri2NConfigOptions);
446 driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum,
447 "dri2");
448
449 return psp;
450 }
451
452 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
453 {
454 return psp->extensions;
455 }
456
457 /** Core interface */
458 const __DRIcoreExtension driCoreExtension = {
459 { __DRI_CORE, __DRI_CORE_VERSION },
460 NULL,
461 driDestroyScreen,
462 driGetExtensions,
463 driGetConfigAttrib,
464 driIndexConfigAttrib,
465 NULL,
466 driDestroyDrawable,
467 NULL,
468 NULL,
469 driCopyContext,
470 driDestroyContext,
471 driBindContext,
472 driUnbindContext
473 };
474
475 /** DRI2 interface */
476 const __DRIdri2Extension driDRI2Extension = {
477 { __DRI_DRI2, __DRI_DRI2_VERSION },
478 dri2CreateNewScreen,
479 dri2CreateNewDrawable,
480 dri2CreateNewContext,
481 dri2GetAPIMask,
482 dri2CreateNewContextForAPI,
483 dri2AllocateBuffer,
484 dri2ReleaseBuffer
485 };
486
487 const __DRI2configQueryExtension dri2ConfigQueryExtension = {
488 { __DRI2_CONFIG_QUERY, __DRI2_CONFIG_QUERY_VERSION },
489 dri2ConfigQueryb,
490 dri2ConfigQueryi,
491 dri2ConfigQueryf,
492 };
493
494 void
495 dri2InvalidateDrawable(__DRIdrawable *drawable)
496 {
497 drawable->dri2.stamp++;
498 }
499
500 /**
501 * Check that the gl_framebuffer associated with dPriv is the right size.
502 * Resize the gl_framebuffer if needed.
503 * It's expected that the dPriv->driverPrivate member points to a
504 * gl_framebuffer object.
505 */
506 void
507 driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv)
508 {
509 struct gl_framebuffer *fb = (struct gl_framebuffer *) dPriv->driverPrivate;
510 if (fb && (dPriv->w != fb->Width || dPriv->h != fb->Height)) {
511 ctx->Driver.ResizeBuffers(ctx, fb, dPriv->w, dPriv->h);
512 /* if the driver needs the hw lock for ResizeBuffers, the drawable
513 might have changed again by now */
514 assert(fb->Width == dPriv->w);
515 assert(fb->Height == dPriv->h);
516 }
517 }