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