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