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) || defined(GLX_USE_APPLE))
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 #ifdef HAVE_LIBDRM
36 #include "dri3_priv.h"
37 #endif
38 #include <X11/extensions/shmproto.h>
39 #include <assert.h>
40 #include <vulkan/vulkan_core.h>
41 #include <vulkan/vulkan_xcb.h>
42 #include "util/u_debug.h"
43 #include "kopper_interface.h"
44 #include "loader_dri_helper.h"
45 #include "dri_util.h"
46
47 static int xshm_error = 0;
48 static int xshm_opcode = -1;
49
50 /**
51 * Catches potential Xlib errors.
52 */
53 static int
handle_xerror(Display * dpy,XErrorEvent * event)54 handle_xerror(Display *dpy, XErrorEvent *event)
55 {
56 (void) dpy;
57
58 assert(xshm_opcode != -1);
59 if (event->request_code != xshm_opcode)
60 return 0;
61
62 xshm_error = event->error_code;
63 return 0;
64 }
65
66 static Bool
XCreateDrawable(struct drisw_drawable * pdp,int shmid,Display * dpy)67 XCreateDrawable(struct drisw_drawable * pdp, int shmid, Display * dpy)
68 {
69 if (pdp->ximage) {
70 XDestroyImage(pdp->ximage);
71 pdp->ximage = NULL;
72 if ((pdp->shminfo.shmid > 0) && (shmid != pdp->shminfo.shmid))
73 XShmDetach(dpy, &pdp->shminfo);
74 }
75
76 if (!xshm_error && shmid >= 0) {
77 pdp->shminfo.shmid = shmid;
78 pdp->ximage = XShmCreateImage(dpy,
79 NULL,
80 pdp->xDepth,
81 ZPixmap, /* format */
82 NULL, /* data */
83 &pdp->shminfo, /* shminfo */
84 0, 0); /* width, height */
85 if (pdp->ximage != NULL) {
86 int (*old_handler)(Display *, XErrorEvent *);
87
88 /* dispatch pending errors */
89 XSync(dpy, False);
90
91 old_handler = XSetErrorHandler(handle_xerror);
92 /* This may trigger the X protocol error we're ready to catch: */
93 XShmAttach(dpy, &pdp->shminfo);
94 XSync(dpy, False);
95
96 if (xshm_error) {
97 /* we are on a remote display, this error is normal, don't print it */
98 XDestroyImage(pdp->ximage);
99 pdp->ximage = NULL;
100 }
101
102 (void) XSetErrorHandler(old_handler);
103 }
104 }
105
106 if (pdp->ximage == NULL) {
107 pdp->shminfo.shmid = -1;
108 pdp->ximage = XCreateImage(dpy,
109 NULL,
110 pdp->xDepth,
111 ZPixmap, 0, /* format, offset */
112 NULL, /* data */
113 0, 0, /* width, height */
114 32, /* bitmap_pad */
115 0); /* bytes_per_line */
116 }
117
118 /**
119 * swrast does not handle 24-bit depth with 24 bpp, so let X do the
120 * the conversion for us.
121 */
122 if (pdp->ximage->bits_per_pixel == 24)
123 pdp->ximage->bits_per_pixel = 32;
124
125 return True;
126 }
127
128 static void
XDestroyDrawable(struct drisw_drawable * pdp,Display * dpy,XID drawable)129 XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable)
130 {
131 if (pdp->ximage)
132 XDestroyImage(pdp->ximage);
133
134 if (pdp->shminfo.shmid > 0)
135 XShmDetach(dpy, &pdp->shminfo);
136
137 XFreeGC(dpy, pdp->gc);
138 }
139
140 /**
141 * swrast loader functions
142 */
143
144 static void
swrastGetDrawableInfo(__DRIdrawable * draw,int * x,int * y,int * w,int * h,void * loaderPrivate)145 swrastGetDrawableInfo(__DRIdrawable * draw,
146 int *x, int *y, int *w, int *h,
147 void *loaderPrivate)
148 {
149 struct drisw_drawable *pdp = loaderPrivate;
150 __GLXDRIdrawable *pdraw = &(pdp->base);
151 Display *dpy = pdraw->psc->dpy;
152 Drawable drawable;
153
154 Window root;
155 unsigned uw, uh, bw, depth;
156
157 drawable = pdraw->xDrawable;
158
159 XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth);
160 *w = uw;
161 *h = uh;
162 }
163
164 /**
165 * Align renderbuffer pitch.
166 *
167 * This should be chosen by the driver and the loader (libGL, xserver/glx)
168 * should use the driver provided pitch.
169 *
170 * It seems that the xorg loader (that is the xserver loading swrast_dri for
171 * indirect rendering, not client-side libGL) requires that the pitch is
172 * exactly the image width padded to 32 bits. XXX
173 *
174 * The above restriction can probably be overcome by using ScratchPixmap and
175 * CopyArea in the xserver, similar to ShmPutImage, and setting the width of
176 * the scratch pixmap to 'pitch / cpp'.
177 */
178 static inline int
bytes_per_line(unsigned pitch_bits,unsigned mul)179 bytes_per_line(unsigned pitch_bits, unsigned mul)
180 {
181 unsigned mask = mul - 1;
182
183 return ((pitch_bits + mask) & ~mask) / 8;
184 }
185
186 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)187 swrastXPutImage(__DRIdrawable * draw, int op,
188 int srcx, int srcy, int x, int y,
189 int w, int h, int stride,
190 int shmid, char *data, void *loaderPrivate)
191 {
192 struct drisw_drawable *pdp = loaderPrivate;
193 __GLXDRIdrawable *pdraw = &(pdp->base);
194 Display *dpy = pdraw->psc->dpy;
195 Drawable drawable;
196 XImage *ximage;
197 GC gc = pdp->gc;
198
199 if (!pdp->ximage || shmid != pdp->shminfo.shmid) {
200 if (!XCreateDrawable(pdp, shmid, dpy))
201 return;
202 }
203
204 drawable = pdraw->xDrawable;
205 ximage = pdp->ximage;
206 ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
207 ximage->data = data;
208
209 ximage->width = ximage->bytes_per_line / ((ximage->bits_per_pixel + 7)/ 8);
210 ximage->height = h;
211
212 if (pdp->shminfo.shmid >= 0) {
213 XShmPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h, False);
214 XSync(dpy, False);
215 } else {
216 XPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h);
217 }
218 ximage->data = NULL;
219 }
220
221 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)222 swrastPutImageShm(__DRIdrawable * draw, int op,
223 int x, int y, int w, int h, int stride,
224 int shmid, char *shmaddr, unsigned offset,
225 void *loaderPrivate)
226 {
227 struct drisw_drawable *pdp = loaderPrivate;
228
229 if (!pdp)
230 return;
231
232 pdp->shminfo.shmaddr = shmaddr;
233 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, shmid,
234 shmaddr + offset, loaderPrivate);
235 }
236
237 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)238 swrastPutImageShm2(__DRIdrawable * draw, int op,
239 int x, int y,
240 int w, int h, int stride,
241 int shmid, char *shmaddr, unsigned offset,
242 void *loaderPrivate)
243 {
244 struct drisw_drawable *pdp = loaderPrivate;
245
246 if (!pdp)
247 return;
248
249 pdp->shminfo.shmaddr = shmaddr;
250 swrastXPutImage(draw, op, x, 0, x, y, w, h, stride, shmid,
251 shmaddr + offset, loaderPrivate);
252 }
253
254 static void
swrastPutImage2(__DRIdrawable * draw,int op,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)255 swrastPutImage2(__DRIdrawable * draw, int op,
256 int x, int y, int w, int h, int stride,
257 char *data, void *loaderPrivate)
258 {
259 if (!loaderPrivate)
260 return;
261
262 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, -1,
263 data, loaderPrivate);
264 }
265
266 static void
swrastPutImage(__DRIdrawable * draw,int op,int x,int y,int w,int h,char * data,void * loaderPrivate)267 swrastPutImage(__DRIdrawable * draw, int op,
268 int x, int y, int w, int h,
269 char *data, void *loaderPrivate)
270 {
271 if (!loaderPrivate)
272 return;
273
274 swrastXPutImage(draw, op, 0, 0, x, y, w, h, 0, -1,
275 data, loaderPrivate);
276 }
277
278 static void
swrastGetImage2(__DRIdrawable * read,int x,int y,int w,int h,int stride,char * data,void * loaderPrivate)279 swrastGetImage2(__DRIdrawable * read,
280 int x, int y, int w, int h, int stride,
281 char *data, void *loaderPrivate)
282 {
283 struct drisw_drawable *prp = loaderPrivate;
284 __GLXDRIdrawable *pread = &(prp->base);
285 Display *dpy = pread->psc->dpy;
286 Drawable readable;
287 XImage *ximage;
288
289 if (!prp->ximage || prp->shminfo.shmid >= 0) {
290 if (!XCreateDrawable(prp, -1, dpy))
291 return;
292 }
293
294 readable = pread->xDrawable;
295
296 ximage = prp->ximage;
297 ximage->data = data;
298 ximage->width = w;
299 ximage->height = h;
300 ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
301
302 XGetSubImage(dpy, readable, x, y, w, h, ~0L, ZPixmap, ximage, 0, 0);
303
304 ximage->data = NULL;
305 }
306
307 static void
swrastGetImage(__DRIdrawable * read,int x,int y,int w,int h,char * data,void * loaderPrivate)308 swrastGetImage(__DRIdrawable * read,
309 int x, int y, int w, int h,
310 char *data, void *loaderPrivate)
311 {
312 swrastGetImage2(read, x, y, w, h, 0, data, loaderPrivate);
313 }
314
315 static GLboolean
swrastGetImageShm2(__DRIdrawable * read,int x,int y,int w,int h,int shmid,void * loaderPrivate)316 swrastGetImageShm2(__DRIdrawable * read,
317 int x, int y, int w, int h,
318 int shmid, void *loaderPrivate)
319 {
320 struct drisw_drawable *prp = loaderPrivate;
321 __GLXDRIdrawable *pread = &(prp->base);
322 Display *dpy = pread->psc->dpy;
323 Drawable readable;
324 XImage *ximage;
325
326 if (!prp->ximage || shmid != prp->shminfo.shmid) {
327 if (!XCreateDrawable(prp, shmid, dpy))
328 return GL_FALSE;
329 }
330
331 if (prp->shminfo.shmid == -1)
332 return GL_FALSE;
333 readable = pread->xDrawable;
334
335 ximage = prp->ximage;
336 ximage->data = prp->shminfo.shmaddr; /* no offset */
337 ximage->width = w;
338 ximage->height = h;
339 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
340
341 XShmGetImage(dpy, readable, ximage, x, y, ~0L);
342 return GL_TRUE;
343 }
344
345 static void
swrastGetImageShm(__DRIdrawable * read,int x,int y,int w,int h,int shmid,void * loaderPrivate)346 swrastGetImageShm(__DRIdrawable * read,
347 int x, int y, int w, int h,
348 int shmid, void *loaderPrivate)
349 {
350 swrastGetImageShm2(read, x, y, w, h, shmid, loaderPrivate);
351 }
352
353 static const __DRIswrastLoaderExtension swrastLoaderExtension_shm = {
354 .base = {__DRI_SWRAST_LOADER, 6 },
355
356 .getDrawableInfo = swrastGetDrawableInfo,
357 .putImage = swrastPutImage,
358 .getImage = swrastGetImage,
359 .putImage2 = swrastPutImage2,
360 .getImage2 = swrastGetImage2,
361 .putImageShm = swrastPutImageShm,
362 .getImageShm = swrastGetImageShm,
363 .putImageShm2 = swrastPutImageShm2,
364 .getImageShm2 = swrastGetImageShm2,
365 };
366
367 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
368 .base = {__DRI_SWRAST_LOADER, 3 },
369
370 .getDrawableInfo = swrastGetDrawableInfo,
371 .putImage = swrastPutImage,
372 .getImage = swrastGetImage,
373 .putImage2 = swrastPutImage2,
374 .getImage2 = swrastGetImage2,
375 };
376
377 static_assert(sizeof(struct kopper_vk_surface_create_storage) >= sizeof(VkXcbSurfaceCreateInfoKHR), "");
378
379 static void
kopperSetSurfaceCreateInfo(void * _draw,struct kopper_loader_info * out)380 kopperSetSurfaceCreateInfo(void *_draw, struct kopper_loader_info *out)
381 {
382 __GLXDRIdrawable *draw = _draw;
383 VkXcbSurfaceCreateInfoKHR *xcb = (VkXcbSurfaceCreateInfoKHR *)&out->bos;
384
385 xcb->sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
386 xcb->pNext = NULL;
387 xcb->flags = 0;
388 xcb->connection = XGetXCBConnection(draw->psc->dpy);
389 xcb->window = draw->xDrawable;
390 }
391
392 static const __DRIkopperLoaderExtension kopperLoaderExtension = {
393 .base = { __DRI_KOPPER_LOADER, 1 },
394
395 .SetSurfaceCreateInfo = kopperSetSurfaceCreateInfo,
396 };
397
398 static const __DRIextension *loader_extensions_shm[] = {
399 &swrastLoaderExtension_shm.base,
400 &kopperLoaderExtension.base,
401 NULL
402 };
403
404 static const __DRIextension *loader_extensions_noshm[] = {
405 &swrastLoaderExtension.base,
406 &kopperLoaderExtension.base,
407 NULL
408 };
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
423 static void
drisw_wait_gl(struct glx_context * context)424 drisw_wait_gl(struct glx_context *context)
425 {
426 glFinish();
427 }
428
429 static void
drisw_wait_x(struct glx_context * context)430 drisw_wait_x(struct glx_context *context)
431 {
432 XSync(context->currentDpy, False);
433 }
434
435 int
436 kopper_get_buffer_age(__GLXDRIdrawable *pdraw);
437 int
kopper_get_buffer_age(__GLXDRIdrawable * pdraw)438 kopper_get_buffer_age(__GLXDRIdrawable *pdraw)
439 {
440 return kopperQueryBufferAge(pdraw->dri_drawable);
441 }
442
443 static const struct glx_context_vtable drisw_context_vtable = {
444 .destroy = dri_destroy_context,
445 .bind = dri_bind_context,
446 .unbind = dri_unbind_context,
447 .wait_gl = drisw_wait_gl,
448 .wait_x = drisw_wait_x,
449 };
450
451 static void
driswDestroyDrawable(__GLXDRIdrawable * pdraw)452 driswDestroyDrawable(__GLXDRIdrawable * pdraw)
453 {
454 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
455
456 driDestroyDrawable(pdp->base.dri_drawable);
457
458 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
459 free(pdp);
460 }
461
462 static __GLXDRIdrawable *
driswCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,int type,struct glx_config * modes)463 driswCreateDrawable(struct glx_screen *base, XID xDrawable,
464 GLXDrawable drawable, int type,
465 struct glx_config *modes)
466 {
467 struct drisw_drawable *pdp;
468 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
469 unsigned depth;
470 struct drisw_screen *psc = (struct drisw_screen *) base;
471 Display *dpy = psc->base.dpy;
472
473 xcb_connection_t *conn = XGetXCBConnection(dpy);
474 xcb_generic_error_t *error;
475 xcb_get_geometry_cookie_t cookie = xcb_get_geometry(conn, xDrawable);
476 xcb_get_geometry_reply_t *reply = xcb_get_geometry_reply(conn, cookie, &error);
477 if (reply)
478 depth = reply->depth;
479 free(reply);
480 if (!reply || error)
481 return NULL;
482
483 pdp = calloc(1, sizeof(*pdp));
484 if (!pdp)
485 return NULL;
486
487 pdp->base.xDrawable = xDrawable;
488 pdp->base.drawable = drawable;
489 pdp->base.psc = &psc->base;
490 pdp->config = modes;
491 pdp->gc = XCreateGC(dpy, xDrawable, 0, NULL);
492 pdp->xDepth = 0;
493
494 /* Use the visual depth, if this fbconfig corresponds to a visual */
495 if (pdp->config->visualID != 0) {
496 int matches = 0;
497 XVisualInfo *visinfo, template;
498
499 template.visualid = pdp->config->visualID;
500 template.screen = pdp->config->screen;
501 visinfo = XGetVisualInfo(dpy, VisualIDMask | VisualScreenMask,
502 &template, &matches);
503
504 if (visinfo && matches) {
505 pdp->xDepth = visinfo->depth;
506 XFree(visinfo);
507 }
508 }
509
510 /* Otherwise, or if XGetVisualInfo failed, ask the server */
511 if (pdp->xDepth == 0) {
512 pdp->xDepth = depth;
513 }
514
515 pdp->swapInterval = dri_get_initial_swap_interval(psc->base.frontend_screen);
516 /* Create a new drawable */
517 pdp->base.dri_drawable = dri_create_drawable(psc->base.frontend_screen, config->driConfig, !(type & GLX_WINDOW_BIT), pdp);
518 if (psc->kopper)
519 kopperSetSwapInterval(pdp->base.dri_drawable, pdp->swapInterval);
520
521 if (!pdp->base.dri_drawable) {
522 XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
523 free(pdp);
524 return NULL;
525 }
526
527 pdp->base.destroyDrawable = driswDestroyDrawable;
528
529 return &pdp->base;
530 }
531
532 static int64_t
driswSwapBuffers(__GLXDRIdrawable * pdraw,int64_t target_msc,int64_t divisor,int64_t remainder,Bool flush)533 driswSwapBuffers(__GLXDRIdrawable * pdraw,
534 int64_t target_msc, int64_t divisor, int64_t remainder,
535 Bool flush)
536 {
537 struct drisw_screen *psc = (struct drisw_screen *) pdraw->psc;
538
539 (void) target_msc;
540 (void) divisor;
541 (void) remainder;
542
543 if (flush) {
544 glFlush();
545 }
546
547 if (psc->kopper)
548 return kopperSwapBuffers(pdraw->dri_drawable, 0);
549
550 driSwapBuffers(pdraw->dri_drawable);
551
552 return 0;
553 }
554
555 static void
drisw_copy_sub_buffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)556 drisw_copy_sub_buffer(__GLXDRIdrawable * pdraw,
557 int x, int y, int width, int height, Bool flush)
558 {
559 if (flush) {
560 glFlush();
561 }
562
563 driswCopySubBuffer(pdraw->dri_drawable, x, y, width, height);
564 }
565
566 static int
check_xshm(Display * dpy)567 check_xshm(Display *dpy)
568 {
569 xcb_connection_t *c = XGetXCBConnection(dpy);
570 xcb_void_cookie_t cookie;
571 xcb_generic_error_t *error;
572 int ret = True;
573 xcb_query_extension_cookie_t shm_cookie;
574 xcb_query_extension_reply_t *shm_reply;
575 bool has_mit_shm;
576
577 shm_cookie = xcb_query_extension(c, 7, "MIT-SHM");
578 shm_reply = xcb_query_extension_reply(c, shm_cookie, NULL);
579 xshm_opcode = shm_reply->major_opcode;
580
581 has_mit_shm = shm_reply->present;
582 free(shm_reply);
583 if (!has_mit_shm)
584 return False;
585
586 cookie = xcb_shm_detach_checked(c, 0);
587 if ((error = xcb_request_check(c, cookie))) {
588 /* BadRequest means we're a remote client. If we were local we'd
589 * expect BadValue since 'info' has an invalid segment name.
590 */
591 if (error->error_code == BadRequest)
592 ret = False;
593 free(error);
594 }
595
596 return ret;
597 }
598
599 static int
driswKopperSetSwapInterval(__GLXDRIdrawable * pdraw,int interval)600 driswKopperSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
601 {
602 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
603 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
604
605 if (!dri_valid_swap_interval(psc->base.frontend_screen, interval))
606 return GLX_BAD_VALUE;
607
608 kopperSetSwapInterval(pdp->base.dri_drawable, interval);
609 pdp->swapInterval = interval;
610
611 return 0;
612 }
613
614 static int
kopperGetSwapInterval(__GLXDRIdrawable * pdraw)615 kopperGetSwapInterval(__GLXDRIdrawable *pdraw)
616 {
617 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
618
619 return pdp->swapInterval;
620 }
621
622 struct glx_screen *
driswCreateScreen(int screen,struct glx_display * priv,enum glx_driver glx_driver,bool driver_name_is_inferred)623 driswCreateScreen(int screen, struct glx_display *priv, enum glx_driver glx_driver, bool driver_name_is_inferred)
624 {
625 __GLXDRIscreen *psp;
626 struct drisw_screen *psc;
627 const __DRIextension **loader_extensions_local;
628 bool kopper_disable = debug_get_bool_option("LIBGL_KOPPER_DISABLE", false);
629
630 /* this is only relevant if zink bits are set */
631 glx_driver &= (GLX_DRIVER_ZINK_INFER | GLX_DRIVER_ZINK_YES);
632 const char *driver = glx_driver && !kopper_disable ? "zink" : "swrast";
633
634 psc = calloc(1, sizeof *psc);
635 if (psc == NULL)
636 return NULL;
637 psc->kopper = !strcmp(driver, "zink");
638
639 if (!glx_screen_init(&psc->base, screen, priv)) {
640 free(psc);
641 return NULL;
642 }
643
644 psc->base.driverName = strdup(driver);
645
646 if (glx_driver)
647 loader_extensions_local = kopper_extensions_noshm;
648 else if (!check_xshm(psc->base.dpy))
649 loader_extensions_local = loader_extensions_noshm;
650 else
651 loader_extensions_local = loader_extensions_shm;
652 priv->driver = glx_driver ? GLX_DRIVER_ZINK_YES : GLX_DRIVER_SW;
653
654 if (!dri_screen_init(&psc->base, priv, screen, -1, loader_extensions_local, driver_name_is_inferred)) {
655 if (!glx_driver || !driver_name_is_inferred)
656 ErrorMessageF("glx: failed to create drisw screen\n");
657 goto handle_error;
658 }
659
660 psc->base.context_vtable = &drisw_context_vtable;
661 psp = &psc->base.driScreen;
662 psc->base.can_EXT_texture_from_pixmap = true;
663 psp->createDrawable = driswCreateDrawable;
664 psp->swapBuffers = driswSwapBuffers;
665
666 if (!glx_driver)
667 psp->copySubBuffer = drisw_copy_sub_buffer;
668
669 if (psc->kopper) {
670 psp->setSwapInterval = driswKopperSetSwapInterval;
671 psp->getSwapInterval = kopperGetSwapInterval;
672 psp->maxSwapInterval = 1;
673 }
674
675 return &psc->base;
676
677 handle_error:
678
679 glx_screen_cleanup(&psc->base);
680 free(psc);
681
682 if (glx_driver & GLX_DRIVER_ZINK_YES && !driver_name_is_inferred)
683 CriticalErrorMessageF("failed to load driver: %s\n", driver);
684
685 return NULL;
686 }
687
688 #endif /* GLX_DIRECT_RENDERING */
689