Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5563 | 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 | |||
34 | #ifdef GLX_DIRECT_RENDERING |
||
35 | |||
36 | #include |
||
37 | #include |
||
38 | #include |
||
39 | #include |
||
40 | #include |
||
41 | #include "xf86drm.h" |
||
42 | #include "dri2.h" |
||
43 | #include "glxclient.h" |
||
44 | #include "GL/glxext.h" |
||
45 | |||
46 | /* Allow the build to work with an older versions of dri2proto.h and |
||
47 | * dri2tokens.h. |
||
48 | */ |
||
49 | #if DRI2_MINOR < 1 |
||
50 | #undef DRI2_MINOR |
||
51 | #define DRI2_MINOR 1 |
||
52 | #define X_DRI2GetBuffersWithFormat 7 |
||
53 | #endif |
||
54 | |||
55 | |||
56 | static char dri2ExtensionName[] = DRI2_NAME; |
||
57 | static XExtensionInfo *dri2Info; |
||
58 | static XEXT_GENERATE_CLOSE_DISPLAY (DRI2CloseDisplay, dri2Info) |
||
59 | |||
60 | static Bool |
||
61 | DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire); |
||
62 | static Status |
||
63 | DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire); |
||
64 | static int |
||
65 | DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code); |
||
66 | |||
67 | static /* const */ XExtensionHooks dri2ExtensionHooks = { |
||
68 | NULL, /* create_gc */ |
||
69 | NULL, /* copy_gc */ |
||
70 | NULL, /* flush_gc */ |
||
71 | NULL, /* free_gc */ |
||
72 | NULL, /* create_font */ |
||
73 | NULL, /* free_font */ |
||
74 | DRI2CloseDisplay, /* close_display */ |
||
75 | DRI2WireToEvent, /* wire_to_event */ |
||
76 | DRI2EventToWire, /* event_to_wire */ |
||
77 | DRI2Error, /* error */ |
||
78 | NULL, /* error_string */ |
||
79 | }; |
||
80 | |||
81 | static XEXT_GENERATE_FIND_DISPLAY (DRI2FindDisplay, |
||
82 | dri2Info, |
||
83 | dri2ExtensionName, |
||
84 | &dri2ExtensionHooks, |
||
85 | 0, NULL) |
||
86 | |||
87 | static Bool |
||
88 | DRI2WireToEvent(Display *dpy, XEvent *event, xEvent *wire) |
||
89 | { |
||
90 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
91 | struct glx_drawable *glxDraw; |
||
92 | |||
93 | XextCheckExtension(dpy, info, dri2ExtensionName, False); |
||
94 | |||
95 | switch ((wire->u.u.type & 0x7f) - info->codes->first_event) { |
||
96 | |||
97 | #ifdef X_DRI2SwapBuffers |
||
98 | case DRI2_BufferSwapComplete: |
||
99 | { |
||
100 | GLXBufferSwapComplete *aevent = (GLXBufferSwapComplete *)event; |
||
101 | xDRI2BufferSwapComplete2 *awire = (xDRI2BufferSwapComplete2 *)wire; |
||
102 | __GLXDRIdrawable *pdraw; |
||
103 | |||
104 | pdraw = dri2GetGlxDrawableFromXDrawableId(dpy, awire->drawable); |
||
105 | |||
106 | /* Ignore swap events if we're not looking for them */ |
||
107 | aevent->type = dri2GetSwapEventType(dpy, awire->drawable); |
||
108 | if(!aevent->type) |
||
109 | return False; |
||
110 | |||
111 | aevent->serial = _XSetLastRequestRead(dpy, (xGenericReply *) wire); |
||
112 | aevent->send_event = (awire->type & 0x80) != 0; |
||
113 | aevent->display = dpy; |
||
114 | aevent->drawable = awire->drawable; |
||
115 | switch (awire->event_type) { |
||
116 | case DRI2_EXCHANGE_COMPLETE: |
||
117 | aevent->event_type = GLX_EXCHANGE_COMPLETE_INTEL; |
||
118 | break; |
||
119 | case DRI2_BLIT_COMPLETE: |
||
120 | aevent->event_type = GLX_COPY_COMPLETE_INTEL; |
||
121 | break; |
||
122 | case DRI2_FLIP_COMPLETE: |
||
123 | aevent->event_type = GLX_FLIP_COMPLETE_INTEL; |
||
124 | break; |
||
125 | default: |
||
126 | /* unknown swap completion type */ |
||
127 | return False; |
||
128 | } |
||
129 | aevent->ust = ((CARD64)awire->ust_hi << 32) | awire->ust_lo; |
||
130 | aevent->msc = ((CARD64)awire->msc_hi << 32) | awire->msc_lo; |
||
131 | |||
132 | glxDraw = GetGLXDrawable(dpy, pdraw->drawable); |
||
133 | if (awire->sbc < glxDraw->lastEventSbc) |
||
134 | glxDraw->eventSbcWrap += 0x100000000; |
||
135 | glxDraw->lastEventSbc = awire->sbc; |
||
136 | aevent->sbc = awire->sbc + glxDraw->eventSbcWrap; |
||
137 | |||
138 | return True; |
||
139 | } |
||
140 | #endif |
||
141 | #ifdef DRI2_InvalidateBuffers |
||
142 | case DRI2_InvalidateBuffers: |
||
143 | { |
||
144 | xDRI2InvalidateBuffers *awire = (xDRI2InvalidateBuffers *)wire; |
||
145 | |||
146 | dri2InvalidateBuffers(dpy, awire->drawable); |
||
147 | return False; |
||
148 | } |
||
149 | #endif |
||
150 | default: |
||
151 | /* client doesn't support server event */ |
||
152 | break; |
||
153 | } |
||
154 | |||
155 | return False; |
||
156 | } |
||
157 | |||
158 | /* We don't actually support this. It doesn't make sense for clients to |
||
159 | * send each other DRI2 events. |
||
160 | */ |
||
161 | static Status |
||
162 | DRI2EventToWire(Display *dpy, XEvent *event, xEvent *wire) |
||
163 | { |
||
164 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
165 | |||
166 | XextCheckExtension(dpy, info, dri2ExtensionName, False); |
||
167 | |||
168 | switch (event->type) { |
||
169 | default: |
||
170 | /* client doesn't support server event */ |
||
171 | break; |
||
172 | } |
||
173 | |||
174 | return Success; |
||
175 | } |
||
176 | |||
177 | static int |
||
178 | DRI2Error(Display *display, xError *err, XExtCodes *codes, int *ret_code) |
||
179 | { |
||
180 | if (err->majorCode == codes->major_opcode && |
||
181 | err->errorCode == BadDrawable && |
||
182 | err->minorCode == X_DRI2CopyRegion) |
||
183 | return True; |
||
184 | |||
185 | /* If the X drawable was destroyed before the GLX drawable, the |
||
186 | * DRI2 drawble will be gone by the time we call |
||
187 | * DRI2DestroyDrawable. So just ignore BadDrawable here. */ |
||
188 | if (err->majorCode == codes->major_opcode && |
||
189 | err->errorCode == BadDrawable && |
||
190 | err->minorCode == X_DRI2DestroyDrawable) |
||
191 | return True; |
||
192 | |||
193 | /* If the server is non-local DRI2Connect will raise BadRequest. |
||
194 | * Swallow this so that DRI2Connect can signal this in its return code */ |
||
195 | if (err->majorCode == codes->major_opcode && |
||
196 | err->minorCode == X_DRI2Connect && |
||
197 | err->errorCode == BadRequest) { |
||
198 | *ret_code = False; |
||
199 | return True; |
||
200 | } |
||
201 | |||
202 | return False; |
||
203 | } |
||
204 | |||
205 | Bool |
||
206 | DRI2QueryExtension(Display * dpy, int *eventBase, int *errorBase) |
||
207 | { |
||
208 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
209 | |||
210 | if (XextHasExtension(info)) { |
||
211 | *eventBase = info->codes->first_event; |
||
212 | *errorBase = info->codes->first_error; |
||
213 | return True; |
||
214 | } |
||
215 | |||
216 | return False; |
||
217 | } |
||
218 | |||
219 | Bool |
||
220 | DRI2QueryVersion(Display * dpy, int *major, int *minor) |
||
221 | { |
||
222 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
223 | xDRI2QueryVersionReply rep; |
||
224 | xDRI2QueryVersionReq *req; |
||
225 | int i, nevents; |
||
226 | |||
227 | XextCheckExtension(dpy, info, dri2ExtensionName, False); |
||
228 | |||
229 | LockDisplay(dpy); |
||
230 | GetReq(DRI2QueryVersion, req); |
||
231 | req->reqType = info->codes->major_opcode; |
||
232 | req->dri2ReqType = X_DRI2QueryVersion; |
||
233 | req->majorVersion = DRI2_MAJOR; |
||
234 | req->minorVersion = DRI2_MINOR; |
||
235 | if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { |
||
236 | UnlockDisplay(dpy); |
||
237 | SyncHandle(); |
||
238 | return False; |
||
239 | } |
||
240 | *major = rep.majorVersion; |
||
241 | *minor = rep.minorVersion; |
||
242 | UnlockDisplay(dpy); |
||
243 | SyncHandle(); |
||
244 | |||
245 | switch (rep.minorVersion) { |
||
246 | case 1: |
||
247 | nevents = 0; |
||
248 | break; |
||
249 | case 2: |
||
250 | nevents = 1; |
||
251 | break; |
||
252 | case 3: |
||
253 | default: |
||
254 | nevents = 2; |
||
255 | break; |
||
256 | } |
||
257 | |||
258 | for (i = 0; i < nevents; i++) { |
||
259 | XESetWireToEvent (dpy, info->codes->first_event + i, DRI2WireToEvent); |
||
260 | XESetEventToWire (dpy, info->codes->first_event + i, DRI2EventToWire); |
||
261 | } |
||
262 | |||
263 | return True; |
||
264 | } |
||
265 | |||
266 | Bool |
||
267 | DRI2Connect(Display * dpy, XID window, char **driverName, char **deviceName) |
||
268 | { |
||
269 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
270 | xDRI2ConnectReply rep; |
||
271 | xDRI2ConnectReq *req; |
||
272 | |||
273 | XextCheckExtension(dpy, info, dri2ExtensionName, False); |
||
274 | |||
275 | LockDisplay(dpy); |
||
276 | GetReq(DRI2Connect, req); |
||
277 | req->reqType = info->codes->major_opcode; |
||
278 | req->dri2ReqType = X_DRI2Connect; |
||
279 | req->window = window; |
||
280 | |||
281 | req->driverType = DRI2DriverDRI; |
||
282 | #ifdef DRI2DriverPrimeShift |
||
283 | { |
||
284 | char *prime = getenv("DRI_PRIME"); |
||
285 | if (prime) { |
||
286 | uint32_t primeid; |
||
287 | errno = 0; |
||
288 | primeid = strtoul(prime, NULL, 0); |
||
289 | if (errno == 0) |
||
290 | req->driverType |= |
||
291 | ((primeid & DRI2DriverPrimeMask) << DRI2DriverPrimeShift); |
||
292 | } |
||
293 | } |
||
294 | #endif |
||
295 | |||
296 | if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { |
||
297 | UnlockDisplay(dpy); |
||
298 | SyncHandle(); |
||
299 | return False; |
||
300 | } |
||
301 | |||
302 | if (rep.driverNameLength == 0 && rep.deviceNameLength == 0) { |
||
303 | UnlockDisplay(dpy); |
||
304 | SyncHandle(); |
||
305 | return False; |
||
306 | } |
||
307 | |||
308 | *driverName = malloc(rep.driverNameLength + 1); |
||
309 | if (*driverName == NULL) { |
||
310 | _XEatData(dpy, |
||
311 | ((rep.driverNameLength + 3) & ~3) + |
||
312 | ((rep.deviceNameLength + 3) & ~3)); |
||
313 | UnlockDisplay(dpy); |
||
314 | SyncHandle(); |
||
315 | return False; |
||
316 | } |
||
317 | _XReadPad(dpy, *driverName, rep.driverNameLength); |
||
318 | (*driverName)[rep.driverNameLength] = '\0'; |
||
319 | |||
320 | *deviceName = malloc(rep.deviceNameLength + 1); |
||
321 | if (*deviceName == NULL) { |
||
322 | free(*driverName); |
||
323 | _XEatData(dpy, ((rep.deviceNameLength + 3) & ~3)); |
||
324 | UnlockDisplay(dpy); |
||
325 | SyncHandle(); |
||
326 | return False; |
||
327 | } |
||
328 | _XReadPad(dpy, *deviceName, rep.deviceNameLength); |
||
329 | (*deviceName)[rep.deviceNameLength] = '\0'; |
||
330 | |||
331 | UnlockDisplay(dpy); |
||
332 | SyncHandle(); |
||
333 | |||
334 | return True; |
||
335 | } |
||
336 | |||
337 | Bool |
||
338 | DRI2Authenticate(Display * dpy, XID window, drm_magic_t magic) |
||
339 | { |
||
340 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
341 | xDRI2AuthenticateReq *req; |
||
342 | xDRI2AuthenticateReply rep; |
||
343 | |||
344 | XextCheckExtension(dpy, info, dri2ExtensionName, False); |
||
345 | |||
346 | LockDisplay(dpy); |
||
347 | GetReq(DRI2Authenticate, req); |
||
348 | req->reqType = info->codes->major_opcode; |
||
349 | req->dri2ReqType = X_DRI2Authenticate; |
||
350 | req->window = window; |
||
351 | req->magic = magic; |
||
352 | |||
353 | if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { |
||
354 | UnlockDisplay(dpy); |
||
355 | SyncHandle(); |
||
356 | return False; |
||
357 | } |
||
358 | |||
359 | UnlockDisplay(dpy); |
||
360 | SyncHandle(); |
||
361 | |||
362 | return rep.authenticated; |
||
363 | } |
||
364 | |||
365 | void |
||
366 | DRI2CreateDrawable(Display * dpy, XID drawable) |
||
367 | { |
||
368 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
369 | xDRI2CreateDrawableReq *req; |
||
370 | |||
371 | XextSimpleCheckExtension(dpy, info, dri2ExtensionName); |
||
372 | |||
373 | LockDisplay(dpy); |
||
374 | GetReq(DRI2CreateDrawable, req); |
||
375 | req->reqType = info->codes->major_opcode; |
||
376 | req->dri2ReqType = X_DRI2CreateDrawable; |
||
377 | req->drawable = drawable; |
||
378 | UnlockDisplay(dpy); |
||
379 | SyncHandle(); |
||
380 | } |
||
381 | |||
382 | void |
||
383 | DRI2DestroyDrawable(Display * dpy, XID drawable) |
||
384 | { |
||
385 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
386 | xDRI2DestroyDrawableReq *req; |
||
387 | |||
388 | XextSimpleCheckExtension(dpy, info, dri2ExtensionName); |
||
389 | |||
390 | XSync(dpy, False); |
||
391 | |||
392 | LockDisplay(dpy); |
||
393 | GetReq(DRI2DestroyDrawable, req); |
||
394 | req->reqType = info->codes->major_opcode; |
||
395 | req->dri2ReqType = X_DRI2DestroyDrawable; |
||
396 | req->drawable = drawable; |
||
397 | UnlockDisplay(dpy); |
||
398 | SyncHandle(); |
||
399 | } |
||
400 | |||
401 | DRI2Buffer * |
||
402 | DRI2GetBuffers(Display * dpy, XID drawable, |
||
403 | int *width, int *height, |
||
404 | unsigned int *attachments, int count, int *outCount) |
||
405 | { |
||
406 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
407 | xDRI2GetBuffersReply rep; |
||
408 | xDRI2GetBuffersReq *req; |
||
409 | DRI2Buffer *buffers; |
||
410 | xDRI2Buffer repBuffer; |
||
411 | CARD32 *p; |
||
412 | int i; |
||
413 | |||
414 | XextCheckExtension(dpy, info, dri2ExtensionName, False); |
||
415 | |||
416 | LockDisplay(dpy); |
||
417 | GetReqExtra(DRI2GetBuffers, count * 4, req); |
||
418 | req->reqType = info->codes->major_opcode; |
||
419 | req->dri2ReqType = X_DRI2GetBuffers; |
||
420 | req->drawable = drawable; |
||
421 | req->count = count; |
||
422 | p = (CARD32 *) & req[1]; |
||
423 | for (i = 0; i < count; i++) |
||
424 | p[i] = attachments[i]; |
||
425 | |||
426 | if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { |
||
427 | UnlockDisplay(dpy); |
||
428 | SyncHandle(); |
||
429 | return NULL; |
||
430 | } |
||
431 | |||
432 | *width = rep.width; |
||
433 | *height = rep.height; |
||
434 | *outCount = rep.count; |
||
435 | |||
436 | buffers = malloc(rep.count * sizeof buffers[0]); |
||
437 | if (buffers == NULL) { |
||
438 | _XEatData(dpy, rep.count * sizeof repBuffer); |
||
439 | UnlockDisplay(dpy); |
||
440 | SyncHandle(); |
||
441 | return NULL; |
||
442 | } |
||
443 | |||
444 | for (i = 0; i < rep.count; i++) { |
||
445 | _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); |
||
446 | buffers[i].attachment = repBuffer.attachment; |
||
447 | buffers[i].name = repBuffer.name; |
||
448 | buffers[i].pitch = repBuffer.pitch; |
||
449 | buffers[i].cpp = repBuffer.cpp; |
||
450 | buffers[i].flags = repBuffer.flags; |
||
451 | } |
||
452 | |||
453 | UnlockDisplay(dpy); |
||
454 | SyncHandle(); |
||
455 | |||
456 | return buffers; |
||
457 | } |
||
458 | |||
459 | |||
460 | DRI2Buffer * |
||
461 | DRI2GetBuffersWithFormat(Display * dpy, XID drawable, |
||
462 | int *width, int *height, |
||
463 | unsigned int *attachments, int count, int *outCount) |
||
464 | { |
||
465 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
466 | xDRI2GetBuffersReply rep; |
||
467 | xDRI2GetBuffersReq *req; |
||
468 | DRI2Buffer *buffers; |
||
469 | xDRI2Buffer repBuffer; |
||
470 | CARD32 *p; |
||
471 | int i; |
||
472 | |||
473 | XextCheckExtension(dpy, info, dri2ExtensionName, False); |
||
474 | |||
475 | LockDisplay(dpy); |
||
476 | GetReqExtra(DRI2GetBuffers, count * (4 * 2), req); |
||
477 | req->reqType = info->codes->major_opcode; |
||
478 | req->dri2ReqType = X_DRI2GetBuffersWithFormat; |
||
479 | req->drawable = drawable; |
||
480 | req->count = count; |
||
481 | p = (CARD32 *) & req[1]; |
||
482 | for (i = 0; i < (count * 2); i++) |
||
483 | p[i] = attachments[i]; |
||
484 | |||
485 | if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) { |
||
486 | UnlockDisplay(dpy); |
||
487 | SyncHandle(); |
||
488 | return NULL; |
||
489 | } |
||
490 | |||
491 | *width = rep.width; |
||
492 | *height = rep.height; |
||
493 | *outCount = rep.count; |
||
494 | |||
495 | buffers = malloc(rep.count * sizeof buffers[0]); |
||
496 | if (buffers == NULL) { |
||
497 | _XEatData(dpy, rep.count * sizeof repBuffer); |
||
498 | UnlockDisplay(dpy); |
||
499 | SyncHandle(); |
||
500 | return NULL; |
||
501 | } |
||
502 | |||
503 | for (i = 0; i < rep.count; i++) { |
||
504 | _XReadPad(dpy, (char *) &repBuffer, sizeof repBuffer); |
||
505 | buffers[i].attachment = repBuffer.attachment; |
||
506 | buffers[i].name = repBuffer.name; |
||
507 | buffers[i].pitch = repBuffer.pitch; |
||
508 | buffers[i].cpp = repBuffer.cpp; |
||
509 | buffers[i].flags = repBuffer.flags; |
||
510 | } |
||
511 | |||
512 | UnlockDisplay(dpy); |
||
513 | SyncHandle(); |
||
514 | |||
515 | return buffers; |
||
516 | } |
||
517 | |||
518 | |||
519 | void |
||
520 | DRI2CopyRegion(Display * dpy, XID drawable, XserverRegion region, |
||
521 | CARD32 dest, CARD32 src) |
||
522 | { |
||
523 | XExtDisplayInfo *info = DRI2FindDisplay(dpy); |
||
524 | xDRI2CopyRegionReq *req; |
||
525 | xDRI2CopyRegionReply rep; |
||
526 | |||
527 | XextSimpleCheckExtension(dpy, info, dri2ExtensionName); |
||
528 | |||
529 | LockDisplay(dpy); |
||
530 | GetReq(DRI2CopyRegion, req); |
||
531 | req->reqType = info->codes->major_opcode; |
||
532 | req->dri2ReqType = X_DRI2CopyRegion; |
||
533 | req->drawable = drawable; |
||
534 | req->region = region; |
||
535 | req->dest = dest; |
||
536 | req->src = src; |
||
537 | |||
538 | _XReply(dpy, (xReply *) & rep, 0, xFalse); |
||
539 | |||
540 | UnlockDisplay(dpy); |
||
541 | SyncHandle(); |
||
542 | } |
||
543 | |||
544 | #endif /* GLX_DIRECT_RENDERING */>>>>><>>>><>><>> |