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