1 /**************************************************************************
2
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 All Rights Reserved.
5
6 Permission is hereby granted, free of charge, to any person obtaining a
7 copy of this software and associated documentation files (the
8 "Software"), to deal in the Software without restriction, including
9 without limitation the rights to use, copy, modify, merge, publish,
10 distribute, sub license, and/or sell copies of the Software, and to
11 permit persons to whom the Software is furnished to do so, subject to
12 the following conditions:
13
14 The above copyright notice and this permission notice (including the
15 next paragraph) shall be included in all copies or substantial portions
16 of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
22 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29 * Authors:
30 * Kevin E. Martin <kevin@precisioninsight.com>
31 * Brian Paul <brian@precisioninsight.com>
32 *
33 */
34
35 #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL)
36
37 #include <X11/Xlib.h>
38 #include <X11/extensions/Xfixes.h>
39 #include <X11/extensions/Xdamage.h>
40 #include "glxclient.h"
41 #include "xf86dri.h"
42 #include "dri2.h"
43 #include "dri_sarea.h"
44 #include <dlfcn.h>
45 #include <sys/time.h>
46 #include <sys/types.h>
47 #include <sys/mman.h>
48 #include "xf86drm.h"
49 #include "dri_common.h"
50
51 struct dri_display
52 {
53 __GLXDRIdisplay base;
54
55 /*
56 ** XFree86-DRI version information
57 */
58 int driMajor;
59 int driMinor;
60 int driPatch;
61 };
62
63 struct dri_screen
64 {
65 struct glx_screen base;
66
67 __DRIscreen *driScreen;
68 __GLXDRIscreen vtable;
69 const __DRIlegacyExtension *legacy;
70 const __DRIcoreExtension *core;
71 const __DRIswapControlExtension *swapControl;
72 const __DRImediaStreamCounterExtension *msc;
73 const __DRIconfig **driver_configs;
74 const __DRIcopySubBufferExtension *driCopySubBuffer;
75
76 void *driver;
77 int fd;
78 };
79
80 struct dri_context
81 {
82 struct glx_context base;
83 __DRIcontext *driContext;
84 XID hwContextID;
85 };
86
87 struct dri_drawable
88 {
89 __GLXDRIdrawable base;
90
91 __DRIdrawable *driDrawable;
92 };
93
94 static char *
dri_get_driver_name(struct glx_screen * psc)95 dri_get_driver_name(struct glx_screen *psc)
96 {
97 Display *dpy = psc->dpy;
98 int scrNum = psc->scr;
99 int directCapable;
100 Bool b;
101 int event, error;
102 int driverMajor, driverMinor, driverPatch;
103 char *driverName = NULL;
104
105 if (XF86DRIQueryExtension(dpy, &event, &error)) { /* DRI1 */
106 if (!XF86DRIQueryDirectRenderingCapable(dpy, scrNum, &directCapable)) {
107 ErrorMessageF("XF86DRIQueryDirectRenderingCapable failed\n");
108 return NULL;
109 }
110 if (!directCapable) {
111 ErrorMessageF("XF86DRIQueryDirectRenderingCapable returned false\n");
112 return NULL;
113 }
114
115 b = XF86DRIGetClientDriverName(dpy, scrNum, &driverMajor, &driverMinor,
116 &driverPatch, &driverName);
117 if (!b) {
118 ErrorMessageF("Cannot determine driver name for screen %d\n",
119 scrNum);
120 return NULL;
121 }
122
123 InfoMessageF("XF86DRIGetClientDriverName: %d.%d.%d %s (screen %d)\n",
124 driverMajor, driverMinor, driverPatch, driverName,
125 scrNum);
126
127 return driverName;
128 }
129 return NULL;
130 }
131
132 /**
133 * Get the unadjusted system time (UST). Currently, the UST is measured in
134 * microseconds since Epoc. The actual resolution of the UST may vary from
135 * system to system, and the units may vary from release to release.
136 * Drivers should not call this function directly. They should instead use
137 * \c glXGetProcAddress to obtain a pointer to the function.
138 *
139 * \param ust Location to store the 64-bit UST
140 * \returns Zero on success or a negative errno value on failure.
141 *
142 * \sa glXGetProcAddress, PFNGLXGETUSTPROC
143 *
144 * \since Internal API version 20030317.
145 */
146 static int
__glXGetUST(int64_t * ust)147 __glXGetUST(int64_t * ust)
148 {
149 struct timeval tv;
150
151 if (ust == NULL) {
152 return -EFAULT;
153 }
154
155 if (gettimeofday(&tv, NULL) == 0) {
156 ust[0] = (tv.tv_sec * 1000000) + tv.tv_usec;
157 return 0;
158 }
159 else {
160 return -errno;
161 }
162 }
163
164 static GLboolean
__driGetMSCRate(__DRIdrawable * draw,int32_t * numerator,int32_t * denominator,void * loaderPrivate)165 __driGetMSCRate(__DRIdrawable *draw,
166 int32_t * numerator, int32_t * denominator,
167 void *loaderPrivate)
168 {
169 __GLXDRIdrawable *glxDraw = loaderPrivate;
170
171 return __glxGetMscRate(glxDraw->psc, numerator, denominator);
172 }
173
174 static const __DRIsystemTimeExtension systemTimeExtension = {
175 .base = {__DRI_SYSTEM_TIME, 1 },
176
177 .getUST = __glXGetUST,
178 .getMSCRate = __driGetMSCRate
179 };
180
181 static GLboolean
has_damage_post(Display * dpy)182 has_damage_post(Display * dpy)
183 {
184 static GLboolean inited = GL_FALSE;
185 static GLboolean has_damage;
186
187 if (!inited) {
188 int major, minor;
189
190 if (XDamageQueryVersion(dpy, &major, &minor) &&
191 major == 1 && minor >= 1) {
192 has_damage = GL_TRUE;
193 }
194 else {
195 has_damage = GL_FALSE;
196 }
197 inited = GL_TRUE;
198 }
199
200 return has_damage;
201 }
202
203 static void
__glXReportDamage(__DRIdrawable * driDraw,int x,int y,drm_clip_rect_t * rects,int num_rects,GLboolean front_buffer,void * loaderPrivate)204 __glXReportDamage(__DRIdrawable * driDraw,
205 int x, int y,
206 drm_clip_rect_t * rects, int num_rects,
207 GLboolean front_buffer, void *loaderPrivate)
208 {
209 XRectangle *xrects;
210 XserverRegion region;
211 int i;
212 int x_off, y_off;
213 __GLXDRIdrawable *glxDraw = loaderPrivate;
214 struct glx_screen *psc = glxDraw->psc;
215 Display *dpy = psc->dpy;
216 Drawable drawable;
217
218 if (!has_damage_post(dpy))
219 return;
220
221 if (front_buffer) {
222 x_off = x;
223 y_off = y;
224 drawable = RootWindow(dpy, psc->scr);
225 }
226 else {
227 x_off = 0;
228 y_off = 0;
229 drawable = glxDraw->xDrawable;
230 }
231
232 xrects = malloc(sizeof(XRectangle) * num_rects);
233 if (xrects == NULL)
234 return;
235
236 for (i = 0; i < num_rects; i++) {
237 xrects[i].x = rects[i].x1 + x_off;
238 xrects[i].y = rects[i].y1 + y_off;
239 xrects[i].width = rects[i].x2 - rects[i].x1;
240 xrects[i].height = rects[i].y2 - rects[i].y1;
241 }
242 region = XFixesCreateRegion(dpy, xrects, num_rects);
243 free(xrects);
244 XDamageAdd(dpy, drawable, region);
245 XFixesDestroyRegion(dpy, region);
246 }
247
248 static const __DRIdamageExtension damageExtension = {
249 .base = {__DRI_DAMAGE, 1 },
250
251 .reportDamage = __glXReportDamage,
252 };
253
254 static GLboolean
__glXDRIGetDrawableInfo(__DRIdrawable * drawable,unsigned int * index,unsigned int * stamp,int * X,int * Y,int * W,int * H,int * numClipRects,drm_clip_rect_t ** pClipRects,int * backX,int * backY,int * numBackClipRects,drm_clip_rect_t ** pBackClipRects,void * loaderPrivate)255 __glXDRIGetDrawableInfo(__DRIdrawable * drawable,
256 unsigned int *index, unsigned int *stamp,
257 int *X, int *Y, int *W, int *H,
258 int *numClipRects, drm_clip_rect_t ** pClipRects,
259 int *backX, int *backY,
260 int *numBackClipRects,
261 drm_clip_rect_t ** pBackClipRects,
262 void *loaderPrivate)
263 {
264 __GLXDRIdrawable *glxDraw = loaderPrivate;
265 struct glx_screen *psc = glxDraw->psc;
266 Display *dpy = psc->dpy;
267
268 return XF86DRIGetDrawableInfo(dpy, psc->scr, glxDraw->drawable,
269 index, stamp, X, Y, W, H,
270 numClipRects, pClipRects,
271 backX, backY,
272 numBackClipRects, pBackClipRects);
273 }
274
275 static const __DRIgetDrawableInfoExtension getDrawableInfoExtension = {
276 .base = {__DRI_GET_DRAWABLE_INFO, 1 },
277
278 .getDrawableInfo = __glXDRIGetDrawableInfo
279 };
280
281 static const __DRIextension *loader_extensions[] = {
282 &systemTimeExtension.base,
283 &getDrawableInfoExtension.base,
284 &damageExtension.base,
285 NULL
286 };
287
288 /**
289 * Perform the required libGL-side initialization and call the client-side
290 * driver's \c __driCreateNewScreen function.
291 *
292 * \param dpy Display pointer.
293 * \param scrn Screen number on the display.
294 * \param psc DRI screen information.
295 * \param driDpy DRI display information.
296 * \param createNewScreen Pointer to the client-side driver's
297 * \c __driCreateNewScreen function.
298 * \returns A pointer to the \c __DRIscreen structure returned by
299 * the client-side driver on success, or \c NULL on failure.
300 */
301 static void *
CallCreateNewScreen(Display * dpy,int scrn,struct dri_screen * psc,struct dri_display * driDpy)302 CallCreateNewScreen(Display *dpy, int scrn, struct dri_screen *psc,
303 struct dri_display * driDpy)
304 {
305 void *psp = NULL;
306 drm_handle_t hSAREA;
307 drmAddress pSAREA = MAP_FAILED;
308 char *BusID;
309 __DRIversion ddx_version;
310 __DRIversion dri_version;
311 __DRIversion drm_version;
312 __DRIframebuffer framebuffer;
313 int fd = -1;
314 int status;
315
316 drm_magic_t magic;
317 drmVersionPtr version;
318 int newlyopened;
319 char *driverName;
320 drm_handle_t hFB;
321 int junk;
322 const __DRIconfig **driver_configs;
323 struct glx_config *visual, *configs = NULL, *visuals = NULL;
324
325 /* DRI protocol version. */
326 dri_version.major = driDpy->driMajor;
327 dri_version.minor = driDpy->driMinor;
328 dri_version.patch = driDpy->driPatch;
329
330 framebuffer.base = MAP_FAILED;
331 framebuffer.dev_priv = NULL;
332 framebuffer.size = 0;
333
334 if (!XF86DRIOpenConnection(dpy, scrn, &hSAREA, &BusID)) {
335 ErrorMessageF("XF86DRIOpenConnection failed\n");
336 goto handle_error;
337 }
338
339 fd = drmOpenOnce(NULL, BusID, &newlyopened);
340
341 free(BusID); /* No longer needed */
342
343 if (fd < 0) {
344 ErrorMessageF("drmOpenOnce failed (%s)\n", strerror(-fd));
345 goto handle_error;
346 }
347
348 if (drmGetMagic(fd, &magic)) {
349 ErrorMessageF("drmGetMagic failed\n");
350 goto handle_error;
351 }
352
353 version = drmGetVersion(fd);
354 if (version) {
355 drm_version.major = version->version_major;
356 drm_version.minor = version->version_minor;
357 drm_version.patch = version->version_patchlevel;
358 drmFreeVersion(version);
359 }
360 else {
361 drm_version.major = -1;
362 drm_version.minor = -1;
363 drm_version.patch = -1;
364 }
365
366 if (newlyopened && !XF86DRIAuthConnection(dpy, scrn, magic)) {
367 ErrorMessageF("XF86DRIAuthConnection failed\n");
368 goto handle_error;
369 }
370
371 /* Get device name (like "radeon") and the ddx version numbers.
372 * We'll check the version in each DRI driver's "createNewScreen"
373 * function. */
374 if (!XF86DRIGetClientDriverName(dpy, scrn,
375 &ddx_version.major,
376 &ddx_version.minor,
377 &ddx_version.patch, &driverName)) {
378 ErrorMessageF("XF86DRIGetClientDriverName failed\n");
379 goto handle_error;
380 }
381
382 free(driverName); /* No longer needed. */
383
384 /*
385 * Get device-specific info. pDevPriv will point to a struct
386 * (such as DRIRADEONRec in xfree86/driver/ati/radeon_dri.h) that
387 * has information about the screen size, depth, pitch, ancilliary
388 * buffers, DRM mmap handles, etc.
389 */
390 if (!XF86DRIGetDeviceInfo(dpy, scrn, &hFB, &junk,
391 &framebuffer.size, &framebuffer.stride,
392 &framebuffer.dev_priv_size,
393 &framebuffer.dev_priv)) {
394 ErrorMessageF("XF86DRIGetDeviceInfo failed\n");
395 goto handle_error;
396 }
397
398 framebuffer.width = DisplayWidth(dpy, scrn);
399 framebuffer.height = DisplayHeight(dpy, scrn);
400
401 /* Map the framebuffer region. */
402 status = drmMap(fd, hFB, framebuffer.size,
403 (drmAddressPtr) & framebuffer.base);
404 if (status != 0) {
405 ErrorMessageF("drmMap of framebuffer failed (%s)\n", strerror(-status));
406 goto handle_error;
407 }
408
409 /* Map the SAREA region. Further mmap regions may be setup in
410 * each DRI driver's "createNewScreen" function.
411 */
412 status = drmMap(fd, hSAREA, SAREA_MAX, &pSAREA);
413 if (status != 0) {
414 ErrorMessageF("drmMap of SAREA failed (%s)\n", strerror(-status));
415 goto handle_error;
416 }
417
418 psp = (*psc->legacy->createNewScreen) (scrn,
419 &ddx_version,
420 &dri_version,
421 &drm_version,
422 &framebuffer,
423 pSAREA,
424 fd,
425 loader_extensions,
426 &driver_configs, psc);
427
428 if (psp == NULL) {
429 ErrorMessageF("Calling driver entry point failed\n");
430 goto handle_error;
431 }
432
433 configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs);
434 visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs);
435
436 if (!configs || !visuals) {
437 ErrorMessageF("No matching fbConfigs or visuals found\n");
438 goto handle_error;
439 }
440
441 glx_config_destroy_list(psc->base.configs);
442 psc->base.configs = configs;
443 glx_config_destroy_list(psc->base.visuals);
444 psc->base.visuals = visuals;
445
446 psc->driver_configs = driver_configs;
447
448 /* Visuals with depth != screen depth are subject to automatic compositing
449 * in the X server, so DRI1 can't render to them properly. Mark them as
450 * non-conformant to prevent apps from picking them up accidentally.
451 */
452 for (visual = psc->base.visuals; visual; visual = visual->next) {
453 XVisualInfo templ;
454 XVisualInfo *visuals;
455 int num_visuals;
456 long mask;
457
458 templ.visualid = visual->visualID;
459 mask = VisualIDMask;
460 visuals = XGetVisualInfo(dpy, mask, &templ, &num_visuals);
461
462 if (visuals) {
463 if (num_visuals > 0 && visuals->depth != DefaultDepth(dpy, scrn))
464 visual->visualRating = GLX_NON_CONFORMANT_CONFIG;
465
466 free(visuals);
467 }
468 }
469
470 return psp;
471
472 handle_error:
473 if (configs)
474 glx_config_destroy_list(configs);
475 if (visuals)
476 glx_config_destroy_list(visuals);
477
478 if (pSAREA != MAP_FAILED)
479 drmUnmap(pSAREA, SAREA_MAX);
480
481 if (framebuffer.base != MAP_FAILED)
482 drmUnmap((drmAddress) framebuffer.base, framebuffer.size);
483
484 free(framebuffer.dev_priv);
485
486 if (fd >= 0)
487 drmCloseOnce(fd);
488
489 XF86DRICloseConnection(dpy, scrn);
490
491 ErrorMessageF("reverting to software direct rendering\n");
492
493 return NULL;
494 }
495
496 static void
dri_destroy_context(struct glx_context * context)497 dri_destroy_context(struct glx_context * context)
498 {
499 struct dri_context *pcp = (struct dri_context *) context;
500 struct dri_screen *psc = (struct dri_screen *) context->psc;
501
502 driReleaseDrawables(&pcp->base);
503
504 free((char *) context->extensions);
505
506 (*psc->core->destroyContext) (pcp->driContext);
507
508 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
509 free(pcp);
510 }
511
512 static int
dri_bind_context(struct glx_context * context,struct glx_context * old,GLXDrawable draw,GLXDrawable read)513 dri_bind_context(struct glx_context *context, struct glx_context *old,
514 GLXDrawable draw, GLXDrawable read)
515 {
516 struct dri_context *pcp = (struct dri_context *) context;
517 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
518 struct dri_drawable *pdraw, *pread;
519
520 pdraw = (struct dri_drawable *) driFetchDrawable(context, draw);
521 pread = (struct dri_drawable *) driFetchDrawable(context, read);
522
523 driReleaseDrawables(&pcp->base);
524
525 if (pdraw == NULL || pread == NULL)
526 return GLXBadDrawable;
527
528 if ((*psc->core->bindContext) (pcp->driContext,
529 pdraw->driDrawable, pread->driDrawable))
530 return Success;
531
532 return GLXBadContext;
533 }
534
535 static void
dri_unbind_context(struct glx_context * context,struct glx_context * new)536 dri_unbind_context(struct glx_context *context, struct glx_context *new)
537 {
538 struct dri_context *pcp = (struct dri_context *) context;
539 struct dri_screen *psc = (struct dri_screen *) pcp->base.psc;
540
541 (*psc->core->unbindContext) (pcp->driContext);
542 }
543
544 static const struct glx_context_vtable dri_context_vtable = {
545 .destroy = dri_destroy_context,
546 .bind = dri_bind_context,
547 .unbind = dri_unbind_context,
548 .wait_gl = NULL,
549 .wait_x = NULL,
550 .use_x_font = DRI_glXUseXFont,
551 .bind_tex_image = NULL,
552 .release_tex_image = NULL,
553 .get_proc_address = NULL,
554 };
555
556 static struct glx_context *
dri_create_context(struct glx_screen * base,struct glx_config * config_base,struct glx_context * shareList,int renderType)557 dri_create_context(struct glx_screen *base,
558 struct glx_config *config_base,
559 struct glx_context *shareList, int renderType)
560 {
561 struct dri_context *pcp, *pcp_shared;
562 struct dri_screen *psc = (struct dri_screen *) base;
563 drm_context_t hwContext;
564 __DRIcontext *shared = NULL;
565 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
566
567 if (!psc->base.driScreen)
568 return NULL;
569
570 /* Check the renderType value */
571 if (!validate_renderType_against_config(config_base, renderType))
572 return NULL;
573
574 if (shareList) {
575 /* If the shareList context is not a DRI context, we cannot possibly
576 * create a DRI context that shares it.
577 */
578 if (shareList->vtable->destroy != dri_destroy_context) {
579 return NULL;
580 }
581
582 pcp_shared = (struct dri_context *) shareList;
583 shared = pcp_shared->driContext;
584 }
585
586 pcp = calloc(1, sizeof *pcp);
587 if (pcp == NULL)
588 return NULL;
589
590 if (!glx_context_init(&pcp->base, &psc->base, &config->base)) {
591 free(pcp);
592 return NULL;
593 }
594
595 pcp->base.renderType = renderType;
596
597 if (!XF86DRICreateContextWithConfig(psc->base.dpy, psc->base.scr,
598 config->base.visualID,
599 &pcp->hwContextID, &hwContext)) {
600 free(pcp);
601 return NULL;
602 }
603
604 pcp->driContext =
605 (*psc->legacy->createNewContext) (psc->driScreen,
606 config->driConfig,
607 renderType, shared, hwContext, pcp);
608 if (pcp->driContext == NULL) {
609 XF86DRIDestroyContext(psc->base.dpy, psc->base.scr, pcp->hwContextID);
610 free(pcp);
611 return NULL;
612 }
613
614 pcp->base.vtable = &dri_context_vtable;
615
616 return &pcp->base;
617 }
618
619 static void
driDestroyDrawable(__GLXDRIdrawable * pdraw)620 driDestroyDrawable(__GLXDRIdrawable * pdraw)
621 {
622 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
623 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
624
625 (*psc->core->destroyDrawable) (pdp->driDrawable);
626 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, pdraw->drawable);
627 free(pdraw);
628 }
629
630 static __GLXDRIdrawable *
driCreateDrawable(struct glx_screen * base,XID xDrawable,GLXDrawable drawable,struct glx_config * config_base)631 driCreateDrawable(struct glx_screen *base,
632 XID xDrawable,
633 GLXDrawable drawable, struct glx_config *config_base)
634 {
635 drm_drawable_t hwDrawable;
636 void *empty_attribute_list = NULL;
637 __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base;
638 struct dri_screen *psc = (struct dri_screen *) base;
639 struct dri_drawable *pdp;
640
641 /* Old dri can't handle GLX 1.3+ drawable constructors. */
642 if (xDrawable != drawable)
643 return NULL;
644
645 pdp = calloc(1, sizeof *pdp);
646 if (!pdp)
647 return NULL;
648
649 pdp->base.drawable = drawable;
650 pdp->base.psc = &psc->base;
651
652 if (!XF86DRICreateDrawable(psc->base.dpy, psc->base.scr,
653 drawable, &hwDrawable)) {
654 free(pdp);
655 return NULL;
656 }
657
658 /* Create a new drawable */
659 pdp->driDrawable =
660 (*psc->legacy->createNewDrawable) (psc->driScreen,
661 config->driConfig,
662 hwDrawable,
663 GLX_WINDOW_BIT,
664 empty_attribute_list, pdp);
665
666 if (!pdp->driDrawable) {
667 XF86DRIDestroyDrawable(psc->base.dpy, psc->base.scr, drawable);
668 free(pdp);
669 return NULL;
670 }
671
672 pdp->base.destroyDrawable = driDestroyDrawable;
673
674 return &pdp->base;
675 }
676
677 static int64_t
driSwapBuffers(__GLXDRIdrawable * pdraw,int64_t unused1,int64_t unused2,int64_t unused3,Bool flush)678 driSwapBuffers(__GLXDRIdrawable * pdraw, int64_t unused1, int64_t unused2,
679 int64_t unused3, Bool flush)
680 {
681 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
682 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
683
684 if (flush) {
685 glFlush();
686 }
687
688 (*psc->core->swapBuffers) (pdp->driDrawable);
689 return 0;
690 }
691
692 static void
driCopySubBuffer(__GLXDRIdrawable * pdraw,int x,int y,int width,int height,Bool flush)693 driCopySubBuffer(__GLXDRIdrawable * pdraw,
694 int x, int y, int width, int height, Bool flush)
695 {
696 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
697 struct dri_screen *psc = (struct dri_screen *) pdp->base.psc;
698
699 if (flush) {
700 glFlush();
701 }
702
703 (*psc->driCopySubBuffer->copySubBuffer) (pdp->driDrawable,
704 x, y, width, height);
705 }
706
707 static void
driDestroyScreen(struct glx_screen * base)708 driDestroyScreen(struct glx_screen *base)
709 {
710 struct dri_screen *psc = (struct dri_screen *) base;
711
712 /* Free the direct rendering per screen data */
713 if (psc->driScreen)
714 (*psc->core->destroyScreen) (psc->driScreen);
715 driDestroyConfigs(psc->driver_configs);
716 psc->driScreen = NULL;
717 if (psc->driver)
718 dlclose(psc->driver);
719 }
720
721 static int
driSetSwapInterval(__GLXDRIdrawable * pdraw,int interval)722 driSetSwapInterval(__GLXDRIdrawable *pdraw, int interval)
723 {
724 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
725
726 if (pdraw != NULL) {
727 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
728
729 if (psc->swapControl != NULL) {
730 psc->swapControl->setSwapInterval(pdp->driDrawable, interval);
731 return 0;
732 }
733 }
734 return GLX_BAD_CONTEXT;
735 }
736
737 static int
driGetSwapInterval(__GLXDRIdrawable * pdraw)738 driGetSwapInterval(__GLXDRIdrawable *pdraw)
739 {
740 struct dri_drawable *pdp = (struct dri_drawable *) pdraw;
741
742 if (pdraw != NULL) {
743 struct dri_screen *psc = (struct dri_screen *) pdraw->psc;
744
745 if (psc->swapControl != NULL)
746 return psc->swapControl->getSwapInterval(pdp->driDrawable);
747 }
748 return 0;
749 }
750
751 /* Bind DRI1 specific extensions */
752 static void
driBindExtensions(struct dri_screen * psc,const __DRIextension ** extensions)753 driBindExtensions(struct dri_screen *psc, const __DRIextension **extensions)
754 {
755 int i;
756
757 for (i = 0; extensions[i]; i++) {
758 /* No DRI2 support for swap_control at the moment, since SwapBuffers
759 * is done by the X server */
760 if (strcmp(extensions[i]->name, __DRI_SWAP_CONTROL) == 0) {
761 psc->swapControl = (__DRIswapControlExtension *) extensions[i];
762 __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control");
763 __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control");
764 }
765
766 if (strcmp(extensions[i]->name, __DRI_MEDIA_STREAM_COUNTER) == 0) {
767 psc->msc = (__DRImediaStreamCounterExtension *) extensions[i];
768 __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync");
769 }
770
771 if (strcmp(extensions[i]->name, __DRI_COPY_SUB_BUFFER) == 0) {
772 psc->driCopySubBuffer = (__DRIcopySubBufferExtension *) extensions[i];
773 __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer");
774 }
775
776 if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
777 __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read");
778 }
779 /* Ignore unknown extensions */
780 }
781 }
782
783 static const struct glx_screen_vtable dri_screen_vtable = {
784 .create_context = dri_create_context,
785 .create_context_attribs = NULL,
786 .query_renderer_integer = NULL,
787 .query_renderer_string = NULL,
788 .get_driver_name = dri_get_driver_name,
789 };
790
791 static struct glx_screen *
driCreateScreen(int screen,struct glx_display * priv)792 driCreateScreen(int screen, struct glx_display *priv)
793 {
794 struct dri_display *pdp;
795 __GLXDRIscreen *psp;
796 const __DRIextension **extensions;
797 struct dri_screen *psc;
798 char *driverName;
799 int i;
800
801 psc = calloc(1, sizeof *psc);
802 if (psc == NULL)
803 return NULL;
804
805 if (!glx_screen_init(&psc->base, screen, priv)) {
806 free(psc);
807 return NULL;
808 }
809
810 if (!(driverName = dri_get_driver_name(&psc->base))) {
811 goto cleanup;
812 }
813
814 extensions = driOpenDriver(driverName, &psc->driver);
815 if (extensions == NULL) {
816 ErrorMessageF("driver exports no extensions (%s)\n", dlerror());
817 goto cleanup;
818 }
819
820 for (i = 0; extensions[i]; i++) {
821 if (strcmp(extensions[i]->name, __DRI_CORE) == 0)
822 psc->core = (__DRIcoreExtension *) extensions[i];
823 if (strcmp(extensions[i]->name, __DRI_LEGACY) == 0)
824 psc->legacy = (__DRIlegacyExtension *) extensions[i];
825 }
826
827 if (psc->core == NULL || psc->legacy == NULL)
828 goto cleanup;
829
830 pdp = (struct dri_display *) priv->driDisplay;
831 psc->driScreen =
832 CallCreateNewScreen(psc->base.dpy, screen, psc, pdp);
833 if (psc->driScreen == NULL)
834 goto cleanup;
835
836 extensions = psc->core->getExtensions(psc->driScreen);
837 driBindExtensions(psc, extensions);
838
839 psc->base.vtable = &dri_screen_vtable;
840 psp = &psc->vtable;
841 psc->base.driScreen = psp;
842 if (psc->driCopySubBuffer)
843 psp->copySubBuffer = driCopySubBuffer;
844
845 psp->destroyScreen = driDestroyScreen;
846 psp->createDrawable = driCreateDrawable;
847 psp->swapBuffers = driSwapBuffers;
848
849 psp->setSwapInterval = driSetSwapInterval;
850 psp->getSwapInterval = driGetSwapInterval;
851
852 free(driverName);
853
854 return &psc->base;
855
856 cleanup:
857 CriticalErrorMessageF("failed to load driver: %s\n", driverName);
858
859 free(driverName);
860
861 if (psc->driver)
862 dlclose(psc->driver);
863 glx_screen_cleanup(&psc->base);
864 free(psc);
865
866 return NULL;
867 }
868
869 /* Called from __glXFreeDisplayPrivate.
870 */
871 static void
driDestroyDisplay(__GLXDRIdisplay * dpy)872 driDestroyDisplay(__GLXDRIdisplay * dpy)
873 {
874 free(dpy);
875 }
876
877 /*
878 * Allocate, initialize and return a __DRIdisplayPrivate object.
879 * This is called from __glXInitialize() when we are given a new
880 * display pointer.
881 */
882 _X_HIDDEN __GLXDRIdisplay *
driCreateDisplay(Display * dpy)883 driCreateDisplay(Display * dpy)
884 {
885 struct dri_display *pdpyp;
886 int eventBase, errorBase;
887 int major, minor, patch;
888
889 if (!XF86DRIQueryExtension(dpy, &eventBase, &errorBase)) {
890 return NULL;
891 }
892
893 if (!XF86DRIQueryVersion(dpy, &major, &minor, &patch)) {
894 return NULL;
895 }
896
897 pdpyp = malloc(sizeof *pdpyp);
898 if (!pdpyp) {
899 return NULL;
900 }
901
902 pdpyp->driMajor = major;
903 pdpyp->driMinor = minor;
904 pdpyp->driPatch = patch;
905
906 pdpyp->base.destroyDisplay = driDestroyDisplay;
907 pdpyp->base.createScreen = driCreateScreen;
908
909 return &pdpyp->base;
910 }
911
912 #endif /* GLX_DIRECT_RENDERING */
913