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