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