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