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