xref: /aosp_15_r20/external/mesa3d/src/glx/drisw_glx.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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