dri_util: move screen 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 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 (un)binding functions */
138 /*****************************************************************/
139 /*@{*/
140
141 /**
142 * Unbind context.
143 *
144 * \param scrn the screen.
145 * \param gc context.
146 *
147 * \return \c GL_TRUE on success, or \c GL_FALSE on failure.
148 *
149 * \internal
150 * This function calls __DriverAPIRec::UnbindContext, and then decrements
151 * __DRIdrawableRec::refcount which must be non-zero for a successful
152 * return.
153 *
154 * While casting the opaque private pointers associated with the parameters
155 * into their respective real types it also assures they are not \c NULL.
156 */
157 static int driUnbindContext(__DRIcontext *pcp)
158 {
159 __DRIdrawable *pdp;
160 __DRIdrawable *prp;
161
162 /*
163 ** Assume error checking is done properly in glXMakeCurrent before
164 ** calling driUnbindContext.
165 */
166
167 if (pcp == NULL)
168 return GL_FALSE;
169
170 pdp = pcp->driDrawablePriv;
171 prp = pcp->driReadablePriv;
172
173 /* already unbound */
174 if (!pdp && !prp)
175 return GL_TRUE;
176 /* Let driver unbind drawable from context */
177 driDriverAPI.UnbindContext(pcp);
178
179 assert(pdp);
180 if (pdp->refcount == 0) {
181 /* ERROR!!! */
182 return GL_FALSE;
183 }
184
185 dri_put_drawable(pdp);
186
187 if (prp != pdp) {
188 if (prp->refcount == 0) {
189 /* ERROR!!! */
190 return GL_FALSE;
191 }
192
193 dri_put_drawable(prp);
194 }
195
196
197 /* XXX this is disabled so that if we call SwapBuffers on an unbound
198 * window we can determine the last context bound to the window and
199 * use that context's lock. (BrianP, 2-Dec-2000)
200 */
201 pcp->driDrawablePriv = pcp->driReadablePriv = NULL;
202
203 return GL_TRUE;
204 }
205
206 /**
207 * This function takes both a read buffer and a draw buffer. This is needed
208 * for \c glXMakeCurrentReadSGI or GLX 1.3's \c glXMakeContextCurrent
209 * function.
210 */
211 static int driBindContext(__DRIcontext *pcp,
212 __DRIdrawable *pdp,
213 __DRIdrawable *prp)
214 {
215 /*
216 ** Assume error checking is done properly in glXMakeCurrent before
217 ** calling driUnbindContext.
218 */
219
220 if (!pcp)
221 return GL_FALSE;
222
223 /* Bind the drawable to the context */
224 pcp->driDrawablePriv = pdp;
225 pcp->driReadablePriv = prp;
226 if (pdp) {
227 pdp->driContextPriv = pcp;
228 dri_get_drawable(pdp);
229 }
230 if (prp && pdp != prp) {
231 dri_get_drawable(prp);
232 }
233
234 /* Call device-specific MakeCurrent */
235 return driDriverAPI.MakeCurrent(pcp, pdp, prp);
236 }
237
238 static __DRIdrawable *
239 dri2CreateNewDrawable(__DRIscreen *screen,
240 const __DRIconfig *config,
241 void *loaderPrivate)
242 {
243 __DRIdrawable *pdraw;
244
245 pdraw = malloc(sizeof *pdraw);
246 if (!pdraw)
247 return NULL;
248
249 pdraw->driContextPriv = NULL;
250 pdraw->loaderPrivate = loaderPrivate;
251 pdraw->refcount = 1;
252 pdraw->lastStamp = 0;
253 pdraw->w = 0;
254 pdraw->h = 0;
255 pdraw->driScreenPriv = screen;
256
257 if (!driDriverAPI.CreateBuffer(screen, pdraw, &config->modes, 0)) {
258 free(pdraw);
259 return NULL;
260 }
261
262 pdraw->dri2.stamp = pdraw->lastStamp + 1;
263
264 return pdraw;
265 }
266
267 static __DRIbuffer *
268 dri2AllocateBuffer(__DRIscreen *screen,
269 unsigned int attachment, unsigned int format,
270 int width, int height)
271 {
272 return driDriverAPI.AllocateBuffer(screen, attachment, format,
273 width, height);
274 }
275
276 static void
277 dri2ReleaseBuffer(__DRIscreen *screen, __DRIbuffer *buffer)
278 {
279 driDriverAPI.ReleaseBuffer(screen, buffer);
280 }
281
282
283 static int
284 dri2ConfigQueryb(__DRIscreen *screen, const char *var, GLboolean *val)
285 {
286 if (!driCheckOption(&screen->optionCache, var, DRI_BOOL))
287 return -1;
288
289 *val = driQueryOptionb(&screen->optionCache, var);
290
291 return 0;
292 }
293
294 static int
295 dri2ConfigQueryi(__DRIscreen *screen, const char *var, GLint *val)
296 {
297 if (!driCheckOption(&screen->optionCache, var, DRI_INT) &&
298 !driCheckOption(&screen->optionCache, var, DRI_ENUM))
299 return -1;
300
301 *val = driQueryOptioni(&screen->optionCache, var);
302
303 return 0;
304 }
305
306 static int
307 dri2ConfigQueryf(__DRIscreen *screen, const char *var, GLfloat *val)
308 {
309 if (!driCheckOption(&screen->optionCache, var, DRI_FLOAT))
310 return -1;
311
312 *val = driQueryOptionf(&screen->optionCache, var);
313
314 return 0;
315 }
316
317
318 static void dri_get_drawable(__DRIdrawable *pdp)
319 {
320 pdp->refcount++;
321 }
322
323 static void dri_put_drawable(__DRIdrawable *pdp)
324 {
325 __DRIscreen *psp;
326
327 if (pdp) {
328 pdp->refcount--;
329 if (pdp->refcount)
330 return;
331
332 psp = pdp->driScreenPriv;
333 driDriverAPI.DestroyBuffer(pdp);
334 free(pdp);
335 }
336 }
337
338 static void
339 driDestroyDrawable(__DRIdrawable *pdp)
340 {
341 dri_put_drawable(pdp);
342 }
343
344 /*@}*/
345
346
347 /*****************************************************************/
348 /** \name Context handling functions */
349 /*****************************************************************/
350 /*@{*/
351
352 /**
353 * Destroy the per-context private information.
354 *
355 * \internal
356 * This function calls __DriverAPIRec::DestroyContext on \p contextPrivate, calls
357 * drmDestroyContext(), and finally frees \p contextPrivate.
358 */
359 static void
360 driDestroyContext(__DRIcontext *pcp)
361 {
362 if (pcp) {
363 driDriverAPI.DestroyContext(pcp);
364 free(pcp);
365 }
366 }
367
368 static unsigned int
369 dri2GetAPIMask(__DRIscreen *screen)
370 {
371 return screen->api_mask;
372 }
373
374 static __DRIcontext *
375 dri2CreateNewContextForAPI(__DRIscreen *screen, int api,
376 const __DRIconfig *config,
377 __DRIcontext *shared, void *data)
378 {
379 __DRIcontext *context;
380 const struct gl_config *modes = (config != NULL) ? &config->modes : NULL;
381 void *shareCtx = (shared != NULL) ? shared->driverPrivate : NULL;
382 gl_api mesa_api;
383
384 if (!(screen->api_mask & (1 << api)))
385 return NULL;
386
387 switch (api) {
388 case __DRI_API_OPENGL:
389 mesa_api = API_OPENGL;
390 break;
391 case __DRI_API_GLES:
392 mesa_api = API_OPENGLES;
393 break;
394 case __DRI_API_GLES2:
395 mesa_api = API_OPENGLES2;
396 break;
397 default:
398 return NULL;
399 }
400
401 context = malloc(sizeof *context);
402 if (!context)
403 return NULL;
404
405 context->driScreenPriv = screen;
406 context->driDrawablePriv = NULL;
407 context->loaderPrivate = data;
408
409 if (!driDriverAPI.CreateContext(mesa_api, modes,
410 context, shareCtx) ) {
411 free(context);
412 return NULL;
413 }
414
415 return context;
416 }
417
418
419 static __DRIcontext *
420 dri2CreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
421 __DRIcontext *shared, void *data)
422 {
423 return dri2CreateNewContextForAPI(screen, __DRI_API_OPENGL,
424 config, shared, data);
425 }
426
427 static int
428 driCopyContext(__DRIcontext *dest, __DRIcontext *src, unsigned long mask)
429 {
430 (void) dest;
431 (void) src;
432 (void) mask;
433 return GL_FALSE;
434 }
435
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 }