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