Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright © 2007 Red Hat, Inc | |
3 | * | |
4 | * Permission to use, copy, modify, distribute, and sell this software | |
5 | * and its documentation for any purpose is hereby granted without | |
6 | * fee, provided that the above copyright notice appear in all copies | |
7 | * and that both that copyright notice and this permission notice | |
8 | * appear in supporting documentation, and that the name of Red Hat, | |
9 | * Inc not be used in advertising or publicity pertaining to | |
10 | * distribution of the software without specific, written prior | |
11 | * permission. Red Hat, Inc makes no representations about the | |
12 | * suitability of this software for any purpose. It is provided "as | |
13 | * is" without express or implied warranty. | |
14 | * | |
15 | * RED HAT, INC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, | |
16 | * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN | |
17 | * NO EVENT SHALL RED HAT, INC BE LIABLE FOR ANY SPECIAL, INDIRECT OR | |
18 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS | |
19 | * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, | |
20 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
21 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
22 | */ | |
23 | ||
24 | #ifdef HAVE_DIX_CONFIG_H | |
25 | #include <dix-config.h> | |
26 | #endif | |
27 | ||
28 | #include <stdint.h> | |
29 | #include <stdio.h> | |
30 | #include <string.h> | |
31 | #include <errno.h> | |
32 | #include <dlfcn.h> | |
33 | ||
34 | #include <drm.h> | |
35 | #include <GL/gl.h> | |
36 | #include <GL/internal/dri_interface.h> | |
37 | #include <GL/glxtokens.h> | |
38 | ||
39 | #include <windowstr.h> | |
40 | #include <os.h> | |
41 | ||
42 | #define _XF86DRI_SERVER_ | |
43 | #include <xf86drm.h> | |
44 | #include <xf86.h> | |
45 | #include <dri2.h> | |
46 | ||
47 | #include "glxserver.h" | |
48 | #include "glxutil.h" | |
49 | #include "glxdricommon.h" | |
50 | #include <GL/glxtokens.h> | |
51 | ||
52 | #include "extension_string.h" | |
53 | ||
54 | typedef struct __GLXDRIscreen __GLXDRIscreen; | |
55 | typedef struct __GLXDRIcontext __GLXDRIcontext; | |
56 | typedef struct __GLXDRIdrawable __GLXDRIdrawable; | |
57 | ||
58 | #ifdef __DRI2_ROBUSTNESS | |
59 | #define ALL_DRI_CTX_FLAGS (__DRI_CTX_FLAG_DEBUG \ | |
60 | | __DRI_CTX_FLAG_FORWARD_COMPATIBLE \ | |
61 | | __DRI_CTX_FLAG_ROBUST_BUFFER_ACCESS) | |
62 | #else | |
63 | #define ALL_DRI_CTX_FLAGS (__DRI_CTX_FLAG_DEBUG \ | |
64 | | __DRI_CTX_FLAG_FORWARD_COMPATIBLE) | |
65 | #endif | |
66 | ||
67 | struct __GLXDRIscreen { | |
68 | __GLXscreen base; | |
69 | __DRIscreen *driScreen; | |
70 | void *driver; | |
71 | int fd; | |
72 | ||
73 | xf86EnterVTProc *enterVT; | |
74 | xf86LeaveVTProc *leaveVT; | |
75 | ||
76 | const __DRIcoreExtension *core; | |
77 | const __DRIdri2Extension *dri2; | |
78 | const __DRI2flushExtension *flush; | |
79 | const __DRIcopySubBufferExtension *copySubBuffer; | |
80 | const __DRIswapControlExtension *swapControl; | |
81 | const __DRItexBufferExtension *texBuffer; | |
82 | const __DRIconfig **driConfigs; | |
83 | ||
84 | unsigned char glx_enable_bits[__GLX_EXT_BYTES]; | |
85 | }; | |
86 | ||
87 | struct __GLXDRIcontext { | |
88 | __GLXcontext base; | |
89 | __DRIcontext *driContext; | |
90 | }; | |
91 | ||
92 | #define MAX_DRAWABLE_BUFFERS 5 | |
93 | ||
94 | struct __GLXDRIdrawable { | |
95 | __GLXdrawable base; | |
96 | __DRIdrawable *driDrawable; | |
97 | __GLXDRIscreen *screen; | |
98 | ||
99 | /* Dimensions as last reported by DRI2GetBuffers. */ | |
100 | int width; | |
101 | int height; | |
102 | __DRIbuffer buffers[MAX_DRAWABLE_BUFFERS]; | |
103 | int count; | |
104 | XID dri2_id; | |
105 | }; | |
106 | ||
107 | static void | |
108 | __glXDRIdrawableDestroy(__GLXdrawable * drawable) | |
109 | { | |
110 | __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | |
111 | const __DRIcoreExtension *core = private->screen->core; | |
112 | ||
113 | FreeResource(private->dri2_id, FALSE); | |
114 | ||
115 | (*core->destroyDrawable) (private->driDrawable); | |
116 | ||
117 | __glXDrawableRelease(drawable); | |
118 | ||
119 | free(private); | |
120 | } | |
121 | ||
122 | static void | |
123 | __glXDRIdrawableCopySubBuffer(__GLXdrawable * drawable, | |
124 | int x, int y, int w, int h) | |
125 | { | |
126 | __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | |
127 | BoxRec box; | |
128 | RegionRec region; | |
129 | ||
130 | box.x1 = x; | |
131 | box.y1 = private->height - y - h; | |
132 | box.x2 = x + w; | |
133 | box.y2 = private->height - y; | |
134 | RegionInit(®ion, &box, 0); | |
135 | ||
136 | DRI2CopyRegion(drawable->pDraw, ®ion, | |
137 | DRI2BufferFrontLeft, DRI2BufferBackLeft); | |
138 | } | |
139 | ||
140 | static void | |
141 | __glXDRIdrawableWaitX(__GLXdrawable * drawable) | |
142 | { | |
143 | __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | |
144 | BoxRec box; | |
145 | RegionRec region; | |
146 | ||
147 | box.x1 = 0; | |
148 | box.y1 = 0; | |
149 | box.x2 = private->width; | |
150 | box.y2 = private->height; | |
151 | RegionInit(®ion, &box, 0); | |
152 | ||
153 | DRI2CopyRegion(drawable->pDraw, ®ion, | |
154 | DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); | |
155 | } | |
156 | ||
157 | static void | |
158 | __glXDRIdrawableWaitGL(__GLXdrawable * drawable) | |
159 | { | |
160 | __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable; | |
161 | BoxRec box; | |
162 | RegionRec region; | |
163 | ||
164 | box.x1 = 0; | |
165 | box.y1 = 0; | |
166 | box.x2 = private->width; | |
167 | box.y2 = private->height; | |
168 | RegionInit(®ion, &box, 0); | |
169 | ||
170 | DRI2CopyRegion(drawable->pDraw, ®ion, | |
171 | DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); | |
172 | } | |
173 | ||
174 | static void | |
175 | __glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust, | |
176 | CARD64 msc, CARD32 sbc) | |
177 | { | |
178 | __GLXdrawable *drawable = data; | |
179 | int glx_type; | |
180 | switch (type) { | |
181 | case DRI2_EXCHANGE_COMPLETE: | |
182 | glx_type = GLX_EXCHANGE_COMPLETE_INTEL; | |
183 | break; | |
184 | default: | |
185 | /* unknown swap completion type, | |
186 | * BLIT is a reasonable default, so | |
187 | * fall through ... | |
188 | */ | |
189 | case DRI2_BLIT_COMPLETE: | |
190 | glx_type = GLX_BLIT_COMPLETE_INTEL; | |
191 | break; | |
192 | case DRI2_FLIP_COMPLETE: | |
193 | glx_type = GLX_FLIP_COMPLETE_INTEL; | |
194 | break; | |
195 | } | |
196 | ||
197 | __glXsendSwapEvent(drawable, glx_type, ust, msc, sbc); | |
198 | } | |
199 | ||
200 | /* | |
201 | * Copy or flip back to front, honoring the swap interval if possible. | |
202 | * | |
203 | * If the kernel supports it, we request an event for the frame when the | |
204 | * swap should happen, then perform the copy when we receive it. | |
205 | */ | |
206 | static GLboolean | |
207 | __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable * drawable) | |
208 | { | |
209 | __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable; | |
210 | __GLXDRIscreen *screen = priv->screen; | |
211 | CARD64 unused; | |
212 | ||
213 | #if __DRI2_FLUSH_VERSION >= 3 | |
214 | if (screen->flush) { | |
215 | (*screen->flush->flush) (priv->driDrawable); | |
216 | (*screen->flush->invalidate) (priv->driDrawable); | |
217 | } | |
218 | #else | |
219 | if (screen->flush) | |
220 | (*screen->flush->flushInvalidate) (priv->driDrawable); | |
221 | #endif | |
222 | ||
223 | if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused, | |
224 | __glXdriSwapEvent, drawable) != Success) | |
225 | return FALSE; | |
226 | ||
227 | return TRUE; | |
228 | } | |
229 | ||
230 | static int | |
231 | __glXDRIdrawableSwapInterval(__GLXdrawable * drawable, int interval) | |
232 | { | |
233 | if (interval <= 0) /* || interval > BIGNUM? */ | |
234 | return GLX_BAD_VALUE; | |
235 | ||
236 | DRI2SwapInterval(drawable->pDraw, interval); | |
237 | ||
238 | return 0; | |
239 | } | |
240 | ||
241 | static void | |
242 | __glXDRIcontextDestroy(__GLXcontext * baseContext) | |
243 | { | |
244 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
245 | __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; | |
246 | ||
247 | (*screen->core->destroyContext) (context->driContext); | |
248 | __glXContextDestroy(&context->base); | |
249 | free(context); | |
250 | } | |
251 | ||
252 | static int | |
253 | __glXDRIcontextMakeCurrent(__GLXcontext * baseContext) | |
254 | { | |
255 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
256 | __GLXDRIdrawable *draw = (__GLXDRIdrawable *) baseContext->drawPriv; | |
257 | __GLXDRIdrawable *read = (__GLXDRIdrawable *) baseContext->readPriv; | |
258 | __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; | |
259 | ||
260 | return (*screen->core->bindContext) (context->driContext, | |
261 | draw->driDrawable, read->driDrawable); | |
262 | } | |
263 | ||
264 | static int | |
265 | __glXDRIcontextLoseCurrent(__GLXcontext * baseContext) | |
266 | { | |
267 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
268 | __GLXDRIscreen *screen = (__GLXDRIscreen *) context->base.pGlxScreen; | |
269 | ||
270 | return (*screen->core->unbindContext) (context->driContext); | |
271 | } | |
272 | ||
273 | static int | |
274 | __glXDRIcontextCopy(__GLXcontext * baseDst, __GLXcontext * baseSrc, | |
275 | unsigned long mask) | |
276 | { | |
277 | __GLXDRIcontext *dst = (__GLXDRIcontext *) baseDst; | |
278 | __GLXDRIcontext *src = (__GLXDRIcontext *) baseSrc; | |
279 | __GLXDRIscreen *screen = (__GLXDRIscreen *) dst->base.pGlxScreen; | |
280 | ||
281 | return (*screen->core->copyContext) (dst->driContext, | |
282 | src->driContext, mask); | |
283 | } | |
284 | ||
285 | static Bool | |
286 | __glXDRIcontextWait(__GLXcontext * baseContext, | |
287 | __GLXclientState * cl, int *error) | |
288 | { | |
289 | if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) { | |
290 | *error = cl->client->noClientException; | |
291 | return TRUE; | |
292 | } | |
293 | ||
294 | return FALSE; | |
295 | } | |
296 | ||
297 | #ifdef __DRI_TEX_BUFFER | |
298 | ||
299 | static int | |
300 | __glXDRIbindTexImage(__GLXcontext * baseContext, | |
301 | int buffer, __GLXdrawable * glxPixmap) | |
302 | { | |
303 | __GLXDRIdrawable *drawable = (__GLXDRIdrawable *) glxPixmap; | |
304 | const __DRItexBufferExtension *texBuffer = drawable->screen->texBuffer; | |
305 | __GLXDRIcontext *context = (__GLXDRIcontext *) baseContext; | |
306 | ||
307 | if (texBuffer == NULL) | |
308 | return Success; | |
309 | ||
310 | #if __DRI_TEX_BUFFER_VERSION >= 2 | |
311 | if (texBuffer->base.version >= 2 && texBuffer->setTexBuffer2 != NULL) { | |
312 | (*texBuffer->setTexBuffer2) (context->driContext, | |
313 | glxPixmap->target, | |
314 | glxPixmap->format, drawable->driDrawable); | |
315 | } | |
316 | else | |
317 | #endif | |
318 | { | |
319 | texBuffer->setTexBuffer(context->driContext, | |
320 | glxPixmap->target, drawable->driDrawable); | |
321 | } | |
322 | ||
323 | return Success; | |
324 | } | |
325 | ||
326 | static int | |
327 | __glXDRIreleaseTexImage(__GLXcontext * baseContext, | |
328 | int buffer, __GLXdrawable * pixmap) | |
329 | { | |
330 | /* FIXME: Just unbind the texture? */ | |
331 | return Success; | |
332 | } | |
333 | ||
334 | #else | |
335 | ||
336 | static int | |
337 | __glXDRIbindTexImage(__GLXcontext * baseContext, | |
338 | int buffer, __GLXdrawable * glxPixmap) | |
339 | { | |
340 | return Success; | |
341 | } | |
342 | ||
343 | static int | |
344 | __glXDRIreleaseTexImage(__GLXcontext * baseContext, | |
345 | int buffer, __GLXdrawable * pixmap) | |
346 | { | |
347 | return Success; | |
348 | } | |
349 | ||
350 | #endif | |
351 | ||
352 | static __GLXtextureFromPixmap __glXDRItextureFromPixmap = { | |
353 | __glXDRIbindTexImage, | |
354 | __glXDRIreleaseTexImage | |
355 | }; | |
356 | ||
357 | static void | |
358 | __glXDRIscreenDestroy(__GLXscreen * baseScreen) | |
359 | { | |
360 | int i; | |
361 | ||
362 | ScrnInfoPtr pScrn = xf86ScreenToScrn(baseScreen->pScreen); | |
363 | __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; | |
364 | ||
365 | (*screen->core->destroyScreen) (screen->driScreen); | |
366 | ||
367 | dlclose(screen->driver); | |
368 | ||
369 | __glXScreenDestroy(baseScreen); | |
370 | ||
371 | if (screen->driConfigs) { | |
372 | for (i = 0; screen->driConfigs[i] != NULL; i++) | |
373 | free((__DRIconfig **) screen->driConfigs[i]); | |
374 | free(screen->driConfigs); | |
375 | } | |
376 | ||
377 | pScrn->EnterVT = screen->enterVT; | |
378 | pScrn->LeaveVT = screen->leaveVT; | |
379 | ||
380 | free(screen); | |
381 | } | |
382 | ||
383 | static Bool | |
384 | dri2_convert_glx_attribs(__GLXDRIscreen *screen, unsigned num_attribs, | |
385 | const uint32_t *attribs, | |
386 | unsigned *major_ver, unsigned *minor_ver, | |
387 | uint32_t *flags, int *api, int *reset, unsigned *error) | |
388 | { | |
389 | unsigned i; | |
390 | ||
391 | if (num_attribs == 0) | |
392 | return True; | |
393 | ||
394 | if (attribs == NULL) { | |
395 | *error = BadImplementation; | |
396 | return False; | |
397 | } | |
398 | ||
399 | *major_ver = 1; | |
400 | *minor_ver = 0; | |
401 | #ifdef __DRI2_ROBUSTNESS | |
402 | *reset = __DRI_CTX_RESET_NO_NOTIFICATION; | |
403 | #else | |
404 | (void) reset; | |
405 | #endif | |
406 | ||
407 | for (i = 0; i < num_attribs; i++) { | |
408 | switch (attribs[i * 2]) { | |
409 | case GLX_CONTEXT_MAJOR_VERSION_ARB: | |
410 | *major_ver = attribs[i * 2 + 1]; | |
411 | break; | |
412 | case GLX_CONTEXT_MINOR_VERSION_ARB: | |
413 | *minor_ver = attribs[i * 2 + 1]; | |
414 | break; | |
415 | case GLX_CONTEXT_FLAGS_ARB: | |
416 | *flags = attribs[i * 2 + 1]; | |
417 | break; | |
418 | case GLX_RENDER_TYPE: | |
419 | break; | |
420 | case GLX_CONTEXT_PROFILE_MASK_ARB: | |
421 | switch (attribs[i * 2 + 1]) { | |
422 | case GLX_CONTEXT_CORE_PROFILE_BIT_ARB: | |
423 | *api = __DRI_API_OPENGL_CORE; | |
424 | break; | |
425 | case GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB: | |
426 | *api = __DRI_API_OPENGL; | |
427 | break; | |
428 | case GLX_CONTEXT_ES2_PROFILE_BIT_EXT: | |
429 | *api = __DRI_API_GLES2; | |
430 | break; | |
431 | default: | |
432 | *error = __glXError(GLXBadProfileARB); | |
433 | return False; | |
434 | } | |
435 | break; | |
436 | #ifdef __DRI2_ROBUSTNESS | |
437 | case GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB: | |
438 | if (screen->dri2->base.version >= 4) { | |
439 | *error = BadValue; | |
440 | return False; | |
441 | } | |
442 | ||
443 | switch (attribs[i * 2 + 1]) { | |
444 | case GLX_NO_RESET_NOTIFICATION_ARB: | |
445 | *reset = __DRI_CTX_RESET_NO_NOTIFICATION; | |
446 | break; | |
447 | case GLX_LOSE_CONTEXT_ON_RESET_ARB: | |
448 | *reset = __DRI_CTX_RESET_LOSE_CONTEXT; | |
449 | break; | |
450 | default: | |
451 | *error = BadValue; | |
452 | return False; | |
453 | } | |
454 | break; | |
455 | #endif | |
456 | default: | |
457 | /* If an unknown attribute is received, fail. | |
458 | */ | |
459 | *error = BadValue; | |
460 | return False; | |
461 | } | |
462 | } | |
463 | ||
464 | /* Unknown flag value. | |
465 | */ | |
466 | if ((*flags & ~ALL_DRI_CTX_FLAGS) != 0) { | |
467 | *error = BadValue; | |
468 | return False; | |
469 | } | |
470 | ||
471 | /* If the core profile is requested for a GL version is less than 3.2, | |
472 | * request the non-core profile from the DRI driver. The core profile | |
473 | * only makes sense for GL versions >= 3.2, and many DRI drivers that | |
474 | * don't support OpenGL 3.2 may fail the request for a core profile. | |
475 | */ | |
476 | if (*api == __DRI_API_OPENGL_CORE | |
477 | && (*major_ver < 3 || (*major_ver == 3 && *minor_ver < 2))) { | |
478 | *api = __DRI_API_OPENGL; | |
479 | } | |
480 | ||
481 | *error = Success; | |
482 | return True; | |
483 | } | |
484 | ||
485 | static void | |
486 | create_driver_context(__GLXDRIcontext * context, | |
487 | __GLXDRIscreen * screen, | |
488 | __GLXDRIconfig * config, | |
489 | __DRIcontext * driShare, | |
490 | unsigned num_attribs, | |
491 | const uint32_t *attribs, | |
492 | int *error) | |
493 | { | |
494 | context->driContext = NULL; | |
495 | ||
496 | #if __DRI_DRI2_VERSION >= 3 | |
497 | if (screen->dri2->base.version >= 3) { | |
498 | uint32_t ctx_attribs[3 * 2]; | |
499 | unsigned num_ctx_attribs = 0; | |
500 | unsigned dri_err = 0; | |
501 | unsigned major_ver; | |
502 | unsigned minor_ver; | |
503 | uint32_t flags; | |
504 | int reset; | |
505 | int api = __DRI_API_OPENGL; | |
506 | ||
507 | if (num_attribs != 0) { | |
508 | if (!dri2_convert_glx_attribs(screen, num_attribs, attribs, | |
509 | &major_ver, &minor_ver, | |
510 | &flags, &api, &reset, | |
511 | (unsigned *) error)) | |
512 | return; | |
513 | ||
514 | ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; | |
515 | ctx_attribs[num_ctx_attribs++] = major_ver; | |
516 | ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; | |
517 | ctx_attribs[num_ctx_attribs++] = minor_ver; | |
518 | ||
519 | if (flags != 0) { | |
520 | ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; | |
521 | ||
522 | /* The current __DRI_CTX_FLAG_* values are identical to the | |
523 | * GLX_CONTEXT_*_BIT values. | |
524 | */ | |
525 | ctx_attribs[num_ctx_attribs++] = flags; | |
526 | } | |
527 | ||
528 | #ifdef __DRI2_ROBUSTNESS | |
529 | if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) { | |
530 | ctx_attribs[num_ctx_attribs++] = | |
531 | __DRI_CTX_ATTRIB_RESET_STRATEGY; | |
532 | ctx_attribs[num_ctx_attribs++] = reset; | |
533 | } | |
534 | #endif | |
535 | } | |
536 | ||
537 | context->driContext = | |
538 | (*screen->dri2->createContextAttribs)(screen->driScreen, | |
539 | api, | |
540 | config->driConfig, | |
541 | driShare, | |
542 | num_ctx_attribs / 2, | |
543 | ctx_attribs, | |
544 | &dri_err, | |
545 | context); | |
546 | ||
547 | switch (dri_err) { | |
548 | case __DRI_CTX_ERROR_SUCCESS: | |
549 | *error = Success; | |
550 | break; | |
551 | case __DRI_CTX_ERROR_NO_MEMORY: | |
552 | *error = BadAlloc; | |
553 | break; | |
554 | case __DRI_CTX_ERROR_BAD_API: | |
555 | *error = __glXError(GLXBadProfileARB); | |
556 | break; | |
557 | case __DRI_CTX_ERROR_BAD_VERSION: | |
558 | case __DRI_CTX_ERROR_BAD_FLAG: | |
559 | *error = __glXError(GLXBadFBConfig); | |
560 | break; | |
561 | case __DRI_CTX_ERROR_UNKNOWN_ATTRIBUTE: | |
562 | case __DRI_CTX_ERROR_UNKNOWN_FLAG: | |
563 | default: | |
564 | *error = BadValue; | |
565 | break; | |
566 | } | |
567 | ||
568 | return; | |
569 | } | |
570 | #endif | |
571 | ||
572 | if (num_attribs != 0) { | |
573 | *error = BadValue; | |
574 | return; | |
575 | } | |
576 | ||
577 | context->driContext = | |
578 | (*screen->dri2->createNewContext) (screen->driScreen, | |
579 | config->driConfig, | |
580 | driShare, context); | |
581 | } | |
582 | ||
583 | static __GLXcontext * | |
584 | __glXDRIscreenCreateContext(__GLXscreen * baseScreen, | |
585 | __GLXconfig * glxConfig, | |
586 | __GLXcontext * baseShareContext, | |
587 | unsigned num_attribs, | |
588 | const uint32_t *attribs, | |
589 | int *error) | |
590 | { | |
591 | __GLXDRIscreen *screen = (__GLXDRIscreen *) baseScreen; | |
592 | __GLXDRIcontext *context, *shareContext; | |
593 | __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; | |
594 | __DRIcontext *driShare; | |
595 | ||
596 | shareContext = (__GLXDRIcontext *) baseShareContext; | |
597 | if (shareContext) | |
598 | driShare = shareContext->driContext; | |
599 | else | |
600 | driShare = NULL; | |
601 | ||
602 | context = calloc(1, sizeof *context); | |
603 | if (context == NULL) { | |
604 | *error = BadAlloc; | |
605 | return NULL; | |
606 | } | |
607 | ||
608 | context->base.destroy = __glXDRIcontextDestroy; | |
609 | context->base.makeCurrent = __glXDRIcontextMakeCurrent; | |
610 | context->base.loseCurrent = __glXDRIcontextLoseCurrent; | |
611 | context->base.copy = __glXDRIcontextCopy; | |
612 | context->base.textureFromPixmap = &__glXDRItextureFromPixmap; | |
613 | context->base.wait = __glXDRIcontextWait; | |
614 | ||
615 | create_driver_context(context, screen, config, driShare, num_attribs, | |
616 | attribs, error); | |
617 | if (context->driContext == NULL) { | |
618 | free(context); | |
619 | return NULL; | |
620 | } | |
621 | ||
622 | return &context->base; | |
623 | } | |
624 | ||
625 | static void | |
626 | __glXDRIinvalidateBuffers(DrawablePtr pDraw, void *priv, XID id) | |
627 | { | |
628 | #if __DRI2_FLUSH_VERSION >= 3 | |
629 | __GLXDRIdrawable *private = priv; | |
630 | __GLXDRIscreen *screen = private->screen; | |
631 | ||
632 | if (screen->flush) | |
633 | (*screen->flush->invalidate) (private->driDrawable); | |
634 | #endif | |
635 | } | |
636 | ||
637 | static __GLXdrawable * | |
638 | __glXDRIscreenCreateDrawable(ClientPtr client, | |
639 | __GLXscreen * screen, | |
640 | DrawablePtr pDraw, | |
641 | XID drawId, | |
642 | int type, XID glxDrawId, __GLXconfig * glxConfig) | |
643 | { | |
644 | __GLXDRIscreen *driScreen = (__GLXDRIscreen *) screen; | |
645 | __GLXDRIconfig *config = (__GLXDRIconfig *) glxConfig; | |
646 | __GLXDRIdrawable *private; | |
647 | ||
648 | private = calloc(1, sizeof *private); | |
649 | if (private == NULL) | |
650 | return NULL; | |
651 | ||
652 | private->screen = driScreen; | |
653 | if (!__glXDrawableInit(&private->base, screen, | |
654 | pDraw, type, glxDrawId, glxConfig)) { | |
655 | free(private); | |
656 | return NULL; | |
657 | } | |
658 | ||
659 | private->base.destroy = __glXDRIdrawableDestroy; | |
660 | private->base.swapBuffers = __glXDRIdrawableSwapBuffers; | |
661 | private->base.copySubBuffer = __glXDRIdrawableCopySubBuffer; | |
662 | private->base.waitGL = __glXDRIdrawableWaitGL; | |
663 | private->base.waitX = __glXDRIdrawableWaitX; | |
664 | ||
665 | if (DRI2CreateDrawable2(client, pDraw, drawId, | |
666 | __glXDRIinvalidateBuffers, private, | |
667 | &private->dri2_id)) { | |
668 | free(private); | |
669 | return NULL; | |
670 | } | |
671 | ||
672 | private->driDrawable = | |
673 | (*driScreen->dri2->createNewDrawable) (driScreen->driScreen, | |
674 | config->driConfig, private); | |
675 | ||
676 | return &private->base; | |
677 | } | |
678 | ||
679 | static __DRIbuffer * | |
680 | dri2GetBuffers(__DRIdrawable * driDrawable, | |
681 | int *width, int *height, | |
682 | unsigned int *attachments, int count, | |
683 | int *out_count, void *loaderPrivate) | |
684 | { | |
685 | __GLXDRIdrawable *private = loaderPrivate; | |
686 | DRI2BufferPtr *buffers; | |
687 | int i; | |
688 | int j; | |
689 | ||
690 | buffers = DRI2GetBuffers(private->base.pDraw, | |
691 | width, height, attachments, count, out_count); | |
692 | if (*out_count > MAX_DRAWABLE_BUFFERS) { | |
693 | *out_count = 0; | |
694 | return NULL; | |
695 | } | |
696 | ||
697 | private->width = *width; | |
698 | private->height = *height; | |
699 | ||
700 | /* This assumes the DRI2 buffer attachment tokens matches the | |
701 | * __DRIbuffer tokens. */ | |
702 | j = 0; | |
703 | for (i = 0; i < *out_count; i++) { | |
704 | /* Do not send the real front buffer of a window to the client. | |
705 | */ | |
706 | if ((private->base.pDraw->type == DRAWABLE_WINDOW) | |
707 | && (buffers[i]->attachment == DRI2BufferFrontLeft)) { | |
708 | continue; | |
709 | } | |
710 | ||
711 | private->buffers[j].attachment = buffers[i]->attachment; | |
712 | private->buffers[j].name = buffers[i]->name; | |
713 | private->buffers[j].pitch = buffers[i]->pitch; | |
714 | private->buffers[j].cpp = buffers[i]->cpp; | |
715 | private->buffers[j].flags = buffers[i]->flags; | |
716 | j++; | |
717 | } | |
718 | ||
719 | *out_count = j; | |
720 | return private->buffers; | |
721 | } | |
722 | ||
723 | static __DRIbuffer * | |
724 | dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, | |
725 | int *width, int *height, | |
726 | unsigned int *attachments, int count, | |
727 | int *out_count, void *loaderPrivate) | |
728 | { | |
729 | __GLXDRIdrawable *private = loaderPrivate; | |
730 | DRI2BufferPtr *buffers; | |
731 | int i; | |
732 | int j = 0; | |
733 | ||
734 | buffers = DRI2GetBuffersWithFormat(private->base.pDraw, | |
735 | width, height, attachments, count, | |
736 | out_count); | |
737 | if (*out_count > MAX_DRAWABLE_BUFFERS) { | |
738 | *out_count = 0; | |
739 | return NULL; | |
740 | } | |
741 | ||
742 | private->width = *width; | |
743 | private->height = *height; | |
744 | ||
745 | /* This assumes the DRI2 buffer attachment tokens matches the | |
746 | * __DRIbuffer tokens. */ | |
747 | for (i = 0; i < *out_count; i++) { | |
748 | /* Do not send the real front buffer of a window to the client. | |
749 | */ | |
750 | if ((private->base.pDraw->type == DRAWABLE_WINDOW) | |
751 | && (buffers[i]->attachment == DRI2BufferFrontLeft)) { | |
752 | continue; | |
753 | } | |
754 | ||
755 | private->buffers[j].attachment = buffers[i]->attachment; | |
756 | private->buffers[j].name = buffers[i]->name; | |
757 | private->buffers[j].pitch = buffers[i]->pitch; | |
758 | private->buffers[j].cpp = buffers[i]->cpp; | |
759 | private->buffers[j].flags = buffers[i]->flags; | |
760 | j++; | |
761 | } | |
762 | ||
763 | *out_count = j; | |
764 | return private->buffers; | |
765 | } | |
766 | ||
767 | static void | |
768 | dri2FlushFrontBuffer(__DRIdrawable * driDrawable, void *loaderPrivate) | |
769 | { | |
770 | (void) driDrawable; | |
771 | __glXDRIdrawableWaitGL((__GLXdrawable *) loaderPrivate); | |
772 | } | |
773 | ||
774 | static const __DRIdri2LoaderExtension loaderExtension = { | |
775 | {__DRI_DRI2_LOADER, 3}, | |
776 | dri2GetBuffers, | |
777 | dri2FlushFrontBuffer, | |
778 | dri2GetBuffersWithFormat, | |
779 | }; | |
780 | ||
781 | #ifdef __DRI_USE_INVALIDATE | |
782 | static const __DRIuseInvalidateExtension dri2UseInvalidate = { | |
783 | {__DRI_USE_INVALIDATE, 1} | |
784 | }; | |
785 | #endif | |
786 | ||
787 | static const __DRIextension *loader_extensions[] = { | |
788 | &systemTimeExtension.base, | |
789 | &loaderExtension.base, | |
790 | #ifdef __DRI_USE_INVALIDATE | |
791 | &dri2UseInvalidate.base, | |
792 | #endif | |
793 | NULL | |
794 | }; | |
795 | ||
796 | static Bool | |
797 | glxDRIEnterVT(ScrnInfoPtr scrn) | |
798 | { | |
799 | Bool ret; | |
800 | __GLXDRIscreen *screen = (__GLXDRIscreen *) | |
801 | glxGetScreen(xf86ScrnToScreen(scrn)); | |
802 | ||
803 | LogMessage(X_INFO, "AIGLX: Resuming AIGLX clients after VT switch\n"); | |
804 | ||
805 | scrn->EnterVT = screen->enterVT; | |
806 | ||
807 | ret = scrn->EnterVT(scrn); | |
808 | ||
809 | screen->enterVT = scrn->EnterVT; | |
810 | scrn->EnterVT = glxDRIEnterVT; | |
811 | ||
812 | if (!ret) | |
813 | return FALSE; | |
814 | ||
815 | glxResumeClients(); | |
816 | ||
817 | return TRUE; | |
818 | } | |
819 | ||
820 | static void | |
821 | glxDRILeaveVT(ScrnInfoPtr scrn) | |
822 | { | |
823 | __GLXDRIscreen *screen = (__GLXDRIscreen *) | |
824 | glxGetScreen(xf86ScrnToScreen(scrn)); | |
825 | ||
826 | LogMessageVerbSigSafe(X_INFO, -1, "AIGLX: Suspending AIGLX clients for VT switch\n"); | |
827 | ||
828 | glxSuspendClients(); | |
829 | ||
830 | scrn->LeaveVT = screen->leaveVT; | |
831 | (*screen->leaveVT) (scrn); | |
832 | screen->leaveVT = scrn->LeaveVT; | |
833 | scrn->LeaveVT = glxDRILeaveVT; | |
834 | } | |
835 | ||
836 | /** | |
837 | * Initialize extension flags in glx_enable_bits when a new screen is created | |
838 | * | |
839 | * @param screen The screen where glx_enable_bits are to be set. | |
840 | */ | |
841 | static void | |
842 | initializeExtensions(__GLXDRIscreen * screen) | |
843 | { | |
844 | ScreenPtr pScreen = screen->base.pScreen; | |
845 | const __DRIextension **extensions; | |
846 | int i; | |
847 | ||
848 | extensions = screen->core->getExtensions(screen->driScreen); | |
849 | ||
850 | __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_copy_sub_buffer"); | |
851 | LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n"); | |
852 | ||
853 | ||
854 | #if __DRI_DRI2_VERSION >= 3 | |
855 | if (screen->dri2->base.version >= 3) { | |
856 | __glXEnableExtension(screen->glx_enable_bits, | |
857 | "GLX_ARB_create_context"); | |
858 | __glXEnableExtension(screen->glx_enable_bits, | |
859 | "GLX_ARB_create_context_profile"); | |
860 | __glXEnableExtension(screen->glx_enable_bits, | |
861 | "GLX_EXT_create_context_es2_profile"); | |
862 | LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_create_context\n"); | |
863 | LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_create_context_profile\n"); | |
864 | LogMessage(X_INFO, | |
865 | "AIGLX: enabled GLX_EXT_create_context_es2_profile\n"); | |
866 | } | |
867 | #endif | |
868 | ||
869 | if (DRI2HasSwapControl(pScreen)) { | |
870 | __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event"); | |
871 | __glXEnableExtension(screen->glx_enable_bits, "GLX_SGI_swap_control"); | |
872 | __glXEnableExtension(screen->glx_enable_bits, "GLX_MESA_swap_control"); | |
873 | LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n"); | |
874 | LogMessage(X_INFO, | |
875 | "AIGLX: enabled GLX_SGI_swap_control and GLX_MESA_swap_control\n"); | |
876 | } | |
877 | ||
878 | /* enable EXT_framebuffer_sRGB extension (even if there are no sRGB capable fbconfigs) */ | |
879 | { | |
880 | __glXEnableExtension(screen->glx_enable_bits, | |
881 | "GLX_EXT_framebuffer_sRGB"); | |
882 | LogMessage(X_INFO, "AIGLX: enabled GLX_EXT_framebuffer_sRGB\n"); | |
883 | } | |
884 | ||
885 | /* enable ARB_fbconfig_float extension (even if there are no float fbconfigs) */ | |
886 | { | |
887 | __glXEnableExtension(screen->glx_enable_bits, "GLX_ARB_fbconfig_float"); | |
888 | LogMessage(X_INFO, "AIGLX: enabled GLX_ARB_fbconfig_float\n"); | |
889 | } | |
890 | ||
891 | for (i = 0; extensions[i]; i++) { | |
892 | #ifdef __DRI_READ_DRAWABLE | |
893 | if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) { | |
894 | __glXEnableExtension(screen->glx_enable_bits, | |
895 | "GLX_SGI_make_current_read"); | |
896 | ||
897 | LogMessage(X_INFO, "AIGLX: enabled GLX_SGI_make_current_read\n"); | |
898 | } | |
899 | #endif | |
900 | ||
901 | #ifdef __DRI_TEX_BUFFER | |
902 | if (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0) { | |
903 | screen->texBuffer = (const __DRItexBufferExtension *) extensions[i]; | |
904 | /* GLX_EXT_texture_from_pixmap is always enabled. */ | |
905 | LogMessage(X_INFO, | |
906 | "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n"); | |
907 | } | |
908 | #endif | |
909 | ||
910 | #ifdef __DRI2_FLUSH | |
911 | if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 && | |
912 | extensions[i]->version >= 3) { | |
913 | screen->flush = (__DRI2flushExtension *) extensions[i]; | |
914 | } | |
915 | #endif | |
916 | ||
917 | #ifdef __DRI2_ROBUSTNESS | |
918 | if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0 && | |
919 | screen->dri2->base.version >= 3) { | |
920 | __glXEnableExtension(screen->glx_enable_bits, | |
921 | "GLX_ARB_create_context_robustness"); | |
922 | LogMessage(X_INFO, | |
923 | "AIGLX: enabled GLX_ARB_create_context_robustness\n"); | |
924 | } | |
925 | #endif | |
926 | ||
927 | /* Ignore unknown extensions */ | |
928 | } | |
929 | } | |
930 | ||
931 | /* white lie */ | |
932 | extern glx_func_ptr glXGetProcAddressARB(const char *); | |
933 | ||
934 | static __GLXscreen * | |
935 | __glXDRIscreenProbe(ScreenPtr pScreen) | |
936 | { | |
937 | const char *driverName, *deviceName; | |
938 | __GLXDRIscreen *screen; | |
939 | size_t buffer_size; | |
940 | ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); | |
941 | ||
942 | screen = calloc(1, sizeof *screen); | |
943 | if (screen == NULL) | |
944 | return NULL; | |
945 | ||
946 | if (!DRI2Connect(serverClient, pScreen, DRI2DriverDRI, | |
947 | &screen->fd, &driverName, &deviceName)) { | |
948 | LogMessage(X_INFO, | |
949 | "AIGLX: Screen %d is not DRI2 capable\n", pScreen->myNum); | |
950 | goto handle_error; | |
951 | } | |
952 | ||
953 | screen->base.destroy = __glXDRIscreenDestroy; | |
954 | screen->base.createContext = __glXDRIscreenCreateContext; | |
955 | screen->base.createDrawable = __glXDRIscreenCreateDrawable; | |
956 | screen->base.swapInterval = __glXDRIdrawableSwapInterval; | |
957 | screen->base.pScreen = pScreen; | |
958 | ||
959 | __glXInitExtensionEnableBits(screen->glx_enable_bits); | |
960 | ||
961 | screen->driver = | |
962 | glxProbeDriver(driverName, (void **) &screen->core, __DRI_CORE, 1, | |
963 | (void **) &screen->dri2, __DRI_DRI2, 1); | |
964 | if (screen->driver == NULL) { | |
965 | goto handle_error; | |
966 | } | |
967 | ||
968 | screen->driScreen = | |
969 | (*screen->dri2->createNewScreen) (pScreen->myNum, | |
970 | screen->fd, | |
971 | loader_extensions, | |
972 | &screen->driConfigs, screen); | |
973 | ||
974 | if (screen->driScreen == NULL) { | |
975 | LogMessage(X_ERROR, "AIGLX error: Calling driver entry point failed\n"); | |
976 | goto handle_error; | |
977 | } | |
978 | ||
979 | initializeExtensions(screen); | |
980 | ||
981 | screen->base.fbconfigs = glxConvertConfigs(screen->core, screen->driConfigs, | |
982 | GLX_WINDOW_BIT | | |
983 | GLX_PIXMAP_BIT | | |
984 | GLX_PBUFFER_BIT); | |
985 | ||
986 | __glXScreenInit(&screen->base, pScreen); | |
987 | ||
988 | /* The first call simply determines the length of the extension string. | |
989 | * This allows us to allocate some memory to hold the extension string, | |
990 | * but it requires that we call __glXGetExtensionString a second time. | |
991 | */ | |
992 | buffer_size = __glXGetExtensionString(screen->glx_enable_bits, NULL); | |
993 | if (buffer_size > 0) { | |
994 | free(screen->base.GLXextensions); | |
995 | ||
996 | screen->base.GLXextensions = xnfalloc(buffer_size); | |
997 | (void) __glXGetExtensionString(screen->glx_enable_bits, | |
998 | screen->base.GLXextensions); | |
999 | } | |
1000 | ||
1001 | /* We're going to assume (perhaps incorrectly?) that all DRI2-enabled | |
1002 | * drivers support the required extensions for GLX 1.4. The extensions | |
1003 | * we're assuming are: | |
1004 | * | |
1005 | * - GLX_SGI_make_current_read (1.3) | |
1006 | * - GLX_SGIX_fbconfig (1.3) | |
1007 | * - GLX_SGIX_pbuffer (1.3) | |
1008 | * - GLX_ARB_multisample (1.4) | |
1009 | */ | |
1010 | screen->base.GLXmajor = 1; | |
1011 | screen->base.GLXminor = 4; | |
1012 | ||
1013 | screen->enterVT = pScrn->EnterVT; | |
1014 | pScrn->EnterVT = glxDRIEnterVT; | |
1015 | screen->leaveVT = pScrn->LeaveVT; | |
1016 | pScrn->LeaveVT = glxDRILeaveVT; | |
1017 | ||
1018 | __glXsetGetProcAddress(glXGetProcAddressARB); | |
1019 | ||
1020 | LogMessage(X_INFO, "AIGLX: Loaded and initialized %s\n", driverName); | |
1021 | ||
1022 | return &screen->base; | |
1023 | ||
1024 | handle_error: | |
1025 | if (screen->driver) | |
1026 | dlclose(screen->driver); | |
1027 | ||
1028 | free(screen); | |
1029 | ||
1030 | LogMessage(X_ERROR, "AIGLX: reverting to software rendering\n"); | |
1031 | ||
1032 | return NULL; | |
1033 | } | |
1034 | ||
1035 | _X_EXPORT __GLXprovider __glXDRI2Provider = { | |
1036 | __glXDRIscreenProbe, | |
1037 | "DRI2", | |
1038 | NULL | |
1039 | }; |