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