xref: /aosp_15_r20/external/mesa3d/src/glx/dri2.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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