Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5564 | serge | 1 | /* |
2 | * Copyright © 2008 Red Hat, Inc. |
||
3 | * |
||
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
||
5 | * copy of this software and associated documentation files (the "Soft- |
||
6 | * ware"), to deal in the Software without restriction, including without |
||
7 | * limitation the rights to use, copy, modify, merge, publish, distribute, |
||
8 | * and/or sell copies of the Software, and to permit persons to whom the |
||
9 | * Software is furnished to do so, provided that the above copyright |
||
10 | * notice(s) and this permission notice appear in all copies of the Soft- |
||
11 | * ware and that both the above copyright notice(s) and this permission |
||
12 | * notice appear in supporting documentation. |
||
13 | * |
||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
15 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
||
16 | * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY |
||
17 | * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN |
||
18 | * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE- |
||
19 | * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
||
20 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
||
21 | * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR- |
||
22 | * MANCE OF THIS SOFTWARE. |
||
23 | * |
||
24 | * Except as contained in this notice, the name of a copyright holder shall |
||
25 | * not be used in advertising or otherwise to promote the sale, use or |
||
26 | * other dealings in this Software without prior written authorization of |
||
27 | * the copyright holder. |
||
28 | * |
||
29 | * Authors: |
||
30 | * Kristian Høgsberg (krh@redhat.com) |
||
31 | */ |
||
32 | |||
33 | #if defined(GLX_DIRECT_RENDERING) && !defined(GLX_USE_APPLEGL) |
||
34 | |||
35 | #include |
||
36 | #include |
||
37 | #include |
||
38 | #include |
||
39 | #include |
||
40 | #include "glxclient.h" |
||
41 | #include |
||
42 | #include |
||
43 | #include |
||
44 | #include |
||
45 | #include |
||
46 | #include |
||
47 | #include |
||
48 | #include "dri2.h" |
||
49 | #include "dri_common.h" |
||
50 | #include "dri2_priv.h" |
||
51 | #include "loader.h" |
||
52 | |||
53 | /* From xmlpool/options.h, user exposed so should be stable */ |
||
54 | #define DRI_CONF_VBLANK_NEVER 0 |
||
55 | #define DRI_CONF_VBLANK_DEF_INTERVAL_0 1 |
||
56 | #define DRI_CONF_VBLANK_DEF_INTERVAL_1 2 |
||
57 | #define DRI_CONF_VBLANK_ALWAYS_SYNC 3 |
||
58 | |||
59 | #undef DRI2_MINOR |
||
60 | #define DRI2_MINOR 1 |
||
61 | |||
62 | struct dri2_display |
||
63 | { |
||
64 | __GLXDRIdisplay base; |
||
65 | |||
66 | /* |
||
67 | ** XFree86-DRI version information |
||
68 | */ |
||
69 | int driMajor; |
||
70 | int driMinor; |
||
71 | int driPatch; |
||
72 | int swapAvailable; |
||
73 | int invalidateAvailable; |
||
74 | |||
75 | __glxHashTable *dri2Hash; |
||
76 | |||
77 | const __DRIextension *loader_extensions[4]; |
||
78 | }; |
||
79 | |||
80 | struct dri2_context |
||
81 | { |
||
82 | struct glx_context base; |
||
83 | __DRIcontext *driContext; |
||
84 | }; |
||
85 | |||
86 | struct dri2_drawable |
||
87 | { |
||
88 | __GLXDRIdrawable base; |
||
89 | __DRIdrawable *driDrawable; |
||
90 | __DRIbuffer buffers[5]; |
||
91 | int bufferCount; |
||
92 | int width, height; |
||
93 | int have_back; |
||
94 | int have_fake_front; |
||
95 | int swap_interval; |
||
96 | |||
97 | uint64_t previous_time; |
||
98 | unsigned frames; |
||
99 | }; |
||
100 | |||
101 | static const struct glx_context_vtable dri2_context_vtable; |
||
102 | |||
103 | /* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and |
||
104 | * low halves separately. This helps you split them. |
||
105 | */ |
||
106 | static void |
||
107 | split_counter(uint64_t counter, uint32_t *hi, uint32_t *lo) |
||
108 | { |
||
109 | *hi = (counter >> 32); |
||
110 | *lo = counter & 0xffffffff; |
||
111 | } |
||
112 | |||
113 | static uint64_t |
||
114 | merge_counter(uint32_t hi, uint32_t lo) |
||
115 | { |
||
116 | return ((uint64_t)hi << 32) | lo; |
||
117 | } |
||
118 | |||
119 | static void |
||
120 | dri2_destroy_context(struct glx_context *context) |
||
121 | { |
||
122 | struct dri2_context *pcp = (struct dri2_context *) context; |
||
123 | struct dri2_screen *psc = (struct dri2_screen *) context->psc; |
||
124 | |||
125 | driReleaseDrawables(&pcp->base); |
||
126 | |||
127 | free((char *) context->extensions); |
||
128 | |||
129 | (*psc->core->destroyContext) (pcp->driContext); |
||
130 | |||
131 | free(pcp); |
||
132 | } |
||
133 | |||
134 | static Bool |
||
135 | dri2_bind_context(struct glx_context *context, struct glx_context *old, |
||
136 | GLXDrawable draw, GLXDrawable read) |
||
137 | { |
||
138 | struct dri2_context *pcp = (struct dri2_context *) context; |
||
139 | struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; |
||
140 | struct dri2_drawable *pdraw, *pread; |
||
141 | __DRIdrawable *dri_draw = NULL, *dri_read = NULL; |
||
142 | struct glx_display *dpyPriv = psc->base.display; |
||
143 | struct dri2_display *pdp; |
||
144 | |||
145 | pdraw = (struct dri2_drawable *) driFetchDrawable(context, draw); |
||
146 | pread = (struct dri2_drawable *) driFetchDrawable(context, read); |
||
147 | |||
148 | driReleaseDrawables(&pcp->base); |
||
149 | |||
150 | if (pdraw) |
||
151 | dri_draw = pdraw->driDrawable; |
||
152 | else if (draw != None) |
||
153 | return GLXBadDrawable; |
||
154 | |||
155 | if (pread) |
||
156 | dri_read = pread->driDrawable; |
||
157 | else if (read != None) |
||
158 | return GLXBadDrawable; |
||
159 | |||
160 | if (!(*psc->core->bindContext) (pcp->driContext, dri_draw, dri_read)) |
||
161 | return GLXBadContext; |
||
162 | |||
163 | /* If the server doesn't send invalidate events, we may miss a |
||
164 | * resize before the rendering starts. Invalidate the buffers now |
||
165 | * so the driver will recheck before rendering starts. */ |
||
166 | pdp = (struct dri2_display *) dpyPriv->dri2Display; |
||
167 | if (!pdp->invalidateAvailable && pdraw) { |
||
168 | dri2InvalidateBuffers(psc->base.dpy, pdraw->base.xDrawable); |
||
169 | if (pread != pdraw && pread) |
||
170 | dri2InvalidateBuffers(psc->base.dpy, pread->base.xDrawable); |
||
171 | } |
||
172 | |||
173 | return Success; |
||
174 | } |
||
175 | |||
176 | static void |
||
177 | dri2_unbind_context(struct glx_context *context, struct glx_context *new) |
||
178 | { |
||
179 | struct dri2_context *pcp = (struct dri2_context *) context; |
||
180 | struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; |
||
181 | |||
182 | (*psc->core->unbindContext) (pcp->driContext); |
||
183 | } |
||
184 | |||
185 | static struct glx_context * |
||
186 | dri2_create_context(struct glx_screen *base, |
||
187 | struct glx_config *config_base, |
||
188 | struct glx_context *shareList, int renderType) |
||
189 | { |
||
190 | struct dri2_context *pcp, *pcp_shared; |
||
191 | struct dri2_screen *psc = (struct dri2_screen *) base; |
||
192 | __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; |
||
193 | __DRIcontext *shared = NULL; |
||
194 | |||
195 | /* Check the renderType value */ |
||
196 | if (!validate_renderType_against_config(config_base, renderType)) |
||
197 | return NULL; |
||
198 | |||
199 | if (shareList) { |
||
200 | /* If the shareList context is not a DRI2 context, we cannot possibly |
||
201 | * create a DRI2 context that shares it. |
||
202 | */ |
||
203 | if (shareList->vtable->destroy != dri2_destroy_context) { |
||
204 | return NULL; |
||
205 | } |
||
206 | |||
207 | pcp_shared = (struct dri2_context *) shareList; |
||
208 | shared = pcp_shared->driContext; |
||
209 | } |
||
210 | |||
211 | pcp = calloc(1, sizeof *pcp); |
||
212 | if (pcp == NULL) |
||
213 | return NULL; |
||
214 | |||
215 | if (!glx_context_init(&pcp->base, &psc->base, &config->base)) { |
||
216 | free(pcp); |
||
217 | return NULL; |
||
218 | } |
||
219 | |||
220 | pcp->base.renderType = renderType; |
||
221 | |||
222 | pcp->driContext = |
||
223 | (*psc->dri2->createNewContext) (psc->driScreen, |
||
224 | config->driConfig, shared, pcp); |
||
225 | |||
226 | if (pcp->driContext == NULL) { |
||
227 | free(pcp); |
||
228 | return NULL; |
||
229 | } |
||
230 | |||
231 | pcp->base.vtable = &dri2_context_vtable; |
||
232 | |||
233 | return &pcp->base; |
||
234 | } |
||
235 | |||
236 | static struct glx_context * |
||
237 | dri2_create_context_attribs(struct glx_screen *base, |
||
238 | struct glx_config *config_base, |
||
239 | struct glx_context *shareList, |
||
240 | unsigned num_attribs, |
||
241 | const uint32_t *attribs, |
||
242 | unsigned *error) |
||
243 | { |
||
244 | struct dri2_context *pcp = NULL; |
||
245 | struct dri2_context *pcp_shared = NULL; |
||
246 | struct dri2_screen *psc = (struct dri2_screen *) base; |
||
247 | __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; |
||
248 | __DRIcontext *shared = NULL; |
||
249 | |||
250 | uint32_t minor_ver; |
||
251 | uint32_t major_ver; |
||
252 | uint32_t renderType; |
||
253 | uint32_t flags; |
||
254 | unsigned api; |
||
255 | int reset; |
||
256 | uint32_t ctx_attribs[2 * 5]; |
||
257 | unsigned num_ctx_attribs = 0; |
||
258 | |||
259 | if (psc->dri2->base.version < 3) { |
||
260 | *error = __DRI_CTX_ERROR_NO_MEMORY; |
||
261 | goto error_exit; |
||
262 | } |
||
263 | |||
264 | /* Remap the GLX tokens to DRI2 tokens. |
||
265 | */ |
||
266 | if (!dri2_convert_glx_attribs(num_attribs, attribs, |
||
267 | &major_ver, &minor_ver, &renderType, &flags, |
||
268 | &api, &reset, error)) |
||
269 | goto error_exit; |
||
270 | |||
271 | /* Check the renderType value */ |
||
272 | if (!validate_renderType_against_config(config_base, renderType)) |
||
273 | goto error_exit; |
||
274 | |||
275 | if (shareList) { |
||
276 | pcp_shared = (struct dri2_context *) shareList; |
||
277 | shared = pcp_shared->driContext; |
||
278 | } |
||
279 | |||
280 | pcp = calloc(1, sizeof *pcp); |
||
281 | if (pcp == NULL) { |
||
282 | *error = __DRI_CTX_ERROR_NO_MEMORY; |
||
283 | goto error_exit; |
||
284 | } |
||
285 | |||
286 | if (!glx_context_init(&pcp->base, &psc->base, &config->base)) |
||
287 | goto error_exit; |
||
288 | |||
289 | ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MAJOR_VERSION; |
||
290 | ctx_attribs[num_ctx_attribs++] = major_ver; |
||
291 | ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_MINOR_VERSION; |
||
292 | ctx_attribs[num_ctx_attribs++] = minor_ver; |
||
293 | |||
294 | /* Only send a value when the non-default value is requested. By doing |
||
295 | * this we don't have to check the driver's DRI2 version before sending the |
||
296 | * default value. |
||
297 | */ |
||
298 | if (reset != __DRI_CTX_RESET_NO_NOTIFICATION) { |
||
299 | ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_RESET_STRATEGY; |
||
300 | ctx_attribs[num_ctx_attribs++] = reset; |
||
301 | } |
||
302 | |||
303 | if (flags != 0) { |
||
304 | ctx_attribs[num_ctx_attribs++] = __DRI_CTX_ATTRIB_FLAGS; |
||
305 | |||
306 | /* The current __DRI_CTX_FLAG_* values are identical to the |
||
307 | * GLX_CONTEXT_*_BIT values. |
||
308 | */ |
||
309 | ctx_attribs[num_ctx_attribs++] = flags; |
||
310 | } |
||
311 | |||
312 | /* The renderType is retrieved from attribs, or set to default |
||
313 | * of GLX_RGBA_TYPE. |
||
314 | */ |
||
315 | pcp->base.renderType = renderType; |
||
316 | |||
317 | pcp->driContext = |
||
318 | (*psc->dri2->createContextAttribs) (psc->driScreen, |
||
319 | api, |
||
320 | config->driConfig, |
||
321 | shared, |
||
322 | num_ctx_attribs / 2, |
||
323 | ctx_attribs, |
||
324 | error, |
||
325 | pcp); |
||
326 | |||
327 | if (pcp->driContext == NULL) |
||
328 | goto error_exit; |
||
329 | |||
330 | pcp->base.vtable = &dri2_context_vtable; |
||
331 | |||
332 | return &pcp->base; |
||
333 | |||
334 | error_exit: |
||
335 | free(pcp); |
||
336 | |||
337 | return NULL; |
||
338 | } |
||
339 | |||
340 | static void |
||
341 | dri2DestroyDrawable(__GLXDRIdrawable *base) |
||
342 | { |
||
343 | struct dri2_screen *psc = (struct dri2_screen *) base->psc; |
||
344 | struct dri2_drawable *pdraw = (struct dri2_drawable *) base; |
||
345 | struct glx_display *dpyPriv = psc->base.display; |
||
346 | struct dri2_display *pdp = (struct dri2_display *)dpyPriv->dri2Display; |
||
347 | |||
348 | __glxHashDelete(pdp->dri2Hash, pdraw->base.xDrawable); |
||
349 | (*psc->core->destroyDrawable) (pdraw->driDrawable); |
||
350 | |||
351 | /* If it's a GLX 1.3 drawables, we can destroy the DRI2 drawable |
||
352 | * now, as the application explicitly asked to destroy the GLX |
||
353 | * drawable. Otherwise, for legacy drawables, we let the DRI2 |
||
354 | * drawable linger on the server, since there's no good way of |
||
355 | * knowing when the application is done with it. The server will |
||
356 | * destroy the DRI2 drawable when it destroys the X drawable or the |
||
357 | * client exits anyway. */ |
||
358 | if (pdraw->base.xDrawable != pdraw->base.drawable) |
||
359 | DRI2DestroyDrawable(psc->base.dpy, pdraw->base.xDrawable); |
||
360 | |||
361 | free(pdraw); |
||
362 | } |
||
363 | |||
364 | static __GLXDRIdrawable * |
||
365 | dri2CreateDrawable(struct glx_screen *base, XID xDrawable, |
||
366 | GLXDrawable drawable, struct glx_config *config_base) |
||
367 | { |
||
368 | struct dri2_drawable *pdraw; |
||
369 | struct dri2_screen *psc = (struct dri2_screen *) base; |
||
370 | __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; |
||
371 | struct glx_display *dpyPriv; |
||
372 | struct dri2_display *pdp; |
||
373 | GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; |
||
374 | |||
375 | dpyPriv = __glXInitialize(psc->base.dpy); |
||
376 | if (dpyPriv == NULL) |
||
377 | return NULL; |
||
378 | |||
379 | pdraw = calloc(1, sizeof(*pdraw)); |
||
380 | if (!pdraw) |
||
381 | return NULL; |
||
382 | |||
383 | pdraw->base.destroyDrawable = dri2DestroyDrawable; |
||
384 | pdraw->base.xDrawable = xDrawable; |
||
385 | pdraw->base.drawable = drawable; |
||
386 | pdraw->base.psc = &psc->base; |
||
387 | pdraw->bufferCount = 0; |
||
388 | pdraw->swap_interval = 1; /* default may be overridden below */ |
||
389 | pdraw->have_back = 0; |
||
390 | |||
391 | if (psc->config) |
||
392 | psc->config->configQueryi(psc->driScreen, |
||
393 | "vblank_mode", &vblank_mode); |
||
394 | |||
395 | switch (vblank_mode) { |
||
396 | case DRI_CONF_VBLANK_NEVER: |
||
397 | case DRI_CONF_VBLANK_DEF_INTERVAL_0: |
||
398 | pdraw->swap_interval = 0; |
||
399 | break; |
||
400 | case DRI_CONF_VBLANK_DEF_INTERVAL_1: |
||
401 | case DRI_CONF_VBLANK_ALWAYS_SYNC: |
||
402 | default: |
||
403 | pdraw->swap_interval = 1; |
||
404 | break; |
||
405 | } |
||
406 | |||
407 | DRI2CreateDrawable(psc->base.dpy, xDrawable); |
||
408 | pdp = (struct dri2_display *)dpyPriv->dri2Display;; |
||
409 | /* Create a new drawable */ |
||
410 | pdraw->driDrawable = |
||
411 | (*psc->dri2->createNewDrawable) (psc->driScreen, |
||
412 | config->driConfig, pdraw); |
||
413 | |||
414 | if (!pdraw->driDrawable) { |
||
415 | DRI2DestroyDrawable(psc->base.dpy, xDrawable); |
||
416 | free(pdraw); |
||
417 | return NULL; |
||
418 | } |
||
419 | |||
420 | if (__glxHashInsert(pdp->dri2Hash, xDrawable, pdraw)) { |
||
421 | (*psc->core->destroyDrawable) (pdraw->driDrawable); |
||
422 | DRI2DestroyDrawable(psc->base.dpy, xDrawable); |
||
423 | free(pdraw); |
||
424 | return None; |
||
425 | } |
||
426 | |||
427 | /* |
||
428 | * Make sure server has the same swap interval we do for the new |
||
429 | * drawable. |
||
430 | */ |
||
431 | if (psc->vtable.setSwapInterval) |
||
432 | psc->vtable.setSwapInterval(&pdraw->base, pdraw->swap_interval); |
||
433 | |||
434 | return &pdraw->base; |
||
435 | } |
||
436 | |||
437 | static int |
||
438 | dri2DrawableGetMSC(struct glx_screen *psc, __GLXDRIdrawable *pdraw, |
||
439 | int64_t *ust, int64_t *msc, int64_t *sbc) |
||
440 | { |
||
441 | xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); |
||
442 | xcb_dri2_get_msc_cookie_t get_msc_cookie; |
||
443 | xcb_dri2_get_msc_reply_t *get_msc_reply; |
||
444 | |||
445 | get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable); |
||
446 | get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL); |
||
447 | |||
448 | if (!get_msc_reply) |
||
449 | return 0; |
||
450 | |||
451 | *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo); |
||
452 | *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo); |
||
453 | *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo); |
||
454 | free(get_msc_reply); |
||
455 | |||
456 | return 1; |
||
457 | } |
||
458 | |||
459 | static int |
||
460 | dri2WaitForMSC(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, |
||
461 | int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) |
||
462 | { |
||
463 | xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); |
||
464 | xcb_dri2_wait_msc_cookie_t wait_msc_cookie; |
||
465 | xcb_dri2_wait_msc_reply_t *wait_msc_reply; |
||
466 | uint32_t target_msc_hi, target_msc_lo; |
||
467 | uint32_t divisor_hi, divisor_lo; |
||
468 | uint32_t remainder_hi, remainder_lo; |
||
469 | |||
470 | split_counter(target_msc, &target_msc_hi, &target_msc_lo); |
||
471 | split_counter(divisor, &divisor_hi, &divisor_lo); |
||
472 | split_counter(remainder, &remainder_hi, &remainder_lo); |
||
473 | |||
474 | wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable, |
||
475 | target_msc_hi, target_msc_lo, |
||
476 | divisor_hi, divisor_lo, |
||
477 | remainder_hi, remainder_lo); |
||
478 | wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL); |
||
479 | |||
480 | if (!wait_msc_reply) |
||
481 | return 0; |
||
482 | |||
483 | *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo); |
||
484 | *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo); |
||
485 | *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo); |
||
486 | free(wait_msc_reply); |
||
487 | |||
488 | return 1; |
||
489 | } |
||
490 | |||
491 | static int |
||
492 | dri2WaitForSBC(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, |
||
493 | int64_t *msc, int64_t *sbc) |
||
494 | { |
||
495 | xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); |
||
496 | xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie; |
||
497 | xcb_dri2_wait_sbc_reply_t *wait_sbc_reply; |
||
498 | uint32_t target_sbc_hi, target_sbc_lo; |
||
499 | |||
500 | split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo); |
||
501 | |||
502 | wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable, |
||
503 | target_sbc_hi, target_sbc_lo); |
||
504 | wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL); |
||
505 | |||
506 | if (!wait_sbc_reply) |
||
507 | return 0; |
||
508 | |||
509 | *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo); |
||
510 | *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo); |
||
511 | *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo); |
||
512 | free(wait_sbc_reply); |
||
513 | |||
514 | return 1; |
||
515 | } |
||
516 | |||
517 | static __DRIcontext * |
||
518 | dri2GetCurrentContext() |
||
519 | { |
||
520 | struct glx_context *gc = __glXGetCurrentContext(); |
||
521 | struct dri2_context *dri2Ctx = (struct dri2_context *)gc; |
||
522 | |||
523 | return dri2Ctx ? dri2Ctx->driContext : NULL; |
||
524 | } |
||
525 | |||
526 | /** |
||
527 | * dri2Throttle - Request driver throttling |
||
528 | * |
||
529 | * This function uses the DRI2 throttle extension to give the |
||
530 | * driver the opportunity to throttle on flush front, copysubbuffer |
||
531 | * and swapbuffers. |
||
532 | */ |
||
533 | static void |
||
534 | dri2Throttle(struct dri2_screen *psc, |
||
535 | struct dri2_drawable *draw, |
||
536 | enum __DRI2throttleReason reason) |
||
537 | { |
||
538 | if (psc->throttle) { |
||
539 | __DRIcontext *ctx = dri2GetCurrentContext(); |
||
540 | |||
541 | psc->throttle->throttle(ctx, draw->driDrawable, reason); |
||
542 | } |
||
543 | } |
||
544 | |||
545 | /** |
||
546 | * Asks the driver to flush any queued work necessary for serializing with the |
||
547 | * X command stream, and optionally the slightly more strict requirement of |
||
548 | * glFlush() equivalence (which would require flushing even if nothing had |
||
549 | * been drawn to a window system framebuffer, for example). |
||
550 | */ |
||
551 | static void |
||
552 | dri2Flush(struct dri2_screen *psc, |
||
553 | __DRIcontext *ctx, |
||
554 | struct dri2_drawable *draw, |
||
555 | unsigned flags, |
||
556 | enum __DRI2throttleReason throttle_reason) |
||
557 | { |
||
558 | if (ctx && psc->f && psc->f->base.version >= 4) { |
||
559 | psc->f->flush_with_flags(ctx, draw->driDrawable, flags, throttle_reason); |
||
560 | } else { |
||
561 | if (flags & __DRI2_FLUSH_CONTEXT) |
||
562 | glFlush(); |
||
563 | |||
564 | if (psc->f) |
||
565 | psc->f->flush(draw->driDrawable); |
||
566 | |||
567 | dri2Throttle(psc, draw, throttle_reason); |
||
568 | } |
||
569 | } |
||
570 | |||
571 | static void |
||
572 | __dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, |
||
573 | int width, int height, |
||
574 | enum __DRI2throttleReason reason, Bool flush) |
||
575 | { |
||
576 | struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; |
||
577 | struct dri2_screen *psc = (struct dri2_screen *) pdraw->psc; |
||
578 | XRectangle xrect; |
||
579 | XserverRegion region; |
||
580 | __DRIcontext *ctx = dri2GetCurrentContext(); |
||
581 | unsigned flags; |
||
582 | |||
583 | /* Check we have the right attachments */ |
||
584 | if (!priv->have_back) |
||
585 | return; |
||
586 | |||
587 | xrect.x = x; |
||
588 | xrect.y = priv->height - y - height; |
||
589 | xrect.width = width; |
||
590 | xrect.height = height; |
||
591 | |||
592 | flags = __DRI2_FLUSH_DRAWABLE; |
||
593 | if (flush) |
||
594 | flags |= __DRI2_FLUSH_CONTEXT; |
||
595 | dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER); |
||
596 | |||
597 | region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); |
||
598 | DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, |
||
599 | DRI2BufferFrontLeft, DRI2BufferBackLeft); |
||
600 | |||
601 | /* Refresh the fake front (if present) after we just damaged the real |
||
602 | * front. |
||
603 | */ |
||
604 | if (priv->have_fake_front) |
||
605 | DRI2CopyRegion(psc->base.dpy, pdraw->xDrawable, region, |
||
606 | DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); |
||
607 | |||
608 | XFixesDestroyRegion(psc->base.dpy, region); |
||
609 | } |
||
610 | |||
611 | static void |
||
612 | dri2CopySubBuffer(__GLXDRIdrawable *pdraw, int x, int y, |
||
613 | int width, int height, Bool flush) |
||
614 | { |
||
615 | __dri2CopySubBuffer(pdraw, x, y, width, height, |
||
616 | __DRI2_THROTTLE_COPYSUBBUFFER, flush); |
||
617 | } |
||
618 | |||
619 | |||
620 | static void |
||
621 | dri2_copy_drawable(struct dri2_drawable *priv, int dest, int src) |
||
622 | { |
||
623 | XRectangle xrect; |
||
624 | XserverRegion region; |
||
625 | struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; |
||
626 | |||
627 | xrect.x = 0; |
||
628 | xrect.y = 0; |
||
629 | xrect.width = priv->width; |
||
630 | xrect.height = priv->height; |
||
631 | |||
632 | if (psc->f) |
||
633 | (*psc->f->flush) (priv->driDrawable); |
||
634 | |||
635 | region = XFixesCreateRegion(psc->base.dpy, &xrect, 1); |
||
636 | DRI2CopyRegion(psc->base.dpy, priv->base.xDrawable, region, dest, src); |
||
637 | XFixesDestroyRegion(psc->base.dpy, region); |
||
638 | |||
639 | } |
||
640 | |||
641 | static void |
||
642 | dri2_wait_x(struct glx_context *gc) |
||
643 | { |
||
644 | struct dri2_drawable *priv = (struct dri2_drawable *) |
||
645 | GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); |
||
646 | |||
647 | if (priv == NULL || !priv->have_fake_front) |
||
648 | return; |
||
649 | |||
650 | dri2_copy_drawable(priv, DRI2BufferFakeFrontLeft, DRI2BufferFrontLeft); |
||
651 | } |
||
652 | |||
653 | static void |
||
654 | dri2_wait_gl(struct glx_context *gc) |
||
655 | { |
||
656 | struct dri2_drawable *priv = (struct dri2_drawable *) |
||
657 | GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); |
||
658 | |||
659 | if (priv == NULL || !priv->have_fake_front) |
||
660 | return; |
||
661 | |||
662 | dri2_copy_drawable(priv, DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft); |
||
663 | } |
||
664 | |||
665 | /** |
||
666 | * Called by the driver when it needs to update the real front buffer with the |
||
667 | * contents of its fake front buffer. |
||
668 | */ |
||
669 | static void |
||
670 | dri2FlushFrontBuffer(__DRIdrawable *driDrawable, void *loaderPrivate) |
||
671 | { |
||
672 | struct glx_display *priv; |
||
673 | struct dri2_display *pdp; |
||
674 | struct glx_context *gc; |
||
675 | struct dri2_drawable *pdraw = loaderPrivate; |
||
676 | struct dri2_screen *psc; |
||
677 | |||
678 | if (!pdraw) |
||
679 | return; |
||
680 | |||
681 | if (!pdraw->base.psc) |
||
682 | return; |
||
683 | |||
684 | psc = (struct dri2_screen *) pdraw->base.psc; |
||
685 | |||
686 | priv = __glXInitialize(psc->base.dpy); |
||
687 | |||
688 | if (priv == NULL) |
||
689 | return; |
||
690 | |||
691 | pdp = (struct dri2_display *) priv->dri2Display; |
||
692 | gc = __glXGetCurrentContext(); |
||
693 | |||
694 | dri2Throttle(psc, pdraw, __DRI2_THROTTLE_FLUSHFRONT); |
||
695 | |||
696 | /* Old servers don't send invalidate events */ |
||
697 | if (!pdp->invalidateAvailable) |
||
698 | dri2InvalidateBuffers(priv->dpy, pdraw->base.xDrawable); |
||
699 | |||
700 | dri2_wait_gl(gc); |
||
701 | } |
||
702 | |||
703 | |||
704 | static void |
||
705 | dri2DestroyScreen(struct glx_screen *base) |
||
706 | { |
||
707 | struct dri2_screen *psc = (struct dri2_screen *) base; |
||
708 | |||
709 | /* Free the direct rendering per screen data */ |
||
710 | (*psc->core->destroyScreen) (psc->driScreen); |
||
711 | driDestroyConfigs(psc->driver_configs); |
||
712 | close(psc->fd); |
||
713 | free(psc); |
||
714 | } |
||
715 | |||
716 | /** |
||
717 | * Process list of buffer received from the server |
||
718 | * |
||
719 | * Processes the list of buffers received in a reply from the server to either |
||
720 | * \c DRI2GetBuffers or \c DRI2GetBuffersWithFormat. |
||
721 | */ |
||
722 | static void |
||
723 | process_buffers(struct dri2_drawable * pdraw, DRI2Buffer * buffers, |
||
724 | unsigned count) |
||
725 | { |
||
726 | int i; |
||
727 | |||
728 | pdraw->bufferCount = count; |
||
729 | pdraw->have_fake_front = 0; |
||
730 | pdraw->have_back = 0; |
||
731 | |||
732 | /* This assumes the DRI2 buffer attachment tokens matches the |
||
733 | * __DRIbuffer tokens. */ |
||
734 | for (i = 0; i < count; i++) { |
||
735 | pdraw->buffers[i].attachment = buffers[i].attachment; |
||
736 | pdraw->buffers[i].name = buffers[i].name; |
||
737 | pdraw->buffers[i].pitch = buffers[i].pitch; |
||
738 | pdraw->buffers[i].cpp = buffers[i].cpp; |
||
739 | pdraw->buffers[i].flags = buffers[i].flags; |
||
740 | if (pdraw->buffers[i].attachment == __DRI_BUFFER_FAKE_FRONT_LEFT) |
||
741 | pdraw->have_fake_front = 1; |
||
742 | if (pdraw->buffers[i].attachment == __DRI_BUFFER_BACK_LEFT) |
||
743 | pdraw->have_back = 1; |
||
744 | } |
||
745 | |||
746 | } |
||
747 | |||
748 | unsigned dri2GetSwapEventType(Display* dpy, XID drawable) |
||
749 | { |
||
750 | struct glx_display *glx_dpy = __glXInitialize(dpy); |
||
751 | __GLXDRIdrawable *pdraw; |
||
752 | pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, drawable); |
||
753 | if (!pdraw || !(pdraw->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)) |
||
754 | return 0; |
||
755 | return glx_dpy->codes->first_event + GLX_BufferSwapComplete; |
||
756 | } |
||
757 | |||
758 | static void show_fps(struct dri2_drawable *draw) |
||
759 | { |
||
760 | const int interval = |
||
761 | ((struct dri2_screen *) draw->base.psc)->show_fps_interval; |
||
762 | struct timeval tv; |
||
763 | uint64_t current_time; |
||
764 | |||
765 | gettimeofday(&tv, 0); |
||
766 | current_time = (uint64_t)tv.tv_sec*1000000 + (uint64_t)tv.tv_usec; |
||
767 | |||
768 | draw->frames++; |
||
769 | |||
770 | if (draw->previous_time + interval * 1000000 <= current_time) { |
||
771 | if (draw->previous_time) { |
||
772 | fprintf(stderr, "libGL: FPS = %.1f\n", |
||
773 | ((uint64_t)draw->frames * 1000000) / |
||
774 | (double)(current_time - draw->previous_time)); |
||
775 | } |
||
776 | draw->frames = 0; |
||
777 | draw->previous_time = current_time; |
||
778 | } |
||
779 | } |
||
780 | |||
781 | static int64_t |
||
782 | dri2XcbSwapBuffers(Display *dpy, |
||
783 | __GLXDRIdrawable *pdraw, |
||
784 | int64_t target_msc, |
||
785 | int64_t divisor, |
||
786 | int64_t remainder) |
||
787 | { |
||
788 | xcb_dri2_swap_buffers_cookie_t swap_buffers_cookie; |
||
789 | xcb_dri2_swap_buffers_reply_t *swap_buffers_reply; |
||
790 | uint32_t target_msc_hi, target_msc_lo; |
||
791 | uint32_t divisor_hi, divisor_lo; |
||
792 | uint32_t remainder_hi, remainder_lo; |
||
793 | int64_t ret = 0; |
||
794 | xcb_connection_t *c = XGetXCBConnection(dpy); |
||
795 | |||
796 | split_counter(target_msc, &target_msc_hi, &target_msc_lo); |
||
797 | split_counter(divisor, &divisor_hi, &divisor_lo); |
||
798 | split_counter(remainder, &remainder_hi, &remainder_lo); |
||
799 | |||
800 | swap_buffers_cookie = |
||
801 | xcb_dri2_swap_buffers_unchecked(c, pdraw->xDrawable, |
||
802 | target_msc_hi, target_msc_lo, |
||
803 | divisor_hi, divisor_lo, |
||
804 | remainder_hi, remainder_lo); |
||
805 | |||
806 | /* Immediately wait on the swapbuffers reply. If we didn't, we'd have |
||
807 | * to do so some time before reusing a (non-pageflipped) backbuffer. |
||
808 | * Otherwise, the new rendering could get ahead of the X Server's |
||
809 | * dispatch of the swapbuffer and you'd display garbage. |
||
810 | * |
||
811 | * We use XSync() first to reap the invalidate events through the event |
||
812 | * filter, to ensure that the next drawing doesn't use an invalidated |
||
813 | * buffer. |
||
814 | */ |
||
815 | XSync(dpy, False); |
||
816 | |||
817 | swap_buffers_reply = |
||
818 | xcb_dri2_swap_buffers_reply(c, swap_buffers_cookie, NULL); |
||
819 | if (swap_buffers_reply) { |
||
820 | ret = merge_counter(swap_buffers_reply->swap_hi, |
||
821 | swap_buffers_reply->swap_lo); |
||
822 | free(swap_buffers_reply); |
||
823 | } |
||
824 | return ret; |
||
825 | } |
||
826 | |||
827 | static int64_t |
||
828 | dri2SwapBuffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, |
||
829 | int64_t remainder, Bool flush) |
||
830 | { |
||
831 | struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; |
||
832 | struct glx_display *dpyPriv = __glXInitialize(priv->base.psc->dpy); |
||
833 | struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; |
||
834 | struct dri2_display *pdp = |
||
835 | (struct dri2_display *)dpyPriv->dri2Display; |
||
836 | int64_t ret = 0; |
||
837 | |||
838 | /* Check we have the right attachments */ |
||
839 | if (!priv->have_back) |
||
840 | return ret; |
||
841 | |||
842 | /* Old servers can't handle swapbuffers */ |
||
843 | if (!pdp->swapAvailable) { |
||
844 | __dri2CopySubBuffer(pdraw, 0, 0, priv->width, priv->height, |
||
845 | __DRI2_THROTTLE_SWAPBUFFER, flush); |
||
846 | } else { |
||
847 | __DRIcontext *ctx = dri2GetCurrentContext(); |
||
848 | unsigned flags = __DRI2_FLUSH_DRAWABLE; |
||
849 | if (flush) |
||
850 | flags |= __DRI2_FLUSH_CONTEXT; |
||
851 | dri2Flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER); |
||
852 | |||
853 | ret = dri2XcbSwapBuffers(pdraw->psc->dpy, pdraw, |
||
854 | target_msc, divisor, remainder); |
||
855 | } |
||
856 | |||
857 | if (psc->show_fps_interval) { |
||
858 | show_fps(priv); |
||
859 | } |
||
860 | |||
861 | /* Old servers don't send invalidate events */ |
||
862 | if (!pdp->invalidateAvailable) |
||
863 | dri2InvalidateBuffers(dpyPriv->dpy, pdraw->xDrawable); |
||
864 | |||
865 | return ret; |
||
866 | } |
||
867 | |||
868 | static __DRIbuffer * |
||
869 | dri2GetBuffers(__DRIdrawable * driDrawable, |
||
870 | int *width, int *height, |
||
871 | unsigned int *attachments, int count, |
||
872 | int *out_count, void *loaderPrivate) |
||
873 | { |
||
874 | struct dri2_drawable *pdraw = loaderPrivate; |
||
875 | DRI2Buffer *buffers; |
||
876 | |||
877 | buffers = DRI2GetBuffers(pdraw->base.psc->dpy, pdraw->base.xDrawable, |
||
878 | width, height, attachments, count, out_count); |
||
879 | if (buffers == NULL) |
||
880 | return NULL; |
||
881 | |||
882 | pdraw->width = *width; |
||
883 | pdraw->height = *height; |
||
884 | process_buffers(pdraw, buffers, *out_count); |
||
885 | |||
886 | free(buffers); |
||
887 | |||
888 | return pdraw->buffers; |
||
889 | } |
||
890 | |||
891 | static __DRIbuffer * |
||
892 | dri2GetBuffersWithFormat(__DRIdrawable * driDrawable, |
||
893 | int *width, int *height, |
||
894 | unsigned int *attachments, int count, |
||
895 | int *out_count, void *loaderPrivate) |
||
896 | { |
||
897 | struct dri2_drawable *pdraw = loaderPrivate; |
||
898 | DRI2Buffer *buffers; |
||
899 | |||
900 | buffers = DRI2GetBuffersWithFormat(pdraw->base.psc->dpy, |
||
901 | pdraw->base.xDrawable, |
||
902 | width, height, attachments, |
||
903 | count, out_count); |
||
904 | if (buffers == NULL) |
||
905 | return NULL; |
||
906 | |||
907 | pdraw->width = *width; |
||
908 | pdraw->height = *height; |
||
909 | process_buffers(pdraw, buffers, *out_count); |
||
910 | |||
911 | free(buffers); |
||
912 | |||
913 | return pdraw->buffers; |
||
914 | } |
||
915 | |||
916 | static int |
||
917 | dri2SetSwapInterval(__GLXDRIdrawable *pdraw, int interval) |
||
918 | { |
||
919 | xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); |
||
920 | struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; |
||
921 | GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; |
||
922 | struct dri2_screen *psc = (struct dri2_screen *) priv->base.psc; |
||
923 | |||
924 | if (psc->config) |
||
925 | psc->config->configQueryi(psc->driScreen, |
||
926 | "vblank_mode", &vblank_mode); |
||
927 | |||
928 | switch (vblank_mode) { |
||
929 | case DRI_CONF_VBLANK_NEVER: |
||
930 | if (interval != 0) |
||
931 | return GLX_BAD_VALUE; |
||
932 | break; |
||
933 | case DRI_CONF_VBLANK_ALWAYS_SYNC: |
||
934 | if (interval <= 0) |
||
935 | return GLX_BAD_VALUE; |
||
936 | break; |
||
937 | default: |
||
938 | break; |
||
939 | } |
||
940 | |||
941 | xcb_dri2_swap_interval(c, priv->base.xDrawable, interval); |
||
942 | priv->swap_interval = interval; |
||
943 | |||
944 | return 0; |
||
945 | } |
||
946 | |||
947 | static int |
||
948 | dri2GetSwapInterval(__GLXDRIdrawable *pdraw) |
||
949 | { |
||
950 | struct dri2_drawable *priv = (struct dri2_drawable *) pdraw; |
||
951 | |||
952 | return priv->swap_interval; |
||
953 | } |
||
954 | |||
955 | static const __DRIdri2LoaderExtension dri2LoaderExtension = { |
||
956 | .base = { __DRI_DRI2_LOADER, 3 }, |
||
957 | |||
958 | .getBuffers = dri2GetBuffers, |
||
959 | .flushFrontBuffer = dri2FlushFrontBuffer, |
||
960 | .getBuffersWithFormat = dri2GetBuffersWithFormat, |
||
961 | }; |
||
962 | |||
963 | static const __DRIdri2LoaderExtension dri2LoaderExtension_old = { |
||
964 | .base = { __DRI_DRI2_LOADER, 3 }, |
||
965 | |||
966 | .getBuffers = dri2GetBuffers, |
||
967 | .flushFrontBuffer = dri2FlushFrontBuffer, |
||
968 | .getBuffersWithFormat = NULL, |
||
969 | }; |
||
970 | |||
971 | static const __DRIuseInvalidateExtension dri2UseInvalidate = { |
||
972 | .base = { __DRI_USE_INVALIDATE, 1 } |
||
973 | }; |
||
974 | |||
975 | _X_HIDDEN void |
||
976 | dri2InvalidateBuffers(Display *dpy, XID drawable) |
||
977 | { |
||
978 | __GLXDRIdrawable *pdraw = |
||
979 | dri2GetGlxDrawableFromXDrawableId(dpy, drawable); |
||
980 | struct dri2_screen *psc; |
||
981 | struct dri2_drawable *pdp = (struct dri2_drawable *) pdraw; |
||
982 | |||
983 | if (!pdraw) |
||
984 | return; |
||
985 | |||
986 | psc = (struct dri2_screen *) pdraw->psc; |
||
987 | |||
988 | if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate) |
||
989 | psc->f->invalidate(pdp->driDrawable); |
||
990 | } |
||
991 | |||
992 | static void |
||
993 | dri2_bind_tex_image(Display * dpy, |
||
994 | GLXDrawable drawable, |
||
995 | int buffer, const int *attrib_list) |
||
996 | { |
||
997 | struct glx_context *gc = __glXGetCurrentContext(); |
||
998 | struct dri2_context *pcp = (struct dri2_context *) gc; |
||
999 | __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); |
||
1000 | struct glx_display *dpyPriv = __glXInitialize(dpy); |
||
1001 | struct dri2_drawable *pdraw = (struct dri2_drawable *) base; |
||
1002 | struct dri2_display *pdp; |
||
1003 | struct dri2_screen *psc; |
||
1004 | |||
1005 | if (dpyPriv == NULL) |
||
1006 | return; |
||
1007 | |||
1008 | pdp = (struct dri2_display *) dpyPriv->dri2Display; |
||
1009 | |||
1010 | if (pdraw != NULL) { |
||
1011 | psc = (struct dri2_screen *) base->psc; |
||
1012 | |||
1013 | if (!pdp->invalidateAvailable && psc->f && |
||
1014 | psc->f->base.version >= 3 && psc->f->invalidate) |
||
1015 | psc->f->invalidate(pdraw->driDrawable); |
||
1016 | |||
1017 | if (psc->texBuffer->base.version >= 2 && |
||
1018 | psc->texBuffer->setTexBuffer2 != NULL) { |
||
1019 | (*psc->texBuffer->setTexBuffer2) (pcp->driContext, |
||
1020 | pdraw->base.textureTarget, |
||
1021 | pdraw->base.textureFormat, |
||
1022 | pdraw->driDrawable); |
||
1023 | } |
||
1024 | else { |
||
1025 | (*psc->texBuffer->setTexBuffer) (pcp->driContext, |
||
1026 | pdraw->base.textureTarget, |
||
1027 | pdraw->driDrawable); |
||
1028 | } |
||
1029 | } |
||
1030 | } |
||
1031 | |||
1032 | static void |
||
1033 | dri2_release_tex_image(Display * dpy, GLXDrawable drawable, int buffer) |
||
1034 | { |
||
1035 | struct glx_context *gc = __glXGetCurrentContext(); |
||
1036 | struct dri2_context *pcp = (struct dri2_context *) gc; |
||
1037 | __GLXDRIdrawable *base = GetGLXDRIDrawable(dpy, drawable); |
||
1038 | struct glx_display *dpyPriv = __glXInitialize(dpy); |
||
1039 | struct dri2_drawable *pdraw = (struct dri2_drawable *) base; |
||
1040 | struct dri2_screen *psc; |
||
1041 | |||
1042 | if (dpyPriv != NULL && pdraw != NULL) { |
||
1043 | psc = (struct dri2_screen *) base->psc; |
||
1044 | |||
1045 | if (psc->texBuffer->base.version >= 3 && |
||
1046 | psc->texBuffer->releaseTexBuffer != NULL) { |
||
1047 | (*psc->texBuffer->releaseTexBuffer) (pcp->driContext, |
||
1048 | pdraw->base.textureTarget, |
||
1049 | pdraw->driDrawable); |
||
1050 | } |
||
1051 | } |
||
1052 | } |
||
1053 | |||
1054 | static const struct glx_context_vtable dri2_context_vtable = { |
||
1055 | .destroy = dri2_destroy_context, |
||
1056 | .bind = dri2_bind_context, |
||
1057 | .unbind = dri2_unbind_context, |
||
1058 | .wait_gl = dri2_wait_gl, |
||
1059 | .wait_x = dri2_wait_x, |
||
1060 | .use_x_font = DRI_glXUseXFont, |
||
1061 | .bind_tex_image = dri2_bind_tex_image, |
||
1062 | .release_tex_image = dri2_release_tex_image, |
||
1063 | .get_proc_address = NULL, |
||
1064 | }; |
||
1065 | |||
1066 | static void |
||
1067 | dri2BindExtensions(struct dri2_screen *psc, struct glx_display * priv, |
||
1068 | const char *driverName) |
||
1069 | { |
||
1070 | const struct dri2_display *const pdp = (struct dri2_display *) |
||
1071 | priv->dri2Display; |
||
1072 | const __DRIextension **extensions; |
||
1073 | int i; |
||
1074 | |||
1075 | extensions = psc->core->getExtensions(psc->driScreen); |
||
1076 | |||
1077 | __glXEnableDirectExtension(&psc->base, "GLX_SGI_video_sync"); |
||
1078 | __glXEnableDirectExtension(&psc->base, "GLX_SGI_swap_control"); |
||
1079 | __glXEnableDirectExtension(&psc->base, "GLX_MESA_swap_control"); |
||
1080 | __glXEnableDirectExtension(&psc->base, "GLX_SGI_make_current_read"); |
||
1081 | |||
1082 | /* |
||
1083 | * GLX_INTEL_swap_event is broken on the server side, where it's |
||
1084 | * currently unconditionally enabled. This completely breaks |
||
1085 | * systems running on drivers which don't support that extension. |
||
1086 | * There's no way to test for its presence on this side, so instead |
||
1087 | * of disabling it unconditionally, just disable it for drivers |
||
1088 | * which are known to not support it, or for DDX drivers supporting |
||
1089 | * only an older (pre-ScheduleSwap) version of DRI2. |
||
1090 | * |
||
1091 | * This is a hack which is required until: |
||
1092 | * http://lists.x.org/archives/xorg-devel/2013-February/035449.html |
||
1093 | * is merged and updated xserver makes it's way into distros: |
||
1094 | */ |
||
1095 | if (pdp->swapAvailable && strcmp(driverName, "vmwgfx") != 0) { |
||
1096 | __glXEnableDirectExtension(&psc->base, "GLX_INTEL_swap_event"); |
||
1097 | } |
||
1098 | |||
1099 | if (psc->dri2->base.version >= 3) { |
||
1100 | const unsigned mask = psc->dri2->getAPIMask(psc->driScreen); |
||
1101 | |||
1102 | __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context"); |
||
1103 | __glXEnableDirectExtension(&psc->base, "GLX_ARB_create_context_profile"); |
||
1104 | |||
1105 | if ((mask & (1 << __DRI_API_GLES2)) != 0) |
||
1106 | __glXEnableDirectExtension(&psc->base, |
||
1107 | "GLX_EXT_create_context_es2_profile"); |
||
1108 | } |
||
1109 | |||
1110 | for (i = 0; extensions[i]; i++) { |
||
1111 | if ((strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { |
||
1112 | psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; |
||
1113 | __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); |
||
1114 | } |
||
1115 | |||
1116 | if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { |
||
1117 | psc->f = (__DRI2flushExtension *) extensions[i]; |
||
1118 | /* internal driver extension, no GL extension exposed */ |
||
1119 | } |
||
1120 | |||
1121 | if ((strcmp(extensions[i]->name, __DRI2_CONFIG_QUERY) == 0)) |
||
1122 | psc->config = (__DRI2configQueryExtension *) extensions[i]; |
||
1123 | |||
1124 | if (((strcmp(extensions[i]->name, __DRI2_THROTTLE) == 0))) |
||
1125 | psc->throttle = (__DRI2throttleExtension *) extensions[i]; |
||
1126 | |||
1127 | /* DRI2 version 3 is also required because |
||
1128 | * GLX_ARB_create_context_robustness requires GLX_ARB_create_context. |
||
1129 | */ |
||
1130 | if (psc->dri2->base.version >= 3 |
||
1131 | && strcmp(extensions[i]->name, __DRI2_ROBUSTNESS) == 0) |
||
1132 | __glXEnableDirectExtension(&psc->base, |
||
1133 | "GLX_ARB_create_context_robustness"); |
||
1134 | |||
1135 | /* DRI2 version 3 is also required because GLX_MESA_query_renderer |
||
1136 | * requires GLX_ARB_create_context_profile. |
||
1137 | */ |
||
1138 | if (psc->dri2->base.version >= 3 |
||
1139 | && strcmp(extensions[i]->name, __DRI2_RENDERER_QUERY) == 0) { |
||
1140 | psc->rendererQuery = (__DRI2rendererQueryExtension *) extensions[i]; |
||
1141 | __glXEnableDirectExtension(&psc->base, "GLX_MESA_query_renderer"); |
||
1142 | } |
||
1143 | } |
||
1144 | } |
||
1145 | |||
1146 | static const struct glx_screen_vtable dri2_screen_vtable = { |
||
1147 | .create_context = dri2_create_context, |
||
1148 | .create_context_attribs = dri2_create_context_attribs, |
||
1149 | .query_renderer_integer = dri2_query_renderer_integer, |
||
1150 | .query_renderer_string = dri2_query_renderer_string, |
||
1151 | }; |
||
1152 | |||
1153 | static struct glx_screen * |
||
1154 | dri2CreateScreen(int screen, struct glx_display * priv) |
||
1155 | { |
||
1156 | const __DRIconfig **driver_configs; |
||
1157 | const __DRIextension **extensions; |
||
1158 | const struct dri2_display *const pdp = (struct dri2_display *) |
||
1159 | priv->dri2Display; |
||
1160 | struct dri2_screen *psc; |
||
1161 | __GLXDRIscreen *psp; |
||
1162 | struct glx_config *configs = NULL, *visuals = NULL; |
||
1163 | char *driverName = NULL, *loader_driverName, *deviceName, *tmp; |
||
1164 | drm_magic_t magic; |
||
1165 | int i; |
||
1166 | |||
1167 | psc = calloc(1, sizeof *psc); |
||
1168 | if (psc == NULL) |
||
1169 | return NULL; |
||
1170 | |||
1171 | psc->fd = -1; |
||
1172 | |||
1173 | if (!glx_screen_init(&psc->base, screen, priv)) { |
||
1174 | free(psc); |
||
1175 | return NULL; |
||
1176 | } |
||
1177 | |||
1178 | if (!DRI2Connect(priv->dpy, RootWindow(priv->dpy, screen), |
||
1179 | &driverName, &deviceName)) { |
||
1180 | glx_screen_cleanup(&psc->base); |
||
1181 | free(psc); |
||
1182 | InfoMessageF("screen %d does not appear to be DRI2 capable\n", screen); |
||
1183 | return NULL; |
||
1184 | } |
||
1185 | |||
1186 | #ifdef O_CLOEXEC |
||
1187 | psc->fd = open(deviceName, O_RDWR | O_CLOEXEC); |
||
1188 | if (psc->fd == -1 && errno == EINVAL) |
||
1189 | #endif |
||
1190 | { |
||
1191 | psc->fd = open(deviceName, O_RDWR); |
||
1192 | if (psc->fd != -1) |
||
1193 | fcntl(psc->fd, F_SETFD, fcntl(psc->fd, F_GETFD) | FD_CLOEXEC); |
||
1194 | } |
||
1195 | if (psc->fd < 0) { |
||
1196 | ErrorMessageF("failed to open drm device: %s\n", strerror(errno)); |
||
1197 | goto handle_error; |
||
1198 | } |
||
1199 | |||
1200 | if (drmGetMagic(psc->fd, &magic)) { |
||
1201 | ErrorMessageF("failed to get magic\n"); |
||
1202 | goto handle_error; |
||
1203 | } |
||
1204 | |||
1205 | if (!DRI2Authenticate(priv->dpy, RootWindow(priv->dpy, screen), magic)) { |
||
1206 | ErrorMessageF("failed to authenticate magic %d\n", magic); |
||
1207 | goto handle_error; |
||
1208 | } |
||
1209 | |||
1210 | /* If Mesa knows about the appropriate driver for this fd, then trust it. |
||
1211 | * Otherwise, default to the server's value. |
||
1212 | */ |
||
1213 | loader_driverName = loader_get_driver_for_fd(psc->fd, 0); |
||
1214 | if (loader_driverName) { |
||
1215 | free(driverName); |
||
1216 | driverName = loader_driverName; |
||
1217 | } |
||
1218 | |||
1219 | psc->driver = driOpenDriver(driverName); |
||
1220 | if (psc->driver == NULL) { |
||
1221 | ErrorMessageF("driver pointer missing\n"); |
||
1222 | goto handle_error; |
||
1223 | } |
||
1224 | |||
1225 | extensions = driGetDriverExtensions(psc->driver, driverName); |
||
1226 | if (extensions == NULL) |
||
1227 | goto handle_error; |
||
1228 | |||
1229 | for (i = 0; extensions[i]; i++) { |
||
1230 | if (strcmp(extensions[i]->name, __DRI_CORE) == 0) |
||
1231 | psc->core = (__DRIcoreExtension *) extensions[i]; |
||
1232 | if (strcmp(extensions[i]->name, __DRI_DRI2) == 0) |
||
1233 | psc->dri2 = (__DRIdri2Extension *) extensions[i]; |
||
1234 | } |
||
1235 | |||
1236 | if (psc->core == NULL || psc->dri2 == NULL) { |
||
1237 | ErrorMessageF("core dri or dri2 extension not found\n"); |
||
1238 | goto handle_error; |
||
1239 | } |
||
1240 | |||
1241 | if (psc->dri2->base.version >= 4) { |
||
1242 | psc->driScreen = |
||
1243 | psc->dri2->createNewScreen2(screen, psc->fd, |
||
1244 | (const __DRIextension **) |
||
1245 | &pdp->loader_extensions[0], |
||
1246 | extensions, |
||
1247 | &driver_configs, psc); |
||
1248 | } else { |
||
1249 | psc->driScreen = |
||
1250 | psc->dri2->createNewScreen(screen, psc->fd, |
||
1251 | (const __DRIextension **) |
||
1252 | &pdp->loader_extensions[0], |
||
1253 | &driver_configs, psc); |
||
1254 | } |
||
1255 | |||
1256 | if (psc->driScreen == NULL) { |
||
1257 | ErrorMessageF("failed to create dri screen\n"); |
||
1258 | goto handle_error; |
||
1259 | } |
||
1260 | |||
1261 | dri2BindExtensions(psc, priv, driverName); |
||
1262 | |||
1263 | configs = driConvertConfigs(psc->core, psc->base.configs, driver_configs); |
||
1264 | visuals = driConvertConfigs(psc->core, psc->base.visuals, driver_configs); |
||
1265 | |||
1266 | if (!configs || !visuals) { |
||
1267 | ErrorMessageF("No matching fbConfigs or visuals found\n"); |
||
1268 | goto handle_error; |
||
1269 | } |
||
1270 | |||
1271 | glx_config_destroy_list(psc->base.configs); |
||
1272 | psc->base.configs = configs; |
||
1273 | glx_config_destroy_list(psc->base.visuals); |
||
1274 | psc->base.visuals = visuals; |
||
1275 | |||
1276 | psc->driver_configs = driver_configs; |
||
1277 | |||
1278 | psc->base.vtable = &dri2_screen_vtable; |
||
1279 | psp = &psc->vtable; |
||
1280 | psc->base.driScreen = psp; |
||
1281 | psp->destroyScreen = dri2DestroyScreen; |
||
1282 | psp->createDrawable = dri2CreateDrawable; |
||
1283 | psp->swapBuffers = dri2SwapBuffers; |
||
1284 | psp->getDrawableMSC = NULL; |
||
1285 | psp->waitForMSC = NULL; |
||
1286 | psp->waitForSBC = NULL; |
||
1287 | psp->setSwapInterval = NULL; |
||
1288 | psp->getSwapInterval = NULL; |
||
1289 | psp->getBufferAge = NULL; |
||
1290 | |||
1291 | if (pdp->driMinor >= 2) { |
||
1292 | psp->getDrawableMSC = dri2DrawableGetMSC; |
||
1293 | psp->waitForMSC = dri2WaitForMSC; |
||
1294 | psp->waitForSBC = dri2WaitForSBC; |
||
1295 | psp->setSwapInterval = dri2SetSwapInterval; |
||
1296 | psp->getSwapInterval = dri2GetSwapInterval; |
||
1297 | __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); |
||
1298 | } |
||
1299 | |||
1300 | /* DRI2 suports SubBuffer through DRI2CopyRegion, so it's always |
||
1301 | * available.*/ |
||
1302 | psp->copySubBuffer = dri2CopySubBuffer; |
||
1303 | __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); |
||
1304 | |||
1305 | free(driverName); |
||
1306 | free(deviceName); |
||
1307 | |||
1308 | tmp = getenv("LIBGL_SHOW_FPS"); |
||
1309 | psc->show_fps_interval = (tmp) ? atoi(tmp) : 0; |
||
1310 | if (psc->show_fps_interval < 0) |
||
1311 | psc->show_fps_interval = 0; |
||
1312 | |||
1313 | InfoMessageF("Using DRI2 for screen %d\n", screen); |
||
1314 | |||
1315 | return &psc->base; |
||
1316 | |||
1317 | handle_error: |
||
1318 | CriticalErrorMessageF("failed to load driver: %s\n", driverName); |
||
1319 | |||
1320 | if (configs) |
||
1321 | glx_config_destroy_list(configs); |
||
1322 | if (visuals) |
||
1323 | glx_config_destroy_list(visuals); |
||
1324 | if (psc->driScreen) |
||
1325 | psc->core->destroyScreen(psc->driScreen); |
||
1326 | psc->driScreen = NULL; |
||
1327 | if (psc->fd >= 0) |
||
1328 | close(psc->fd); |
||
1329 | if (psc->driver) |
||
1330 | dlclose(psc->driver); |
||
1331 | |||
1332 | free(driverName); |
||
1333 | free(deviceName); |
||
1334 | glx_screen_cleanup(&psc->base); |
||
1335 | free(psc); |
||
1336 | |||
1337 | return NULL; |
||
1338 | } |
||
1339 | |||
1340 | /* Called from __glXFreeDisplayPrivate. |
||
1341 | */ |
||
1342 | static void |
||
1343 | dri2DestroyDisplay(__GLXDRIdisplay * dpy) |
||
1344 | { |
||
1345 | struct dri2_display *pdp = (struct dri2_display *) dpy; |
||
1346 | |||
1347 | __glxHashDestroy(pdp->dri2Hash); |
||
1348 | free(dpy); |
||
1349 | } |
||
1350 | |||
1351 | _X_HIDDEN __GLXDRIdrawable * |
||
1352 | dri2GetGlxDrawableFromXDrawableId(Display *dpy, XID id) |
||
1353 | { |
||
1354 | struct glx_display *d = __glXInitialize(dpy); |
||
1355 | struct dri2_display *pdp = (struct dri2_display *) d->dri2Display; |
||
1356 | __GLXDRIdrawable *pdraw; |
||
1357 | |||
1358 | if (__glxHashLookup(pdp->dri2Hash, id, (void *) &pdraw) == 0) |
||
1359 | return pdraw; |
||
1360 | |||
1361 | return NULL; |
||
1362 | } |
||
1363 | |||
1364 | /* |
||
1365 | * Allocate, initialize and return a __DRIdisplayPrivate object. |
||
1366 | * This is called from __glXInitialize() when we are given a new |
||
1367 | * display pointer. |
||
1368 | */ |
||
1369 | _X_HIDDEN __GLXDRIdisplay * |
||
1370 | dri2CreateDisplay(Display * dpy) |
||
1371 | { |
||
1372 | struct dri2_display *pdp; |
||
1373 | int eventBase, errorBase, i; |
||
1374 | |||
1375 | if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) |
||
1376 | return NULL; |
||
1377 | |||
1378 | pdp = malloc(sizeof *pdp); |
||
1379 | if (pdp == NULL) |
||
1380 | return NULL; |
||
1381 | |||
1382 | if (!DRI2QueryVersion(dpy, &pdp->driMajor, &pdp->driMinor)) { |
||
1383 | free(pdp); |
||
1384 | return NULL; |
||
1385 | } |
||
1386 | |||
1387 | pdp->driPatch = 0; |
||
1388 | pdp->swapAvailable = (pdp->driMinor >= 2); |
||
1389 | pdp->invalidateAvailable = (pdp->driMinor >= 3); |
||
1390 | |||
1391 | pdp->base.destroyDisplay = dri2DestroyDisplay; |
||
1392 | pdp->base.createScreen = dri2CreateScreen; |
||
1393 | |||
1394 | i = 0; |
||
1395 | if (pdp->driMinor < 1) |
||
1396 | pdp->loader_extensions[i++] = &dri2LoaderExtension_old.base; |
||
1397 | else |
||
1398 | pdp->loader_extensions[i++] = &dri2LoaderExtension.base; |
||
1399 | |||
1400 | pdp->loader_extensions[i++] = &systemTimeExtension.base; |
||
1401 | |||
1402 | pdp->loader_extensions[i++] = &dri2UseInvalidate.base; |
||
1403 | |||
1404 | pdp->loader_extensions[i++] = NULL; |
||
1405 | |||
1406 | pdp->dri2Hash = __glxHashCreate(); |
||
1407 | if (pdp->dri2Hash == NULL) { |
||
1408 | free(pdp); |
||
1409 | return NULL; |
||
1410 | } |
||
1411 | |||
1412 | return &pdp->base; |
||
1413 | } |
||
1414 | |||
1415 | #endif /* GLX_DIRECT_RENDERING */>>>><>=>=>>>><> |