drisw: Simplify GC setup
[mesa.git] / src / glx / drisw_glx.c
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 <X11/Xlib.h>
27 #include "glxclient.h"
28 #include <dlfcn.h>
29 #include "dri_common.h"
30 #include "drisw_priv.h"
31 #include <X11/extensions/shmproto.h>
32 #include <assert.h>
33
34 static Bool
35 driswCreateGCs(struct drisw_drawable * pdp,
36 Display * dpy, XID drawable, int visualid)
37 {
38 long visMask;
39 XVisualInfo visTemp;
40 int num_visuals;
41
42 pdp->gc = XCreateGC(dpy, drawable, 0, NULL);
43
44 /* visual */
45 visTemp.visualid = visualid;
46 visMask = VisualIDMask;
47 pdp->visinfo = XGetVisualInfo(dpy, visMask, &visTemp, &num_visuals);
48
49 if (!pdp->visinfo || num_visuals == 0)
50 return False;
51
52 return True;
53 }
54
55 static int xshm_error = 0;
56 static int xshm_opcode = -1;
57
58 /**
59 * Catches potential Xlib errors.
60 */
61 static int
62 handle_xerror(Display *dpy, XErrorEvent *event)
63 {
64 (void) dpy;
65
66 assert(xshm_opcode != -1);
67 if (event->request_code != xshm_opcode)
68 return 0;
69
70 xshm_error = event->error_code;
71 return 0;
72 }
73
74 static Bool
75 XCreateDrawable(struct drisw_drawable * pdp, int shmid, Display * dpy)
76 {
77 if (pdp->ximage) {
78 XDestroyImage(pdp->ximage);
79 pdp->ximage = NULL;
80 }
81
82 if (!xshm_error && shmid >= 0) {
83 pdp->shminfo.shmid = shmid;
84 pdp->ximage = XShmCreateImage(dpy,
85 pdp->visinfo->visual,
86 pdp->visinfo->depth,
87 ZPixmap, /* format */
88 NULL, /* data */
89 &pdp->shminfo, /* shminfo */
90 0, 0); /* width, height */
91 if (pdp->ximage != NULL) {
92 int (*old_handler)(Display *, XErrorEvent *);
93
94 /* dispatch pending errors */
95 XSync(dpy, False);
96
97 old_handler = XSetErrorHandler(handle_xerror);
98 /* This may trigger the X protocol error we're ready to catch: */
99 XShmAttach(dpy, &pdp->shminfo);
100 XSync(dpy, False);
101
102 if (xshm_error) {
103 /* we are on a remote display, this error is normal, don't print it */
104 XDestroyImage(pdp->ximage);
105 pdp->ximage = NULL;
106 }
107
108 (void) XSetErrorHandler(old_handler);
109 }
110 }
111
112 if (pdp->ximage == NULL) {
113 pdp->shminfo.shmid = -1;
114 pdp->ximage = XCreateImage(dpy,
115 pdp->visinfo->visual,
116 pdp->visinfo->depth,
117 ZPixmap, 0, /* format, offset */
118 NULL, /* data */
119 0, 0, /* width, height */
120 32, /* bitmap_pad */
121 0); /* bytes_per_line */
122 }
123
124 /**
125 * swrast does not handle 24-bit depth with 24 bpp, so let X do the
126 * the conversion for us.
127 */
128 if (pdp->ximage->bits_per_pixel == 24)
129 pdp->ximage->bits_per_pixel = 32;
130
131 return True;
132 }
133
134 static void
135 XDestroyDrawable(struct drisw_drawable * pdp, Display * dpy, XID drawable)
136 {
137 if (pdp->ximage)
138 XDestroyImage(pdp->ximage);
139
140 if (pdp->shminfo.shmid > 0)
141 XShmDetach(dpy, &pdp->shminfo);
142
143 free(pdp->visinfo);
144
145 XFreeGC(dpy, pdp->gc);
146 }
147
148 /**
149 * swrast loader functions
150 */
151
152 static void
153 swrastGetDrawableInfo(__DRIdrawable * draw,
154 int *x, int *y, int *w, int *h,
155 void *loaderPrivate)
156 {
157 struct drisw_drawable *pdp = loaderPrivate;
158 __GLXDRIdrawable *pdraw = &(pdp->base);
159 Display *dpy = pdraw->psc->dpy;
160 Drawable drawable;
161
162 Window root;
163 unsigned uw, uh, bw, depth;
164
165 drawable = pdraw->xDrawable;
166
167 XGetGeometry(dpy, drawable, &root, x, y, &uw, &uh, &bw, &depth);
168 *w = uw;
169 *h = uh;
170 }
171
172 /**
173 * Align renderbuffer pitch.
174 *
175 * This should be chosen by the driver and the loader (libGL, xserver/glx)
176 * should use the driver provided pitch.
177 *
178 * It seems that the xorg loader (that is the xserver loading swrast_dri for
179 * indirect rendering, not client-side libGL) requires that the pitch is
180 * exactly the image width padded to 32 bits. XXX
181 *
182 * The above restriction can probably be overcome by using ScratchPixmap and
183 * CopyArea in the xserver, similar to ShmPutImage, and setting the width of
184 * the scratch pixmap to 'pitch / cpp'.
185 */
186 static inline int
187 bytes_per_line(unsigned pitch_bits, unsigned mul)
188 {
189 unsigned mask = mul - 1;
190
191 return ((pitch_bits + mask) & ~mask) / 8;
192 }
193
194 static void
195 swrastXPutImage(__DRIdrawable * draw, int op,
196 int srcx, int srcy, int x, int y,
197 int w, int h, int stride,
198 int shmid, char *data, void *loaderPrivate)
199 {
200 struct drisw_drawable *pdp = loaderPrivate;
201 __GLXDRIdrawable *pdraw = &(pdp->base);
202 Display *dpy = pdraw->psc->dpy;
203 Drawable drawable;
204 XImage *ximage;
205 GC gc = pdp->gc;
206
207 if (!pdp->ximage || shmid != pdp->shminfo.shmid) {
208 if (!XCreateDrawable(pdp, shmid, dpy))
209 return;
210 }
211
212 drawable = pdraw->xDrawable;
213 ximage = pdp->ximage;
214 ximage->bytes_per_line = stride ? stride : bytes_per_line(w * ximage->bits_per_pixel, 32);
215 ximage->data = data;
216
217 if (pdp->shminfo.shmid >= 0) {
218 ximage->width = ximage->bytes_per_line / ((ximage->bits_per_pixel + 7)/ 8);
219 ximage->height = h;
220 XShmPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h, False);
221 XSync(dpy, False);
222 } else {
223 ximage->width = w;
224 ximage->height = h;
225 XPutImage(dpy, drawable, gc, ximage, srcx, srcy, x, y, w, h);
226 }
227 ximage->data = NULL;
228 }
229
230 static void
231 swrastPutImageShm(__DRIdrawable * draw, int op,
232 int x, int y, int w, int h, int stride,
233 int shmid, char *shmaddr, unsigned offset,
234 void *loaderPrivate)
235 {
236 struct drisw_drawable *pdp = loaderPrivate;
237
238 pdp->shminfo.shmaddr = shmaddr;
239 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, shmid,
240 shmaddr + offset, loaderPrivate);
241 }
242
243 static void
244 swrastPutImageShm2(__DRIdrawable * draw, int op,
245 int x, int y,
246 int w, int h, int stride,
247 int shmid, char *shmaddr, unsigned offset,
248 void *loaderPrivate)
249 {
250 struct drisw_drawable *pdp = loaderPrivate;
251
252 pdp->shminfo.shmaddr = shmaddr;
253 swrastXPutImage(draw, op, x, 0, x, y, w, h, stride, shmid,
254 shmaddr + offset, loaderPrivate);
255 }
256
257 static void
258 swrastPutImage2(__DRIdrawable * draw, int op,
259 int x, int y, int w, int h, int stride,
260 char *data, void *loaderPrivate)
261 {
262 swrastXPutImage(draw, op, 0, 0, x, y, w, h, stride, -1,
263 data, loaderPrivate);
264 }
265
266 static void
267 swrastPutImage(__DRIdrawable * draw, int op,
268 int x, int y, int w, int h,
269 char *data, void *loaderPrivate)
270 {
271 swrastXPutImage(draw, op, 0, 0, x, y, w, h, 0, -1,
272 data, loaderPrivate);
273 }
274
275 static void
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
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 void
313 swrastGetImageShm(__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;
326 }
327 readable = pread->xDrawable;
328
329 ximage = prp->ximage;
330 ximage->data = prp->shminfo.shmaddr; /* no offset */
331 ximage->width = w;
332 ximage->height = h;
333 ximage->bytes_per_line = bytes_per_line(w * ximage->bits_per_pixel, 32);
334
335 XShmGetImage(dpy, readable, ximage, x, y, ~0L);
336 }
337
338 static const __DRIswrastLoaderExtension swrastLoaderExtension_shm = {
339 .base = {__DRI_SWRAST_LOADER, 5 },
340
341 .getDrawableInfo = swrastGetDrawableInfo,
342 .putImage = swrastPutImage,
343 .getImage = swrastGetImage,
344 .putImage2 = swrastPutImage2,
345 .getImage2 = swrastGetImage2,
346 .putImageShm = swrastPutImageShm,
347 .getImageShm = swrastGetImageShm,
348 .putImageShm2 = swrastPutImageShm2,
349 };
350
351 static const __DRIextension *loader_extensions_shm[] = {
352 &swrastLoaderExtension_shm.base,
353 NULL
354 };
355
356 static const __DRIswrastLoaderExtension swrastLoaderExtension = {
357 .base = {__DRI_SWRAST_LOADER, 3 },
358
359 .getDrawableInfo = swrastGetDrawableInfo,
360 .putImage = swrastPutImage,
361 .getImage = swrastGetImage,
362 .putImage2 = swrastPutImage2,
363 .getImage2 = swrastGetImage2,
364 };
365
366 static const __DRIextension *loader_extensions_noshm[] = {
367 &swrastLoaderExtension.base,
368 NULL
369 };
370
371 /**
372 * GLXDRI functions
373 */
374
375 static void
376 drisw_destroy_context(struct glx_context *context)
377 {
378 struct drisw_context *pcp = (struct drisw_context *) context;
379 struct drisw_screen *psc = (struct drisw_screen *) context->psc;
380
381 driReleaseDrawables(&pcp->base);
382
383 free((char *) context->extensions);
384
385 (*psc->core->destroyContext) (pcp->driContext);
386
387 free(pcp);
388 }
389
390 static int
391 drisw_bind_context(struct glx_context *context, struct glx_context *old,
392 GLXDrawable draw, GLXDrawable read)
393 {
394 struct drisw_context *pcp = (struct drisw_context *) context;
395 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
396 struct drisw_drawable *pdraw, *pread;
397
398 pdraw = (struct drisw_drawable *) driFetchDrawable(context, draw);
399 pread = (struct drisw_drawable *) driFetchDrawable(context, read);
400
401 driReleaseDrawables(&pcp->base);
402
403 if ((*psc->core->bindContext) (pcp->driContext,
404 pdraw ? pdraw->driDrawable : NULL,
405 pread ? pread->driDrawable : NULL))
406 return Success;
407
408 return GLXBadContext;
409 }
410
411 static void
412 drisw_unbind_context(struct glx_context *context, struct glx_context *new)
413 {
414 struct drisw_context *pcp = (struct drisw_context *) context;
415 struct drisw_screen *psc = (struct drisw_screen *) pcp->base.psc;
416
417 (*psc->core->unbindContext) (pcp->driContext);
418 }
419
420 static void
421 drisw_bind_tex_image(Display * dpy,
422 GLXDrawable drawable,
423 int buffer, const int *attrib_list)
424 {
425 struct glx_context *gc = __glXGetCurrentContext();
426 struct drisw_context *pcp = (struct drisw_context *) gc;
427 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
428 struct drisw_drawable *pdraw = (struct drisw_drawable *) base;
429 struct drisw_screen *psc;
430
431 __glXInitialize(dpy);
432
433 if (pdraw != NULL) {
434 psc = (struct drisw_screen *) base->psc;
435
436 if (!psc->texBuffer)
437 return;
438
439 if (psc->texBuffer->base.version >= 2 &&
440 psc->texBuffer->setTexBuffer2 != NULL) {
441 (*psc->texBuffer->setTexBuffer2) (pcp->driContext,
442 pdraw->base.textureTarget,
443 pdraw->base.textureFormat,
444 pdraw->driDrawable);
445 }
446 else {
447 (*psc->texBuffer->setTexBuffer) (pcp->driContext,
448 pdraw->base.textureTarget,
449 pdraw->driDrawable);
450 }
451 }
452 }
453
454 static void
455 drisw_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer)
456 {
457 struct glx_context *gc = __glXGetCurrentContext();
458 struct drisw_context *pcp = (struct drisw_context *) gc;
459 __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable);
460 struct glx_display *dpyPriv = __glXInitialize(dpy);
461 struct drisw_drawable *pdraw = (struct drisw_drawable *) base;
462 struct drisw_screen *psc;
463
464 if (dpyPriv != NULL && pdraw != NULL) {
465 psc = (struct drisw_screen *) base->psc;
466
467 if (!psc->texBuffer)
468 return;
469
470 if (psc->texBuffer->base.version >= 3 &&
471 psc->texBuffer->releaseTexBuffer != NULL) {
472 (*psc->texBuffer->releaseTexBuffer) (pcp->driContext,
473 pdraw->base.textureTarget,
474 pdraw->driDrawable);
475 }
476 }
477 }
478
479 static const struct glx_context_vtable drisw_context_vtable = {
480 .destroy = drisw_destroy_context,
481 .bind = drisw_bind_context,
482 .unbind = drisw_unbind_context,
483 .wait_gl = NULL,
484 .wait_x = NULL,
485 .use_x_font = DRI_glXUseXFont,
486 .bind_tex_image = drisw_bind_tex_image,
487 .release_tex_image = drisw_release_tex_image,
488 .get_proc_address = NULL,
489 };
490
491 static struct glx_context *
492 drisw_create_context(struct glx_screen *base,
493 struct glx_config *config_base,
494 struct glx_context *shareList, int renderType)
495 {
496 struct drisw_context *pcp, *pcp_shared;
497 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
498 struct drisw_screen *psc = (struct drisw_screen *) base;
499 __DRIcontext *shared = NULL;
500
501 if (!psc->base.driScreen)
502 return NULL;
503
504 /* Check the renderType value */
505 if (!validate_renderType_against_config(config_base, renderType))
506 return NULL;
507
508 if (shareList) {
509 /* If the shareList context is not a DRISW context, we cannot possibly
510 * create a DRISW context that shares it.
511 */
512 if (shareList->vtable->destroy != drisw_destroy_context) {
513 return NULL;
514 }
515
516 pcp_shared = (struct drisw_context *) shareList;
517 shared = pcp_shared->driContext;
518 }
519
520 pcp = calloc(1, sizeof *pcp);
521 if (pcp == NULL)
522 return NULL;
523
524 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
525 free(pcp);
526 return NULL;
527 }
528
529 pcp->base.renderType = renderType;
530
531 pcp->driContext =
532 (*psc->core->createNewContext) (psc->driScreen,
533 config->driConfig, shared, pcp);
534 if (pcp->driContext == NULL) {
535 free(pcp);
536 return NULL;
537 }
538
539 pcp->base.vtable = &drisw_context_vtable;
540
541 return &pcp->base;
542 }
543
544 static struct glx_context *
545 drisw_create_context_attribs(struct glx_screen *base,
546 struct glx_config *config_base,
547 struct glx_context *shareList,
548 unsigned num_attribs,
549 const uint32_t *attribs,
550 unsigned *error)
551 {
552 struct drisw_context *pcp, *pcp_shared;
553 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
554 struct drisw_screen *psc = (struct drisw_screen *) base;
555 __DRIcontext *shared = NULL;
556
557 uint32_t minor_ver;
558 uint32_t major_ver;
559 uint32_t renderType;
560 uint32_t flags;
561 unsigned api;
562 int reset;
563 int release;
564 uint32_t ctx_attribs[2 * 5];
565 unsigned num_ctx_attribs = 0;
566
567 if (!psc->base.driScreen)
568 return NULL;
569
570 if (psc->swrast->base.version < 3)
571 return NULL;
572
573 /* Remap the GLX tokens to DRI2 tokens.
574 */
575 if (!dri2_convert_glx_attribs(num_attribs, attribs,
576 &major_ver, &minor_ver, &renderType, &flags,
577 &api, &reset, &release, error))
578 return NULL;
579
580 if (!dri2_check_no_error(flags, shareList, major_ver, error))
581 return NULL;
582
583 /* Check the renderType value */
584 if (!validate_renderType_against_config(config_base, renderType)) {
585 return NULL;
586 }
587
588 if (reset != __DRI_CTX_RESET_NO_NOTIFICATION)
589 return NULL;
590
591 if (release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH &&
592 release != __DRI_CTX_RELEASE_BEHAVIOR_NONE)
593 return NULL;
594
595 if (shareList) {
596 pcp_shared = (struct drisw_context *) shareList;
597 shared = pcp_shared->driContext;
598 }
599
600 pcp = calloc(1, sizeof *pcp);
601 if (pcp == NULL)
602 return NULL;
603
604 if (!glx_context_init(&pcp->base, &psc->base, config_base)) {
605 free(pcp);
606 return NULL;
607 }
608
609 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION;
610 ctx_attribs[num_ctx_attribs++] = major_ver;
611 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION;
612 ctx_attribs[num_ctx_attribs++] = minor_ver;
613 if (release != __DRI_CTX_RELEASE_BEHAVIOR_FLUSH) {
614 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RELEASE_BEHAVIOR;
615 ctx_attribs[num_ctx_attribs++] = release;
616 }
617
618 if (flags != 0) {
619 ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS;
620
621 /* The current __DRI_CTX_FLAG_* values are identical to the
622 * GLX_CONTEXT_*_BIT values.
623 */
624 ctx_attribs[num_ctx_attribs++] = flags;
625
626 if (flags & __DRI_CTX_FLAG_NO_ERROR)
627 pcp->base.noError = GL_TRUE;
628 }
629
630 pcp->base.renderType = renderType;
631
632 pcp->driContext =
633 (*psc->swrast->createContextAttribs) (psc->driScreen,
634 api,
635 config ? config->driConfig : 0,
636 shared,
637 num_ctx_attribs / 2,
638 ctx_attribs,
639 error,
640 pcp);
641 if (pcp->driContext == NULL) {
642 free(pcp);
643 return NULL;
644 }
645
646 pcp->base.vtable = &drisw_context_vtable;
647
648 return &pcp->base;
649 }
650
651 static void
652 driswDestroyDrawable(__GLXDRIdrawable * pdraw)
653 {
654 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
655 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
656
657 (*psc->core->destroyDrawable) (pdp->driDrawable);
658
659 XDestroyDrawable(pdp, pdraw->psc->dpy, pdraw->drawable);
660 free(pdp);
661 }
662
663 static __GLXDRIdrawable *
664 driswCreateDrawable(struct glx_screen *base, XID xDrawable,
665 GLXDrawable drawable, struct glx_config *modes)
666 {
667 struct drisw_drawable *pdp;
668 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) modes;
669 struct drisw_screen *psc = (struct drisw_screen *) base;
670 Bool ret;
671 const __DRIswrastExtension *swrast = psc->swrast;
672
673 pdp = calloc(1, sizeof(*pdp));
674 if (!pdp)
675 return NULL;
676
677 pdp->base.xDrawable = xDrawable;
678 pdp->base.drawable = drawable;
679 pdp->base.psc = &psc->base;
680
681 ret = driswCreateGCs(pdp, psc->base.dpy, xDrawable, modes->visualID);
682 if (!ret) {
683 free(pdp);
684 return NULL;
685 }
686
687 /* Create a new drawable */
688 pdp->driDrawable =
689 (*swrast->createNewDrawable) (psc->driScreen, config->driConfig, pdp);
690
691 if (!pdp->driDrawable) {
692 XDestroyDrawable(pdp, psc->base.dpy, xDrawable);
693 free(pdp);
694 return NULL;
695 }
696
697 pdp->base.destroyDrawable = driswDestroyDrawable;
698
699 return &pdp->base;
700 }
701
702 static int64_t
703 driswSwapBuffers(__GLXDRIdrawable * pdraw,
704 int64_t target_msc, int64_t divisor, int64_t remainder,
705 Bool flush)
706 {
707 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
708 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
709
710 (void) target_msc;
711 (void) divisor;
712 (void) remainder;
713
714 if (flush) {
715 glFlush();
716 }
717
718 (*psc->core->swapBuffers) (pdp->driDrawable);
719
720 return 0;
721 }
722
723 static void
724 driswCopySubBuffer(__GLXDRIdrawable * pdraw,
725 int x, int y, int width, int height, Bool flush)
726 {
727 struct drisw_drawable *pdp = (struct drisw_drawable *) pdraw;
728 struct drisw_screen *psc = (struct drisw_screen *) pdp->base.psc;
729
730 if (flush) {
731 glFlush();
732 }
733
734 (*psc->copySubBuffer->copySubBuffer) (pdp->driDrawable,
735 x, y, width, height);
736 }
737
738 static void
739 driswDestroyScreen(struct glx_screen *base)
740 {
741 struct drisw_screen *psc = (struct drisw_screen *) base;
742
743 /* Free the direct rendering per screen data */
744 (*psc->core->destroyScreen) (psc->driScreen);
745 driDestroyConfigs(psc->driver_configs);
746 psc->driScreen = NULL;
747 if (psc->driver)
748 dlclose(psc->driver);
749 free(psc);
750 }
751
752 #define SWRAST_DRIVER_NAME "swrast"
753
754 static const struct glx_screen_vtable drisw_screen_vtable = {
755 .create_context = drisw_create_context,
756 .create_context_attribs = drisw_create_context_attribs,
757 .query_renderer_integer = drisw_query_renderer_integer,
758 .query_renderer_string = drisw_query_renderer_string,
759 };
760
761 static void
762 driswBindExtensions(struct drisw_screen *psc, const __DRIextension **extensions)
763 {
764 int i;
765
766 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
767
768 if (psc->swrast->base.version >= 3) {
769 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context");
770 __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile");
771
772 /* DRISW version >= 2 implies support for OpenGL ES.
773 */
774 __glXEnableDirectExtension(&psc->base,
775 "GLX_EXT_create_context_es_profile");
776 __glXEnableDirectExtension(&psc->base,
777 "GLX_EXT_create_context_es2_profile");
778 }
779
780 if (psc->copySubBuffer)
781 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
782
783 /* FIXME: Figure out what other extensions can be ported here from dri2. */
784 for (i = 0; extensions[i]; i++) {
785 if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) {
786 psc->texBuffer = (__DRItexBufferExtension *) extensions[i];
787 __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap");
788 }
789 /* DRISW version 3 is also required because GLX_MESA_query_renderer
790 * requires GLX_ARB_create_context_profile.
791 */
792 if (psc->swrast->base.version >= 3
793 && strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) {
794 psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i];
795 __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer");
796 }
797 if (strcmp(extensions[i]->name, __DRI2_FLUSH_CONTROL) == 0) {
798 __glXEnableDirectExtension(&psc->base,
799 "GLX_ARB_context_flush_control");
800 }
801 }
802 }
803
804 static int
805 check_xshm(Display *dpy)
806 {
807 int (*old_handler)(Display *, XErrorEvent *);
808
809 int ignore;
810 XShmSegmentInfo info = { 0, };
811
812 if (!XQueryExtension(dpy, "MIT-SHM", &xshm_opcode, &ignore, &ignore))
813 return False;
814
815 old_handler = XSetErrorHandler(handle_xerror);
816 XShmDetach(dpy, &info);
817 XSync(dpy, False);
818 (void) XSetErrorHandler(old_handler);
819
820 /* BadRequest means we're a remote client. If we were local we'd
821 * expect BadValue since 'info' has an invalid segment name.
822 */
823 if (xshm_error == BadRequest)
824 return False;
825
826 xshm_error = 0;
827 return True;
828 }
829
830 static struct glx_screen *
831 driswCreateScreen(int screen, struct glx_display *priv)
832 {
833 __GLXDRIscreen *psp;
834 const __DRIconfig **driver_configs;
835 const __DRIextension **extensions;
836 struct drisw_screen *psc;
837 struct glx_config *configs = NULL, *visuals = NULL;
838 int i;
839 const __DRIextension **loader_extensions_local;
840
841 psc = calloc(1, sizeof *psc);
842 if (psc == NULL)
843 return NULL;
844
845 if (!glx_screen_init(&psc->base, screen, priv)) {
846 free(psc);
847 return NULL;
848 }
849
850 extensions = driOpenDriver(SWRAST_DRIVER_NAME, &psc->driver);
851 if (extensions == NULL)
852 goto handle_error;
853
854 if (!check_xshm(psc->base.dpy))
855 loader_extensions_local = loader_extensions_noshm;
856 else
857 loader_extensions_local = loader_extensions_shm;
858
859 for (i = 0; extensions[i]; i++) {
860 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
861 psc->core = (__DRIcoreExtension *) extensions[i];
862 if (strcmp(extensions[i]->name, __DRI_SWRAST) == 0)
863 psc->swrast = (__DRIswrastExtension *) extensions[i];
864 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0)
865 psc->copySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
866 }
867
868 if (psc->core == NULL || psc->swrast == NULL) {
869 ErrorMessageF("core dri extension not found\n");
870 goto handle_error;
871 }
872
873 if (psc->swrast->base.version >= 4) {
874 psc->driScreen =
875 psc->swrast->createNewScreen2(screen, loader_extensions_local,
876 extensions,
877 &driver_configs, psc);
878 } else {
879 psc->driScreen =
880 psc->swrast->createNewScreen(screen, loader_extensions_local,
881 &driver_configs, psc);
882 }
883 if (psc->driScreen == NULL) {
884 ErrorMessageF("failed to create dri screen\n");
885 goto handle_error;
886 }
887
888 extensions = psc->core->getExtensions(psc->driScreen);
889 driswBindExtensions(psc, extensions);
890
891 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
892 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
893
894 if (!configs || !visuals) {
895 ErrorMessageF("No matching fbConfigs or visuals found\n");
896 goto handle_error;
897 }
898
899 glx_config_destroy_list(psc->base.configs);
900 psc->base.configs = configs;
901 glx_config_destroy_list(psc->base.visuals);
902 psc->base.visuals = visuals;
903
904 psc->driver_configs = driver_configs;
905
906 psc->base.vtable = &drisw_screen_vtable;
907 psp = &psc->vtable;
908 psc->base.driScreen = psp;
909 psp->destroyScreen = driswDestroyScreen;
910 psp->createDrawable = driswCreateDrawable;
911 psp->swapBuffers = driswSwapBuffers;
912
913 if (psc->copySubBuffer)
914 psp->copySubBuffer = driswCopySubBuffer;
915
916 return &psc->base;
917
918 handle_error:
919 if (configs)
920 glx_config_destroy_list(configs);
921 if (visuals)
922 glx_config_destroy_list(visuals);
923 if (psc->driScreen)
924 psc->core->destroyScreen(psc->driScreen);
925 psc->driScreen = NULL;
926
927 if (psc->driver)
928 dlclose(psc->driver);
929 glx_screen_cleanup(&psc->base);
930 free(psc);
931
932 CriticalErrorMessageF("failed to load driver: %s\n", SWRAST_DRIVER_NAME);
933
934 return NULL;
935 }
936
937 /* Called from __glXFreeDisplayPrivate.
938 */
939 static void
940 driswDestroyDisplay(__GLXDRIdisplay * dpy)
941 {
942 free(dpy);
943 }
944
945 /*
946 * Allocate, initialize and return a __DRIdisplayPrivate object.
947 * This is called from __glXInitialize() when we are given a new
948 * display pointer.
949 */
950 _X_HIDDEN __GLXDRIdisplay *
951 driswCreateDisplay(Display * dpy)
952 {
953 struct drisw_display *pdpyp;
954
955 pdpyp = malloc(sizeof *pdpyp);
956 if (pdpyp == NULL)
957 return NULL;
958
959 pdpyp->base.destroyDisplay = driswDestroyDisplay;
960 pdpyp->base.createScreen = driswCreateScreen;
961
962 return &pdpyp->base;
963 }
964
965 #endif /* GLX_DIRECT_RENDERING */