1/* $XFree86: xc/lib/GL/dri/XF86dri.c,v 1.13 2002/10/30 12:51:25 alanh Exp $ */
2/**************************************************************************
3
4Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
5Copyright 2000 VA Linux Systems, Inc.
6All Rights Reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a
9copy of this software and associated documentation files (the
10"Software"), to deal in the Software without restriction, including
11without limitation the rights to use, copy, modify, merge, publish,
12distribute, sub license, and/or sell copies of the Software, and to
13permit persons to whom the Software is furnished to do so, subject to
14the following conditions:
15
16The above copyright notice and this permission notice (including the
17next paragraph) shall be included in all copies or substantial portions
18of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
24ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28**************************************************************************/
29
30/*
31 * Authors:
32 *   Kevin E. Martin <martin@valinux.com>
33 *   Jens Owen <jens@tungstengraphics.com>
34 *   Rickard E. (Rik) Faith <faith@valinux.com>
35 *
36 */
37
38/* THIS IS NOT AN X CONSORTIUM STANDARD */
39
40#define NEED_REPLIES
41#include <X11/Xlibint.h>
42#include <X11/extensions/Xext.h>
43#include <X11/extensions/extutil.h>
44#include "xf86dristr.h"
45#include <limits.h>
46
47static XExtensionInfo _xf86dri_info_data;
48static XExtensionInfo *xf86dri_info = &_xf86dri_info_data;
49static char xf86dri_extension_name[] = XF86DRINAME;
50
51#define uniDRICheckExtension(dpy,i,val) \
52  XextCheckExtension (dpy, i, xf86dri_extension_name, val)
53
54/*****************************************************************************
55 *                                                                           *
56 *			   private utility routines                          *
57 *                                                                           *
58 *****************************************************************************/
59
60static int close_display(Display * dpy, XExtCodes * extCodes);
61static /* const */ XExtensionHooks xf86dri_extension_hooks = {
62    NULL,			       /* create_gc */
63    NULL,			       /* copy_gc */
64    NULL,			       /* flush_gc */
65    NULL,			       /* free_gc */
66    NULL,			       /* create_font */
67    NULL,			       /* free_font */
68    close_display,		       /* close_display */
69    NULL,			       /* wire_to_event */
70    NULL,			       /* event_to_wire */
71    NULL,			       /* error */
72    NULL,			       /* error_string */
73};
74
75static
76XEXT_GENERATE_FIND_DISPLAY(find_display, xf86dri_info,
77    xf86dri_extension_name, &xf86dri_extension_hooks, 0, NULL)
78
79    static XEXT_GENERATE_CLOSE_DISPLAY(close_display, xf86dri_info)
80
81/*****************************************************************************
82 *                                                                           *
83 *		    public XFree86-DRI Extension routines                    *
84 *                                                                           *
85 *****************************************************************************/
86#if 0
87#include <stdio.h>
88#define TRACE(msg)  fprintf(stderr,"uniDRI%s\n", msg);
89#else
90#define TRACE(msg)
91#endif
92    Bool uniDRIQueryExtension(dpy, event_basep, error_basep)
93    Display *dpy;
94    int *event_basep, *error_basep;
95{
96    XExtDisplayInfo *info = find_display(dpy);
97
98    TRACE("QueryExtension...");
99    if (XextHasExtension(info)) {
100	*event_basep = info->codes->first_event;
101	*error_basep = info->codes->first_error;
102	TRACE("QueryExtension... return True");
103	return True;
104    } else {
105	TRACE("QueryExtension... return False");
106	return False;
107    }
108}
109
110Bool
111uniDRIQueryVersion(dpy, majorVersion, minorVersion, patchVersion)
112    Display *dpy;
113    int *majorVersion;
114    int *minorVersion;
115    int *patchVersion;
116{
117    XExtDisplayInfo *info = find_display(dpy);
118    xXF86DRIQueryVersionReply rep;
119    xXF86DRIQueryVersionReq *req;
120
121    TRACE("QueryVersion...");
122    uniDRICheckExtension(dpy, info, False);
123
124    LockDisplay(dpy);
125    GetReq(XF86DRIQueryVersion, req);
126    req->reqType = info->codes->major_opcode;
127    req->driReqType = X_XF86DRIQueryVersion;
128    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
129	UnlockDisplay(dpy);
130	SyncHandle();
131	TRACE("QueryVersion... return False");
132	return False;
133    }
134    *majorVersion = rep.majorVersion;
135    *minorVersion = rep.minorVersion;
136    *patchVersion = rep.patchVersion;
137    UnlockDisplay(dpy);
138    SyncHandle();
139    TRACE("QueryVersion... return True");
140    return True;
141}
142
143Bool
144uniDRIQueryDirectRenderingCapable(dpy, screen, isCapable)
145    Display *dpy;
146    int screen;
147    Bool *isCapable;
148{
149    XExtDisplayInfo *info = find_display(dpy);
150    xXF86DRIQueryDirectRenderingCapableReply rep;
151    xXF86DRIQueryDirectRenderingCapableReq *req;
152
153    TRACE("QueryDirectRenderingCapable...");
154    uniDRICheckExtension(dpy, info, False);
155
156    LockDisplay(dpy);
157    GetReq(XF86DRIQueryDirectRenderingCapable, req);
158    req->reqType = info->codes->major_opcode;
159    req->driReqType = X_XF86DRIQueryDirectRenderingCapable;
160    req->screen = screen;
161    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
162	UnlockDisplay(dpy);
163	SyncHandle();
164	TRACE("QueryDirectRenderingCapable... return False");
165	return False;
166    }
167    *isCapable = rep.isCapable;
168    UnlockDisplay(dpy);
169    SyncHandle();
170    TRACE("QueryDirectRenderingCapable... return True");
171    return True;
172}
173
174Bool
175uniDRIOpenConnection(dpy, screen, hSAREA, busIdString)
176    Display *dpy;
177    int screen;
178    drm_handle_t *hSAREA;
179    char **busIdString;
180{
181    XExtDisplayInfo *info = find_display(dpy);
182    xXF86DRIOpenConnectionReply rep;
183    xXF86DRIOpenConnectionReq *req;
184
185    TRACE("OpenConnection...");
186    uniDRICheckExtension(dpy, info, False);
187
188    LockDisplay(dpy);
189    GetReq(XF86DRIOpenConnection, req);
190    req->reqType = info->codes->major_opcode;
191    req->driReqType = X_XF86DRIOpenConnection;
192    req->screen = screen;
193    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
194	UnlockDisplay(dpy);
195	SyncHandle();
196	TRACE("OpenConnection... return False");
197	return False;
198    }
199
200    *hSAREA = rep.hSAREALow;
201#ifdef LONG64
202    if (sizeof(drm_handle_t) == 8) {
203	*hSAREA |= ((unsigned long)rep.hSAREAHigh) << 32;
204    }
205#endif
206    if (rep.length) {
207	if (rep.busIdStringLength < INT_MAX)
208	    *busIdString = Xcalloc(rep.busIdStringLength + 1, 1);
209	else
210	    *busIdString = NULL;
211	if (*busIdString == NULL) {
212	    _XEatData(dpy, ((rep.busIdStringLength + 3) & ~3));
213	    UnlockDisplay(dpy);
214	    SyncHandle();
215	    TRACE("OpenConnection... return False");
216	    return False;
217	}
218	_XReadPad(dpy, *busIdString, rep.busIdStringLength);
219    } else {
220	*busIdString = NULL;
221    }
222    UnlockDisplay(dpy);
223    SyncHandle();
224    TRACE("OpenConnection... return True");
225    return True;
226}
227
228Bool
229uniDRIAuthConnection(dpy, screen, magic)
230    Display *dpy;
231    int screen;
232    drm_magic_t magic;
233{
234    XExtDisplayInfo *info = find_display(dpy);
235    xXF86DRIAuthConnectionReq *req;
236    xXF86DRIAuthConnectionReply rep;
237
238    TRACE("AuthConnection...");
239    uniDRICheckExtension(dpy, info, False);
240
241    LockDisplay(dpy);
242    GetReq(XF86DRIAuthConnection, req);
243    req->reqType = info->codes->major_opcode;
244    req->driReqType = X_XF86DRIAuthConnection;
245    req->screen = screen;
246    req->magic = magic;
247    rep.authenticated = 0;
248    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse) || !rep.authenticated) {
249	UnlockDisplay(dpy);
250	SyncHandle();
251	TRACE("AuthConnection... return False");
252	return False;
253    }
254    UnlockDisplay(dpy);
255    SyncHandle();
256    TRACE("AuthConnection... return True");
257    return True;
258}
259
260Bool
261uniDRICloseConnection(dpy, screen)
262    Display *dpy;
263    int screen;
264{
265    XExtDisplayInfo *info = find_display(dpy);
266    xXF86DRICloseConnectionReq *req;
267
268    TRACE("CloseConnection...");
269
270    uniDRICheckExtension(dpy, info, False);
271
272    LockDisplay(dpy);
273    GetReq(XF86DRICloseConnection, req);
274    req->reqType = info->codes->major_opcode;
275    req->driReqType = X_XF86DRICloseConnection;
276    req->screen = screen;
277    UnlockDisplay(dpy);
278    SyncHandle();
279    TRACE("CloseConnection... return True");
280    return True;
281}
282
283Bool
284uniDRIGetClientDriverName(dpy, screen, ddxDriverMajorVersion,
285    ddxDriverMinorVersion, ddxDriverPatchVersion, clientDriverName)
286    Display *dpy;
287    int screen;
288    int *ddxDriverMajorVersion;
289    int *ddxDriverMinorVersion;
290    int *ddxDriverPatchVersion;
291    char **clientDriverName;
292{
293    XExtDisplayInfo *info = find_display(dpy);
294    xXF86DRIGetClientDriverNameReply rep;
295    xXF86DRIGetClientDriverNameReq *req;
296
297    TRACE("GetClientDriverName...");
298    uniDRICheckExtension(dpy, info, False);
299
300    LockDisplay(dpy);
301    GetReq(XF86DRIGetClientDriverName, req);
302    req->reqType = info->codes->major_opcode;
303    req->driReqType = X_XF86DRIGetClientDriverName;
304    req->screen = screen;
305    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
306	UnlockDisplay(dpy);
307	SyncHandle();
308	TRACE("GetClientDriverName... return False");
309	return False;
310    }
311
312    *ddxDriverMajorVersion = rep.ddxDriverMajorVersion;
313    *ddxDriverMinorVersion = rep.ddxDriverMinorVersion;
314    *ddxDriverPatchVersion = rep.ddxDriverPatchVersion;
315
316    if (rep.length) {
317	if (rep.clientDriverNameLength < INT_MAX)
318	    *clientDriverName = Xcalloc(rep.clientDriverNameLength + 1, 1);
319	else
320	    *clientDriverName = NULL;
321	if (*clientDriverName == NULL) {
322	    _XEatData(dpy, ((rep.clientDriverNameLength + 3) & ~3));
323	    UnlockDisplay(dpy);
324	    SyncHandle();
325	    TRACE("GetClientDriverName... return False");
326	    return False;
327	}
328	_XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength);
329    } else {
330	*clientDriverName = NULL;
331    }
332    UnlockDisplay(dpy);
333    SyncHandle();
334    TRACE("GetClientDriverName... return True");
335    return True;
336}
337
338Bool
339uniDRICreateContextWithConfig(dpy, screen, configID, context, hHWContext)
340    Display *dpy;
341    int screen;
342    int configID;
343    XID *context;
344    drm_context_t *hHWContext;
345{
346    XExtDisplayInfo *info = find_display(dpy);
347    xXF86DRICreateContextReply rep;
348    xXF86DRICreateContextReq *req;
349
350    TRACE("CreateContext...");
351    uniDRICheckExtension(dpy, info, False);
352
353    LockDisplay(dpy);
354    GetReq(XF86DRICreateContext, req);
355    req->reqType = info->codes->major_opcode;
356    req->driReqType = X_XF86DRICreateContext;
357    req->visual = configID;
358    req->screen = screen;
359    *context = XAllocID(dpy);
360    req->context = *context;
361    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
362	UnlockDisplay(dpy);
363	SyncHandle();
364	TRACE("CreateContext... return False");
365	return False;
366    }
367    *hHWContext = rep.hHWContext;
368    UnlockDisplay(dpy);
369    SyncHandle();
370    TRACE("CreateContext... return True");
371    return True;
372}
373
374Bool
375uniDRICreateContext(dpy, screen, visual, context, hHWContext)
376    Display *dpy;
377    int screen;
378    Visual *visual;
379    XID *context;
380    drm_context_t *hHWContext;
381{
382    return uniDRICreateContextWithConfig(dpy, screen, visual->visualid,
383	context, hHWContext);
384}
385
386Bool
387uniDRIDestroyContext(Display * ndpy, int screen, XID context)
388{
389    Display *const dpy = (Display *) ndpy;
390    XExtDisplayInfo *info = find_display(dpy);
391    xXF86DRIDestroyContextReq *req;
392
393    TRACE("DestroyContext...");
394    uniDRICheckExtension(dpy, info, False);
395
396    LockDisplay(dpy);
397    GetReq(XF86DRIDestroyContext, req);
398    req->reqType = info->codes->major_opcode;
399    req->driReqType = X_XF86DRIDestroyContext;
400    req->screen = screen;
401    req->context = context;
402    UnlockDisplay(dpy);
403    SyncHandle();
404    TRACE("DestroyContext... return True");
405    return True;
406}
407
408Bool
409uniDRICreateDrawable(Display * ndpy, int screen,
410    Drawable drawable, drm_drawable_t * hHWDrawable)
411{
412    Display *const dpy = (Display *) ndpy;
413    XExtDisplayInfo *info = find_display(dpy);
414    xXF86DRICreateDrawableReply rep;
415    xXF86DRICreateDrawableReq *req;
416
417    TRACE("CreateDrawable...");
418    uniDRICheckExtension(dpy, info, False);
419
420    LockDisplay(dpy);
421    GetReq(XF86DRICreateDrawable, req);
422    req->reqType = info->codes->major_opcode;
423    req->driReqType = X_XF86DRICreateDrawable;
424    req->screen = screen;
425    req->drawable = drawable;
426    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
427	UnlockDisplay(dpy);
428	SyncHandle();
429	TRACE("CreateDrawable... return False");
430	return False;
431    }
432    *hHWDrawable = rep.hHWDrawable;
433    UnlockDisplay(dpy);
434    SyncHandle();
435    TRACE("CreateDrawable... return True");
436    return True;
437}
438
439Bool
440uniDRIDestroyDrawable(Display * ndpy, int screen, Drawable drawable)
441{
442    Display *const dpy = (Display *) ndpy;
443    XExtDisplayInfo *info = find_display(dpy);
444    xXF86DRIDestroyDrawableReq *req;
445
446    TRACE("DestroyDrawable...");
447    uniDRICheckExtension(dpy, info, False);
448
449    LockDisplay(dpy);
450    GetReq(XF86DRIDestroyDrawable, req);
451    req->reqType = info->codes->major_opcode;
452    req->driReqType = X_XF86DRIDestroyDrawable;
453    req->screen = screen;
454    req->drawable = drawable;
455    UnlockDisplay(dpy);
456    SyncHandle();
457    TRACE("DestroyDrawable... return True");
458    return True;
459}
460
461Bool
462uniDRIGetDrawableInfo(Display * dpy, int screen, Drawable drawable,
463    unsigned int *index, unsigned int *stamp,
464    int *X, int *Y, int *W, int *H,
465    int *numClipRects, drm_clip_rect_t ** pClipRects,
466    int *backX, int *backY,
467    int *numBackClipRects, drm_clip_rect_t ** pBackClipRects)
468{
469    XExtDisplayInfo *info = find_display(dpy);
470    xXF86DRIGetDrawableInfoReply rep;
471    xXF86DRIGetDrawableInfoReq *req;
472    int total_rects;
473
474    TRACE("GetDrawableInfo...");
475    uniDRICheckExtension(dpy, info, False);
476
477    LockDisplay(dpy);
478    GetReq(XF86DRIGetDrawableInfo, req);
479    req->reqType = info->codes->major_opcode;
480    req->driReqType = X_XF86DRIGetDrawableInfo;
481    req->screen = screen;
482    req->drawable = drawable;
483
484    if (!_XReply(dpy, (xReply *) & rep, 1, xFalse)) {
485	UnlockDisplay(dpy);
486	SyncHandle();
487	TRACE("GetDrawableInfo... return False");
488	return False;
489    }
490    *index = rep.drawableTableIndex;
491    *stamp = rep.drawableTableStamp;
492    *X = (int)rep.drawableX;
493    *Y = (int)rep.drawableY;
494    *W = (int)rep.drawableWidth;
495    *H = (int)rep.drawableHeight;
496    *numClipRects = rep.numClipRects;
497    total_rects = *numClipRects;
498
499    *backX = rep.backX;
500    *backY = rep.backY;
501    *numBackClipRects = rep.numBackClipRects;
502    total_rects += *numBackClipRects;
503
504#if 0
505    /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks
506     * backwards compatibility (Because of the >> 2 shift) but the fix
507     * enables multi-threaded apps to work.
508     */
509    if (rep.length != ((((SIZEOF(xXF86DRIGetDrawableInfoReply) -
510			SIZEOF(xGenericReply) +
511			total_rects * sizeof(drm_clip_rect_t)) +
512		    3) & ~3) >> 2)) {
513	_XEatData(dpy, rep.length);
514	UnlockDisplay(dpy);
515	SyncHandle();
516	TRACE("GetDrawableInfo... return False");
517	return False;
518    }
519#endif
520
521    if (*numClipRects) {
522	int len = sizeof(drm_clip_rect_t) * (*numClipRects);
523
524	*pClipRects = (drm_clip_rect_t *) Xcalloc(len, 1);
525	if (*pClipRects)
526	    _XRead(dpy, (char *)*pClipRects, len);
527    } else {
528	*pClipRects = NULL;
529    }
530
531    if (*numBackClipRects) {
532	int len = sizeof(drm_clip_rect_t) * (*numBackClipRects);
533
534	*pBackClipRects = (drm_clip_rect_t *) Xcalloc(len, 1);
535	if (*pBackClipRects)
536	    _XRead(dpy, (char *)*pBackClipRects, len);
537    } else {
538	*pBackClipRects = NULL;
539    }
540
541    UnlockDisplay(dpy);
542    SyncHandle();
543    TRACE("GetDrawableInfo... return True");
544    return True;
545}
546
547Bool
548uniDRIGetDeviceInfo(dpy, screen, hFrameBuffer,
549    fbOrigin, fbSize, fbStride, devPrivateSize, pDevPrivate)
550    Display *dpy;
551    int screen;
552    drm_handle_t *hFrameBuffer;
553    int *fbOrigin;
554    int *fbSize;
555    int *fbStride;
556    int *devPrivateSize;
557    void **pDevPrivate;
558{
559    XExtDisplayInfo *info = find_display(dpy);
560    xXF86DRIGetDeviceInfoReply rep;
561    xXF86DRIGetDeviceInfoReq *req;
562
563    TRACE("GetDeviceInfo...");
564    uniDRICheckExtension(dpy, info, False);
565
566    LockDisplay(dpy);
567    GetReq(XF86DRIGetDeviceInfo, req);
568    req->reqType = info->codes->major_opcode;
569    req->driReqType = X_XF86DRIGetDeviceInfo;
570    req->screen = screen;
571    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
572	UnlockDisplay(dpy);
573	SyncHandle();
574	TRACE("GetDeviceInfo... return False");
575	return False;
576    }
577
578    *hFrameBuffer = rep.hFrameBufferLow;
579#ifdef LONG64
580    if (sizeof(drm_handle_t) == 8) {
581	*hFrameBuffer |= ((unsigned long)rep.hFrameBufferHigh) << 32;
582    }
583#endif
584
585    *fbOrigin = rep.framebufferOrigin;
586    *fbSize = rep.framebufferSize;
587    *fbStride = rep.framebufferStride;
588    *devPrivateSize = rep.devPrivateSize;
589
590    if (rep.length) {
591	if (!(*pDevPrivate = (void *)Xcalloc(rep.devPrivateSize, 1))) {
592	    _XEatData(dpy, ((rep.devPrivateSize + 3) & ~3));
593	    UnlockDisplay(dpy);
594	    SyncHandle();
595	    TRACE("GetDeviceInfo... return False");
596	    return False;
597	}
598	_XRead(dpy, (char *)*pDevPrivate, rep.devPrivateSize);
599    } else {
600	*pDevPrivate = NULL;
601    }
602
603    UnlockDisplay(dpy);
604    SyncHandle();
605    TRACE("GetDeviceInfo... return True");
606    return True;
607}
608