1 /*
2 * Copyright 2008 George Sapountzis
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
25
26 #include <xcb/xproto.h>
27 #include <xcb/shm.h>
28 #include <X11/Xlib.h>
29 #include <X11/Xlib-xcb.h>
30 #include "glxclient.h"
31 #include <dlfcn.h>
32 #include "dri_common.h"
33 #include "drisw_priv.h"
34 #include <X11/extensions/shmproto.h>
35 #include <assert.h>
36 #include "util/debug.h"
37 #include "kopper_interface.h"
38 #include "loader_dri_helper.h"
39
40 static int xshm_error = 0;
41 static int xshm_opcode = -1;
42
43 /**
44 * Catches potential Xlib errors.
45 */
46 static int
handle_xerror(Display * dpy,XErrorEvent * event)47 handle_xerror(Display *dpy, XErrorEvent *event)
48 {
49 (void) dpy;
50
51 assert(xshm_opcode != -1);
52 if (event->request_code != xshm_opcode)
53 return 0;
54
55 xshm_error = event->error_code;
56 return 0;
57 }
58
59 static Bool
XCreateDrawable(struct drisw_drawable * pdp,int shmid,Display * dpy)60 XCreateDrawable(struct drisw_drawable * pdp, int shmid, Display * dpy)
61 {
62 if (pdp->ximage) {
63 XDestroyImage(pdp->ximage);
64 pdp->ximage = NULL;
65 if ((pdp->shminfo.shmid > 0) && (shmid != pdp->shminfo.shmid))
66 XShmDetach(dpy, &pdp->shminfo);
67 }
68
69 if (!xshm_error && shmid >= 0) {
70 pdp->shminfo.shmid = shmid;
71 pdp->ximage = XShmCreateImage(dpy,
72 NULL,
73 pdp->xDepth,
74 ZPixmap, /* format */
75 NULL, /* data */
76 &pdp->shminfo, /* shminfo */
77 0, 0); /* width, height */
78 if (pdp->ximage != NULL) {
79 int (*old_handler)(Display *, XErrorEvent *);
80
81 /* dispatch pending errors */
82 XSync(dpy, False);
83
84 old_handler = XSetErrorHandler(handle_xerror);
85 /* This may trigger the X protocol error we're ready to catch: */
86 XShmAttach(dpy, &pdp->shminfo);
87 XSync(dpy, False);
88
89 if (xshm_error) {
90 /* we are on a remote display, this error is normal, don't print it */
91 XDestroyImage(pdp->ximage);
92 pdp->ximage = NULL;
93 }
94
95 (void) XSetErrorHandler(old_handler);
96 }
97 }
98
99 if (pdp->ximage == NULL) {
100 pdp->shminfo.shmid = -1;
101 pdp->ximage = XCreateImage(dpy,
102 NULL,
103 pdp->xDepth,
104 ZPixmap, 0, /* format, offset */
105 NULL, /* data */
106 0, 0, /* width, height */
107 32, /* bitmap_pad */
108 0); /* bytes_per_line */
109 }
110
111 /**
112 * swrast does not handle 24-bit depth with 24 bpp, so let X do the
113 * the conversion for us.
114 */
115 if (pdp->ximage->bits_per_pixel == 24)
116 pdp->ximage->bits_per_pixel = 32;
117
118 return True;
119 }
120
121 static void
XDestroyDrawable(struct drisw_drawable * pdp,Display * dpy,XID drawable)122 XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable)
123 {
124 if (pdp->ximage)
125 XDestroyImage(pdp->ximage);
126
127 if (pdp->shminfo.shmid > 0)
128 XShmDetach(dpy, &pdp->shminfo);
129
130 XFreeGC(dpy, pdp->gc);
131 }
132
133 /**
134 * swrast loader functions
135 */
136
137 static void
swrastGetDrawableInfo(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)138 swrastGetDrawableInfo(__DRIdrawable * draw,
139 int *x, int *y, int *w, int *h,
140 void *loaderPrivate)
141 {
142 struct drisw_drawable *pdp = loaderPrivate;
143 __GLXDRIdrawable *pdraw = &(pdp->base);
144 Display *dpy = pdraw->psc->dpy;
145 Drawable drawable;
146
147 Window root;
148 unsigned uw, uh, bw, depth;
149
150 drawable = pdraw->xDrawable;
151
152 XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth);
153 *w = uw;
154 *h = uh;
155 }
156
157 /**
158 * Align renderbuffer pitch.
159 *
160 * This should be chosen by the driver and the loader (libGL, xserver/glx)
161 * should use the driver provided pitch.
162 *
163 * It seems that the xorg loader (that is the xserver loading swrast_dri for
164 * indirect rendering, not client-side libGL) requires that the pitch is
165 * exactly the image width padded to 32 bits. XXX
166 *
167 * The above restriction can probably be overcome by using ScratchPixmap and
168 * CopyArea in the xserver, similar to ShmPutImage, and setting the width of
169 * the scratch pixmap to 'pitch / cpp'.
170 */
171 static inline int
bytes_per_line(unsigned pitch_bits,unsigned mul)172 bytes_per_line(unsigned pitch_bits, unsigned mul)
173 {
174 unsigned mask = mul - 1;
175
176 return ((pitch_bits + mask) & ~mask) / 8;
177 }
178
179 static void
swrastXPutImage(__DRIdrawable * draw,int op,int srcx,int srcy,int x,int y,int w,int h,int stride,int shmid,char * data,void * loaderPrivate)180 swrastXPutImage(__DRIdrawable * draw, int op,
181 int srcx, int srcy, int x, int y,
182 int w, int h, int stride,
183 int shmid, char *data, void *loaderPrivate)
184 {
185 struct drisw_drawable *pdp = loaderPrivate;
186 __GLXDRIdrawable *pdraw = &(pdp->base);
187 Display *dpy = pdraw->psc->dpy;
188 Drawable drawable;
189 XImage *ximage;
190 GC gc = pdp->gc;
191
192 if (!pdp->ximage || shmid != pdp->shminfo.shmid) {
193 if (!XCreateDrawable(pdp, shmid, dpy))
194 return;
195 }
196
197 drawable = pdraw->xDrawable;
198 ximage = pdp->ximage;
199 ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
200 ximage->data = data;
201
202 ximage->width = ximage->bytes_per_line / ((ximage->bits_per_pixel + 7)/ 8);
203 ximage->height = h;
204
205 if (pdp->shminfo.shmid >= 0) {
206 XShmPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h, False);
207 XSync(dpy, False);
208 } else {
209 XPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h);
210 }
211 ximage->data = NULL;
212 }
213
214 static void
swrastPutImageShm(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,int shmid,char * shmaddr,unsigned offset,void * loaderPrivate)215 swrastPutImageShm(__DRIdrawable * draw, int op,
216 int x, int y, int w, int h, int stride,
217 int shmid, char *shmaddr, unsigned offset,
218 void *loaderPrivate)
219 {
220 struct drisw_drawable *pdp = loaderPrivate;
221
222 if (!pdp)
223 return;
224
225 pdp->shminfo.shmaddr = shmaddr;
226 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, shmid,
227 shmaddr + offset, loaderPrivate);
228 }
229
230 static void
swrastPutImageShm2(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,int shmid,char * shmaddr,unsigned offset,void * loaderPrivate)231 swrastPutImageShm2(__DRIdrawable * draw, int op,
232 int x, int y,
233 int w, int h, int stride,
234 int shmid, char *shmaddr, unsigned offset,
235 void *loaderPrivate)
236 {
237 struct drisw_drawable *pdp = loaderPrivate;
238
239 if (!pdp)
240 return;
241
242 pdp->shminfo.shmaddr = shmaddr;
243 swrastXPutImage(draw, op, x, 0, x, y, w, h, stride, shmid,
244 shmaddr + offset, loaderPrivate);
245 }
246
247 static void
swrastPutImage2(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)248 swrastPutImage2(__DRIdrawable * draw, int op,
249 int x, int y, int w, int h, int stride,
250 char *data, void *loaderPrivate)
251 {
252 if (!loaderPrivate)
253 return;
254
255 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, -1,
256 data, loaderPrivate);
257 }
258
259 static void
swrastPutImage(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)260 swrastPutImage(__DRIdrawable * draw, int op,
261 int x, int y, int w, int h,
262 char *data, void *loaderPrivate)
263 {
264 if (!loaderPrivate)
265 return;
266
267 swrastXPutImage(draw, op, 0, 0, x, y, w, h, 0, -1,
268 data, loaderPrivate);
269 }
270
271 static void
swrastGetImage2(__DRIdrawable * read,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)272 swrastGetImage2(__DRIdrawable * read,
273 int x, int y, int w, int h, int stride,
274 char *data, void *loaderPrivate)
275 {
276 struct drisw_drawable *prp = loaderPrivate;
277 __GLXDRIdrawable *pread = &(prp->base);
278 Display *dpy = pread->psc->dpy;
279 Drawable readable;
280 XImage *ximage;
281
282 if (!prp->ximage || prp->shminfo.shmid >= 0) {
283 if (!XCreateDrawable(prp, -1, dpy))
284 return;
285 }
286
287 readable = pread->xDrawable;
288
289 ximage = prp->ximage;
290 ximage->data = data;
291 ximage->width = w;
292 ximage->height = h;
293 ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
294
295 XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
296
297 ximage->data = NULL;
298 }
299
300 static void
swrastGetImage(__DRIdrawable * read,int x,int y,int w,int h,char * data,void * loaderPrivate)301 swrastGetImage(__DRIdrawable * read,
302 int x, int y, int w, int h,
303 char *data, void *loaderPrivate)
304 {
305 swrastGetImage2(read, x, y, w, h, 0, data, loaderPrivate);
306 }
307
308 static GLboolean
swrastGetImageShm2(__DRIdrawable * read,int x,int y,int w,int h,int shmid,void * loaderPrivate)309 swrastGetImageShm2(__DRIdrawable * read,
310 int x, int y, int w, int h,
311 int shmid, void *loaderPrivate)
312 {
313 struct drisw_drawable *prp = loaderPrivate;
314 __GLXDRIdrawable *pread = &(prp->base);
315 Display *dpy = pread->psc->dpy;
316 Drawable readable;
317 XImage *ximage;
318
319 if (!prp->ximage || shmid != prp->shminfo.shmid) {
320 if (!XCreateDrawable(prp, shmid, dpy))
321 return GL_FALSE;
322 }
323
324 if (prp->shminfo.shmid == -1)
325 return GL_FALSE;
326 readable = pread->xDrawable;
327
328 ximage = prp->ximage;
329 ximage->data = prp->shminfo.shmaddr; /* no offset */
330 ximage->width = w;
331 ximage->height = h;
332 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
333
334 XShmGetImage(dpy, readable, ximage, x, y, ~0L);
335 return GL_TRUE;
336 }
337
338 static void
swrastGetImageShm(__DRIdrawable * read,int x,int y,int w,int h,int shmid,void * loaderPrivate)339 swrastGetImageShm(__DRIdrawable * read,
340 int x, int y, int w, int h,
341 int shmid, void *loaderPrivate)
342 {
343 swrastGetImageShm2(read, x, y, w, h, shmid, loaderPrivate);
344 }
345
346 static const __DRIswrastLoaderExtension swrastLoaderExtension_shm = {
347 .base = {__DRI_SWRAST_LOADER, 6 },
348
349 .getDrawableInfo = swrastGetDrawableInfo,
350 .putImage = swrastPutImage,
351 .getImage = swrastGetImage,
352 .putImage2 = swrastPutImage2,
353 .getImage2 = swrastGetImage2,
354 .putImageShm = swrastPutImageShm,
355 .getImageShm = swrastGetImageShm,
356 .putImageShm2 = swrastPutImageShm2,
357 .getImageShm2 = swrastGetImageShm2,
358 };
359
360 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
361 .base = {__DRI_SWRAST_LOADER, 3 },
362
363 .getDrawableInfo = swrastGetDrawableInfo,
364 .putImage = swrastPutImage,
365 .getImage = swrastGetImage,
366 .putImage2 = swrastPutImage2,
367 .getImage2 = swrastGetImage2,
368 };
369
370 static void
kopperSetSurfaceCreateInfo(void * _draw,struct kopper_loader_info * out)371 kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *out)
372 {
373 __GLXDRIdrawable *draw = _draw;
374
375 out->xcb.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
376 out->xcb.pNext = NULL;
377 out->xcb.flags = 0;
378 out->xcb.connection = XGetXCBConnection(draw->psc->dpy);
379 out->xcb.window = draw->xDrawable;
380 }
381
382 static const __DRIkopperLoaderExtension kopperLoaderExtension = {
383 .base = { __DRI_KOPPER_LOADER, 1 },
384
385 .SetSurfaceCreateInfo = kopperSetSurfaceCreateInfo,
386 };
387
388 static const __DRIextension *loader_extensions_shm[] = {
389 &swrastLoaderExtension_shm.base,
390 &kopperLoaderExtension.base,
391 NULL
392 };
393
394 static const __DRIextension *loader_extensions_noshm[] = {
395 &swrastLoaderExtension.base,
396 &kopperLoaderExtension.base,
397 NULL
398 };
399
400 extern const __DRIuseInvalidateExtension dri2UseInvalidate;
401 extern const __DRIbackgroundCallableExtension driBackgroundCallable;
402
403 static const __DRIextension *kopper_extensions_noshm[] = {
404 &swrastLoaderExtension.base,
405 &kopperLoaderExtension.base,
406 &dri2UseInvalidate.base,
407 &driBackgroundCallable.base,
408 NULL
409 };
410
411 /**
412 * GLXDRI functions
413 */
414
415 static void
drisw_destroy_context(struct glx_context * context)416 drisw_destroy_context(struct glx_context *context)
417 {
418 struct drisw_context *pcp = (struct drisw_context *) context;
419 struct drisw_screen *psc = (struct drisw_screen *) context->psc;
420
421 driReleaseDrawables(&pcp->base);
422
423 free((char *) context->extensions);
424
425 (*psc->core->destroyContext) (pcp->driContext);
426
427 free(pcp);
428 }
429
430 static int
drisw_bind_context(struct glx_context * context,struct glx_context * old,GLXDrawable draw,GLXDrawable read)431 drisw_bind_context(struct glx_context *context, struct glx_context *old,
432 GLXDrawable draw, GLXDrawable read)
433 {
434 struct drisw_context *pcp = (struct drisw_context *) context;
435 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
436 struct drisw_drawable *pdraw, *pread;
437
438 pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw);
439 pread = (struct drisw_drawable *) driFetchDrawable(context, read);
440
441 driReleaseDrawables(old);
442
443 if (!(*psc->core->bindContext) (pcp->driContext,
444 pdraw ? pdraw->driDrawable : NULL,
445 pread ? pread->driDrawable : NULL))
446 return GLXBadContext;
447 if (psc->f) {
448 if (pdraw)
449 psc->f->invalidate(pdraw->driDrawable);
450 if (pread && (!pdraw || pread->driDrawable != pdraw->driDrawable))
451 psc->f->invalidate(pread->driDrawable);
452 }
453
454 return Success;
455 }
456
457 static void
drisw_unbind_context(struct glx_context * context,struct glx_context * new)458 drisw_unbind_context(struct glx_context *context, struct glx_context *new)
459 {
460 struct drisw_context *pcp = (struct drisw_context *) context;
461 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
462
463 (*psc->core->unbindContext) (pcp->driContext);
464 }
465
466 static void
drisw_wait_gl(struct glx_context * context)467 drisw_wait_gl(struct glx_context *context)
468 {
469 glFinish();
470 }
471
472 static void
drisw_wait_x(struct glx_context * context)473 drisw_wait_x(struct glx_context *context)
474 {
475 XSync(context->currentDpy, False);
476 }
477
478 static void
drisw_bind_tex_image(__GLXDRIdrawable * base,int buffer,const int * attrib_list)479 drisw_bind_tex_image(__GLXDRIdrawable *base,
480 int buffer, const int *attrib_list)
481 {
482 struct glx_context *gc = __glXGetCurrentContext();
483 struct drisw_context *pcp = (struct drisw_context *) gc;
484 struct drisw_drawable *pdraw = (struct drisw_drawable *) base;
485 struct drisw_screen *psc;
486
487 if (pdraw != NULL) {
488 psc = (struct drisw_screen *) base->psc;
489
490 if (!psc->texBuffer)
491 return;
492
493 if (psc->texBuffer->base.version >= 2 &&
494 psc->texBuffer->setTexBuffer2 != NULL) {
495 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
496 pdraw->base.textureTarget,
497 pdraw->base.textureFormat,
498 pdraw->driDrawable);
499 }
500 else {
501 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
502 pdraw->base.textureTarget,
503 pdraw->driDrawable);
504 }
505 }
506 }
507
508 static void
drisw_release_tex_image(__GLXDRIdrawable * base,int buffer)509 drisw_release_tex_image(__GLXDRIdrawable *base, int buffer)
510 {
511 struct glx_context *gc = __glXGetCurrentContext();
512 struct drisw_context *pcp = (struct drisw_context *) gc;
513 struct drisw_drawable *pdraw = (struct drisw_drawable *) base;
514 struct drisw_screen *psc;
515
516 if (pdraw != NULL) {
517 psc = (struct drisw_screen *) base->psc;
518
519 if (!psc->texBuffer)
520 return;
521
522 if (psc->texBuffer->base.version >= 3 &&
523 psc->texBuffer->releaseTexBuffer != NULL) {
524 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
525 pdraw->base.textureTarget,
526 pdraw->driDrawable);
527 }
528 }
529 }
530
531 static int
kopper_get_buffer_age(__GLXDRIdrawable * pdraw)532 kopper_get_buffer_age(__GLXDRIdrawable *pdraw)
533 {
534 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
535
536 if (pdp) {
537 struct drisw_screen *psc = (struct drisw_screen *) pdraw->psc;
538
539 if (psc->kopper)
540 return psc->kopper->queryBufferAge(pdp->driDrawable);
541 }
542 return 0;
543 }
544
545 static const struct glx_context_vtable drisw_context_vtable = {
546 .destroy = drisw_destroy_context,
547 .bind = drisw_bind_context,
548 .unbind = drisw_unbind_context,
549 .wait_gl = drisw_wait_gl,
550 .wait_x = drisw_wait_x,
551 };
552
553 static struct glx_context *
drisw_create_context_attribs(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,unsigned num_attribs,const uint32_t * attribs,unsigned * error)554 drisw_create_context_attribs(struct glx_screen *base,
555 struct glx_config *config_base,
556 struct glx_context *shareList,
557 unsigned num_attribs,
558 const uint32_t *attribs,
559 unsigned *error)
560 {
561 struct drisw_context *pcp, *pcp_shared;
562 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
563 struct drisw_screen *psc = (struct drisw_screen *) base;
564 __DRIcontext *shared = NULL;
565
566 struct dri_ctx_attribs dca;
567 uint32_t ctx_attribs[2 * 5];
568 unsigned num_ctx_attribs = 0;
569
570 if (!psc->base.driScreen)
571 return NULL;
572
573 if (psc->swrast->base.version < 3)
574 return NULL;
575
576 *error = dri_convert_glx_attribs(num_attribs, attribs, &dca);
577 if (*error != __DRI_CTX_ERROR_SUCCESS)
578 return NULL;
579
580 /* Check the renderType value */
581 if (!validate_renderType_against_config(config_base, dca.render_type)) {
582 return NULL;
583 }
584
585 if (shareList) {
586 /* We can't share with an indirect context */
587 if (!shareList->isDirect)
588 return NULL;
589
590 /* The GLX_ARB_create_context_no_error specs say:
591 *
592 * BadMatch is generated if the value of GLX_CONTEXT_OPENGL_NO_ERROR_ARB
593 * used to create <share_context> does not match the value of
594 * GLX_CONTEXT_OPENGL_NO_ERROR_ARB for the context being created.
595 */
596 if (!!shareList->noError != !!dca.no_error) {
597 *error = __DRI_CTX_ERROR_BAD_FLAG;
598 return NULL;
599 }
600
601 pcp_shared = (struct drisw_context *) shareList;
602 shared = pcp_shared->driContext;
603 }
604
605 pcp = calloc(1, sizeof *pcp);
606 if (pcp == NULL)
607 return NULL;
608
609 if (!glx_context_init(&pcp->base, &psc->base, config_base)) {
610 free(pcp);
611 return NULL;
612 }
613
614 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
615 ctx_attribs[num_ctx_attribs++] = dca.major_ver;
616 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
617 ctx_attribs[num_ctx_attribs++] = dca.minor_ver;
618 if (dca.reset != __DRI_CTX_RESET_NO_NOTIFICATION) {
619 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY;
620 ctx_attribs[num_ctx_attribs++] = dca.reset;
621 }
622
623 if (dca.release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
624 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
625 ctx_attribs[num_ctx_attribs++] = dca.release;
626 }
627 if (dca.no_error) {
628 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_NO_ERROR;
629 ctx_attribs[num_ctx_attribs++] = GL_TRUE;
630 pcp->base.noError = GL_TRUE;
631 }
632
633 if (dca.flags != 0) {
634 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
635 ctx_attribs[num_ctx_attribs++] = dca.flags;
636 }
637
638 pcp->base.renderType = dca.render_type;
639
640 pcp->driContext =
641 (*psc->swrast->createContextAttribs) (psc->driScreen,
642 dca.api,
643 config ? config->driConfig : NULL,
644 shared,
645 num_ctx_attribs / 2,
646 ctx_attribs,
647 error,
648 pcp);
649 if (pcp->driContext == NULL) {
650 free(pcp);
651 return NULL;
652 }
653
654 pcp->base.vtable = base->context_vtable;
655
656 return &pcp->base;
657 }
658
659 static void
driswDestroyDrawable(__GLXDRIdrawable * pdraw)660 driswDestroyDrawable(__GLXDRIdrawable * pdraw)
661 {
662 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
663 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
664
665 (*psc->core->destroyDrawable) (pdp->driDrawable);
666
667 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
668 free(pdp);
669 }
670
671 static __GLXDRIdrawable *
driswCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * modes)672 driswCreateDrawable(struct glx_screen *base, XID xDrawable,
673 GLXDrawable drawable, int type,
674 struct glx_config *modes)
675 {
676 struct drisw_drawable *pdp;
677 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
678 struct drisw_screen *psc = (struct drisw_screen *) base;
679 const __DRIswrastExtension *swrast = psc->swrast;
680 const __DRIkopperExtension *kopper = psc->kopper;
681 Display *dpy = psc->base.dpy;
682
683 pdp = calloc(1, sizeof(*pdp));
684 if (!pdp)
685 return NULL;
686
687 pdp->base.xDrawable = xDrawable;
688 pdp->base.drawable = drawable;
689 pdp->base.psc = &psc->base;
690 pdp->config = modes;
691 pdp->gc = XCreateGC(dpy, xDrawable, 0, NULL);
692 pdp->xDepth = 0;
693
694 /* Use the visual depth, if this fbconfig corresponds to a visual */
695 if (pdp->config->visualID != 0) {
696 int matches = 0;
697 XVisualInfo *visinfo, template;
698
699 template.visualid = pdp->config->visualID;
700 template.screen = pdp->config->screen;
701 visinfo = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask,
702 &template, &matches);
703
704 if (visinfo && matches) {
705 pdp->xDepth = visinfo->depth;
706 XFree(visinfo);
707 }
708 }
709
710 /* Otherwise, or if XGetVisualInfo failed, ask the server */
711 if (pdp->xDepth == 0) {
712 Window root;
713 int x, y;
714 unsigned uw, uh, bw, depth;
715
716 XGetGeometry(dpy, xDrawable, &root, &x, &y, &uw, &uh, &bw, &depth);
717 pdp->xDepth = depth;
718 }
719
720 /* Create a new drawable */
721 if (kopper) {
722 pdp->driDrawable =
723 (*kopper->createNewDrawable) (psc->driScreen, config->driConfig, pdp, !(type & GLX_WINDOW_BIT));
724
725 pdp->swapInterval = dri_get_initial_swap_interval(psc->driScreen, psc->config);
726 psc->kopper->setSwapInterval(pdp->driDrawable, pdp->swapInterval);
727 }
728 else
729 pdp->driDrawable =
730 (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp);
731
732 if (!pdp->driDrawable) {
733 XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
734 free(pdp);
735 return NULL;
736 }
737
738 pdp->base.destroyDrawable = driswDestroyDrawable;
739
740 return &pdp->base;
741 }
742
743 static int64_t
driswSwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)744 driswSwapBuffers(__GLXDRIdrawable * pdraw,
745 int64_t target_msc, int64_t divisor, int64_t remainder,
746 Bool flush)
747 {
748 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
749 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
750
751 (void) target_msc;
752 (void) divisor;
753 (void) remainder;
754
755 if (flush) {
756 glFlush();
757 }
758
759 if (psc->kopper)
760 return psc->kopper->swapBuffers (pdp->driDrawable);
761
762 (*psc->core->swapBuffers) (pdp->driDrawable);
763
764 return 0;
765 }
766
767 static void
driswCopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)768 driswCopySubBuffer(__GLXDRIdrawable * pdraw,
769 int x, int y, int width, int height, Bool flush)
770 {
771 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
772 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
773
774 if (flush) {
775 glFlush();
776 }
777
778 (*psc->copySubBuffer->copySubBuffer) (pdp->driDrawable,
779 x, y, width, height);
780 }
781
782 static void
driswDestroyScreen(struct glx_screen * base)783 driswDestroyScreen(struct glx_screen *base)
784 {
785 struct drisw_screen *psc = (struct drisw_screen *) base;
786
787 /* Free the direct rendering per screen data */
788 (*psc->core->destroyScreen) (psc->driScreen);
789 driDestroyConfigs(psc->driver_configs);
790 psc->driScreen = NULL;
791 if (psc->driver)
792 dlclose(psc->driver);
793 free(psc);
794 }
795
796 static char *
drisw_get_driver_name(struct glx_screen * glx_screen)797 drisw_get_driver_name(struct glx_screen *glx_screen)
798 {
799 struct drisw_screen *psc = (struct drisw_screen *) glx_screen;
800 return strdup(psc->name);
801 }
802
803 static const struct glx_screen_vtable drisw_screen_vtable = {
804 .create_context = dri_common_create_context,
805 .create_context_attribs = drisw_create_context_attribs,
806 .query_renderer_integer = drisw_query_renderer_integer,
807 .query_renderer_string = drisw_query_renderer_string,
808 .get_driver_name = drisw_get_driver_name,
809 };
810
811 static void
driswBindExtensions(struct drisw_screen * psc,const __DRIextension ** extensions)812 driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions)
813 {
814 int i;
815
816 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
817
818 if (psc->swrast->base.version >= 3) {
819 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
820 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
821 __glXEnableDirectExtension(&psc->base, "GLX_EXT_no_config_context");
822
823 /* DRISW version >= 2 implies support for OpenGL ES.
824 */
825 __glXEnableDirectExtension(&psc->base,
826 "GLX_EXT_create_context_es_profile");
827 __glXEnableDirectExtension(&psc->base,
828 "GLX_EXT_create_context_es2_profile");
829 }
830
831 if (psc->copySubBuffer)
832 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
833
834 /* FIXME: Figure out what other extensions can be ported here from dri2. */
835 for (i = 0; extensions[i]; i++) {
836 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
837 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
838 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
839 }
840 /* DRISW version 3 is also required because GLX_MESA_query_renderer
841 * requires GLX_ARB_create_context_profile.
842 */
843 if (psc->swrast->base.version >= 3
844 && strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
845 psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
846 __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
847 unsigned int no_error = 0;
848 if (psc->rendererQuery->queryInteger(psc->driScreen,
849 __DRI2_RENDERER_HAS_NO_ERROR_CONTEXT,
850 &no_error) == 0 && no_error)
851 __glXEnableDirectExtension(&psc->base,
852 "GLX_ARB_create_context_no_error");
853 }
854
855 if (strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0)
856 __glXEnableDirectExtension(&psc->base,
857 "GLX_ARB_create_context_robustness");
858
859 if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) {
860 __glXEnableDirectExtension(&psc->base,
861 "GLX_ARB_context_flush_control");
862 }
863 if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)
864 psc->f = (__DRI2flushExtension *) extensions[i];
865 if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0))
866 psc->config = (__DRI2configQueryExtension *) extensions[i];
867
868 }
869
870 if (psc->kopper) {
871 __glXEnableDirectExtension(&psc->base, "GLX_EXT_buffer_age");
872 __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control");
873 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
874 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
875 // This needs to check whether RELAXED is available
876 // __glXEnableDirectExtension(&psc->base, "GLX_EXT_swap_control_tear");
877 }
878 }
879
880 static int
check_xshm(Display * dpy)881 check_xshm(Display *dpy)
882 {
883 xcb_connection_t *c = XGetXCBConnection(dpy);
884 xcb_void_cookie_t cookie;
885 xcb_generic_error_t *error;
886 int ret = True;
887 xcb_query_extension_cookie_t shm_cookie;
888 xcb_query_extension_reply_t *shm_reply;
889 bool has_mit_shm;
890
891 shm_cookie = xcb_query_extension(c, 7, "MIT-SHM");
892 shm_reply = xcb_query_extension_reply(c, shm_cookie, NULL);
893
894 has_mit_shm = shm_reply->present;
895 free(shm_reply);
896 if (!has_mit_shm)
897 return False;
898
899 cookie = xcb_shm_detach_checked(c, 0);
900 if ((error = xcb_request_check(c, cookie))) {
901 /* BadRequest means we're a remote client. If we were local we'd
902 * expect BadValue since 'info' has an invalid segment name.
903 */
904 if (error->error_code == BadRequest)
905 ret = False;
906 free(error);
907 }
908
909 return ret;
910 }
911
912 static int
kopperSetSwapInterval(__GLXDRIdrawable * pdraw,int interval)913 kopperSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
914 {
915 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
916 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
917
918 if (!dri_valid_swap_interval(psc->driScreen, psc->config, interval))
919 return GLX_BAD_VALUE;
920
921 psc->kopper->setSwapInterval(pdp->driDrawable, interval);
922 pdp->swapInterval = interval;
923
924 return 0;
925 }
926
927 static int
kopperGetSwapInterval(__GLXDRIdrawable * pdraw)928 kopperGetSwapInterval(__GLXDRIdrawable *pdraw)
929 {
930 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
931
932 return pdp->swapInterval;
933 }
934
935 static struct glx_screen *
driswCreateScreenDriver(int screen,struct glx_display * priv,const char * driver)936 driswCreateScreenDriver(int screen, struct glx_display *priv,
937 const char *driver)
938 {
939 __GLXDRIscreen *psp;
940 const __DRIconfig **driver_configs;
941 const __DRIextension **extensions;
942 struct drisw_screen *psc;
943 struct glx_config *configs = NULL, *visuals = NULL;
944 int i;
945 const __DRIextension **loader_extensions_local;
946 const struct drisw_display *pdpyp = (struct drisw_display *)priv->driswDisplay;
947
948 psc = calloc(1, sizeof *psc);
949 if (psc == NULL)
950 return NULL;
951
952 if (!glx_screen_init(&psc->base, screen, priv)) {
953 free(psc);
954 return NULL;
955 }
956
957 extensions = driOpenDriver(driver, &psc->driver);
958 if (extensions == NULL)
959 goto handle_error;
960 psc->name = driver;
961
962 if (pdpyp->zink)
963 loader_extensions_local = kopper_extensions_noshm;
964 else if (!check_xshm(psc->base.dpy))
965 loader_extensions_local = loader_extensions_noshm;
966 else
967 loader_extensions_local = loader_extensions_shm;
968
969 for (i = 0; extensions[i]; i++) {
970 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
971 psc->core = (__DRIcoreExtension *) extensions[i];
972 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
973 psc->swrast = (__DRIswrastExtension *) extensions[i];
974 if (strcmp(extensions[i]->name, __DRI_KOPPER) == 0)
975 psc->kopper = (__DRIkopperExtension *) extensions[i];
976 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0)
977 psc->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
978 }
979
980 if (psc->core == NULL || psc->swrast == NULL) {
981 ErrorMessageF("core dri extension not found\n");
982 goto handle_error;
983 }
984
985 if (psc->swrast->base.version >= 4) {
986 psc->driScreen =
987 psc->swrast->createNewScreen2(screen, loader_extensions_local,
988 extensions,
989 &driver_configs, psc);
990 } else {
991 psc->driScreen =
992 psc->swrast->createNewScreen(screen, loader_extensions_local,
993 &driver_configs, psc);
994 }
995 if (psc->driScreen == NULL) {
996 ErrorMessageF("glx: failed to create drisw screen\n");
997 goto handle_error;
998 }
999
1000 extensions = psc->core->getExtensions(psc->driScreen);
1001 driswBindExtensions(psc, extensions);
1002
1003 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
1004 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
1005
1006 if (!configs || !visuals) {
1007 ErrorMessageF("No matching fbConfigs or visuals found\n");
1008 goto handle_error;
1009 }
1010
1011 glx_config_destroy_list(psc->base.configs);
1012 psc->base.configs = configs;
1013 glx_config_destroy_list(psc->base.visuals);
1014 psc->base.visuals = visuals;
1015
1016 psc->driver_configs = driver_configs;
1017
1018 psc->base.vtable = &drisw_screen_vtable;
1019 psc->base.context_vtable = &drisw_context_vtable;
1020 psp = &psc->vtable;
1021 psc->base.driScreen = psp;
1022 psp->destroyScreen = driswDestroyScreen;
1023 psp->createDrawable = driswCreateDrawable;
1024 psp->swapBuffers = driswSwapBuffers;
1025 psp->bindTexImage = drisw_bind_tex_image;
1026 psp->releaseTexImage = drisw_release_tex_image;
1027
1028 if (psc->copySubBuffer)
1029 psp->copySubBuffer = driswCopySubBuffer;
1030
1031 if (psc->kopper) {
1032 psp->getBufferAge = kopper_get_buffer_age;
1033 psp->setSwapInterval = kopperSetSwapInterval;
1034 psp->getSwapInterval = kopperGetSwapInterval;
1035 psp->maxSwapInterval = 1;
1036 }
1037
1038 return &psc->base;
1039
1040 handle_error:
1041 if (configs)
1042 glx_config_destroy_list(configs);
1043 if (visuals)
1044 glx_config_destroy_list(visuals);
1045 if (psc->driScreen)
1046 psc->core->destroyScreen(psc->driScreen);
1047 psc->driScreen = NULL;
1048
1049 if (psc->driver)
1050 dlclose(psc->driver);
1051 glx_screen_cleanup(&psc->base);
1052 free(psc);
1053
1054 CriticalErrorMessageF("failed to load driver: %s\n", driver);
1055
1056 return NULL;
1057 }
1058
1059 static struct glx_screen *
driswCreateScreen(int screen,struct glx_display * priv)1060 driswCreateScreen(int screen, struct glx_display *priv)
1061 {
1062 const struct drisw_display *pdpyp = (struct drisw_display *)priv->driswDisplay;
1063 if (pdpyp->zink && !env_var_as_boolean("LIBGL_KOPPER_DISABLE", false)) {
1064 return driswCreateScreenDriver(screen, priv, "zink");
1065 }
1066
1067 return driswCreateScreenDriver(screen, priv, "swrast");
1068 }
1069
1070 /* Called from __glXFreeDisplayPrivate.
1071 */
1072 static void
driswDestroyDisplay(__GLXDRIdisplay * dpy)1073 driswDestroyDisplay(__GLXDRIdisplay * dpy)
1074 {
1075 free(dpy);
1076 }
1077
1078 /*
1079 * Allocate, initialize and return a __DRIdisplayPrivate object.
1080 * This is called from __glXInitialize() when we are given a new
1081 * display pointer.
1082 */
1083 _X_HIDDEN __GLXDRIdisplay *
driswCreateDisplay(Display * dpy,bool zink)1084 driswCreateDisplay(Display * dpy, bool zink)
1085 {
1086 struct drisw_display *pdpyp;
1087
1088 pdpyp = malloc(sizeof *pdpyp);
1089 if (pdpyp == NULL)
1090 return NULL;
1091
1092 pdpyp->base.destroyDisplay = driswDestroyDisplay;
1093 pdpyp->base.createScreen = driswCreateScreen;
1094 pdpyp->zink = zink;
1095
1096 return &pdpyp->base;
1097 }
1098
1099 #endif /* GLX_DIRECT_RENDERING */
1100