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#ifdef HAVE_CONFIG_H
41#include "config.h"
42#endif
43
44#define NEED_REPLIES
45#include <X11/Xlibint.h>
46#include <X11/extensions/Xext.h>
47#include <X11/extensions/extutil.h>
48#include <stdint.h>
49#include "xf86dristr.h"
50
51static XExtensionInfo _xf86dri_info_data;
52static XExtensionInfo *xf86dri_info = &_xf86dri_info_data;
53static char xf86dri_extension_name[] = XF86DRINAME;
54
55#define uniDRICheckExtension(dpy,i,val) \
56  XextCheckExtension (dpy, i, xf86dri_extension_name, val)
57
58/*****************************************************************************
59 *                                                                           *
60 *			   private utility routines                          *
61 *                                                                           *
62 *****************************************************************************/
63
64static int close_display(Display * dpy, XExtCodes * extCodes);
65static /* const */ XExtensionHooks xf86dri_extension_hooks = {
66    NULL,			       /* create_gc */
67    NULL,			       /* copy_gc */
68    NULL,			       /* flush_gc */
69    NULL,			       /* free_gc */
70    NULL,			       /* create_font */
71    NULL,			       /* free_font */
72    close_display,		       /* close_display */
73    NULL,			       /* wire_to_event */
74    NULL,			       /* event_to_wire */
75    NULL,			       /* error */
76    NULL,			       /* error_string */
77};
78
79static
80XEXT_GENERATE_FIND_DISPLAY(find_display, xf86dri_info,
81    xf86dri_extension_name, &xf86dri_extension_hooks, 0, NULL)
82
83    static XEXT_GENERATE_CLOSE_DISPLAY(close_display, xf86dri_info)
84
85/*****************************************************************************
86 *                                                                           *
87 *		    public XFree86-DRI Extension routines                    *
88 *                                                                           *
89 *****************************************************************************/
90#if 0
91#include <stdio.h>
92#define TRACE(msg)  fprintf(stderr,"uniDRI%s\n", msg);
93#else
94#define TRACE(msg)
95#endif
96    Bool uniDRIQueryExtension(dpy, event_basep, error_basep)
97    Display *dpy;
98    int *event_basep, *error_basep;
99{
100    XExtDisplayInfo *info = find_display(dpy);
101
102    TRACE("QueryExtension...");
103    if (XextHasExtension(info)) {
104	*event_basep = info->codes->first_event;
105	*error_basep = info->codes->first_error;
106	TRACE("QueryExtension... return True");
107	return True;
108    } else {
109	TRACE("QueryExtension... return False");
110	return False;
111    }
112}
113
114Bool
115uniDRIQueryVersion(dpy, majorVersion, minorVersion, patchVersion)
116    Display *dpy;
117    int *majorVersion;
118    int *minorVersion;
119    int *patchVersion;
120{
121    XExtDisplayInfo *info = find_display(dpy);
122    xXF86DRIQueryVersionReply rep;
123    xXF86DRIQueryVersionReq *req;
124
125    TRACE("QueryVersion...");
126    uniDRICheckExtension(dpy, info, False);
127
128    LockDisplay(dpy);
129    GetReq(XF86DRIQueryVersion, req);
130    req->reqType = info->codes->major_opcode;
131    req->driReqType = X_XF86DRIQueryVersion;
132    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
133	UnlockDisplay(dpy);
134	SyncHandle();
135	TRACE("QueryVersion... return False");
136	return False;
137    }
138    *majorVersion = rep.majorVersion;
139    *minorVersion = rep.minorVersion;
140    *patchVersion = rep.patchVersion;
141    UnlockDisplay(dpy);
142    SyncHandle();
143    TRACE("QueryVersion... return True");
144    return True;
145}
146
147Bool
148uniDRIQueryDirectRenderingCapable(dpy, screen, isCapable)
149    Display *dpy;
150    int screen;
151    Bool *isCapable;
152{
153    XExtDisplayInfo *info = find_display(dpy);
154    xXF86DRIQueryDirectRenderingCapableReply rep;
155    xXF86DRIQueryDirectRenderingCapableReq *req;
156
157    TRACE("QueryDirectRenderingCapable...");
158    uniDRICheckExtension(dpy, info, False);
159
160    LockDisplay(dpy);
161    GetReq(XF86DRIQueryDirectRenderingCapable, req);
162    req->reqType = info->codes->major_opcode;
163    req->driReqType = X_XF86DRIQueryDirectRenderingCapable;
164    req->screen = screen;
165    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
166	UnlockDisplay(dpy);
167	SyncHandle();
168	TRACE("QueryDirectRenderingCapable... return False");
169	return False;
170    }
171    *isCapable = rep.isCapable;
172    UnlockDisplay(dpy);
173    SyncHandle();
174    TRACE("QueryDirectRenderingCapable... return True");
175    return True;
176}
177
178Bool
179uniDRIOpenConnection(dpy, screen, hSAREA, busIdString)
180    Display *dpy;
181    int screen;
182    drm_handle_t *hSAREA;
183    char **busIdString;
184{
185    XExtDisplayInfo *info = find_display(dpy);
186    xXF86DRIOpenConnectionReply rep;
187    xXF86DRIOpenConnectionReq *req;
188
189    TRACE("OpenConnection...");
190    uniDRICheckExtension(dpy, info, False);
191
192    LockDisplay(dpy);
193    GetReq(XF86DRIOpenConnection, req);
194    req->reqType = info->codes->major_opcode;
195    req->driReqType = X_XF86DRIOpenConnection;
196    req->screen = screen;
197    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
198	UnlockDisplay(dpy);
199	SyncHandle();
200	TRACE("OpenConnection... return False");
201	return False;
202    }
203
204    *hSAREA = rep.hSAREALow;
205#ifdef LONG64
206    if (sizeof(drm_handle_t) == 8) {
207	*hSAREA |= ((unsigned long)rep.hSAREAHigh) << 32;
208    }
209#endif
210    if (rep.length) {
211	if (!(*busIdString = (char *)Xcalloc(rep.busIdStringLength + 1, 1))) {
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 (!(*clientDriverName =
318		(char *)Xcalloc(rep.clientDriverNameLength + 1, 1))) {
319	    _XEatData(dpy, ((rep.clientDriverNameLength + 3) & ~3));
320	    UnlockDisplay(dpy);
321	    SyncHandle();
322	    TRACE("GetClientDriverName... return False");
323	    return False;
324	}
325	_XReadPad(dpy, *clientDriverName, rep.clientDriverNameLength);
326    } else {
327	*clientDriverName = NULL;
328    }
329    UnlockDisplay(dpy);
330    SyncHandle();
331    TRACE("GetClientDriverName... return True");
332    return True;
333}
334
335Bool
336uniDRICreateContextWithConfig(dpy, screen, configID, context, hHWContext)
337    Display *dpy;
338    int screen;
339    int configID;
340    XID *context;
341    drm_context_t *hHWContext;
342{
343    XExtDisplayInfo *info = find_display(dpy);
344    xXF86DRICreateContextReply rep;
345    xXF86DRICreateContextReq *req;
346
347    TRACE("CreateContext...");
348    uniDRICheckExtension(dpy, info, False);
349
350    LockDisplay(dpy);
351    GetReq(XF86DRICreateContext, req);
352    req->reqType = info->codes->major_opcode;
353    req->driReqType = X_XF86DRICreateContext;
354    req->visual = configID;
355    req->screen = screen;
356    *context = XAllocID(dpy);
357    req->context = *context;
358    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
359	UnlockDisplay(dpy);
360	SyncHandle();
361	TRACE("CreateContext... return False");
362	return False;
363    }
364    *hHWContext = rep.hHWContext;
365    UnlockDisplay(dpy);
366    SyncHandle();
367    TRACE("CreateContext... return True");
368    return True;
369}
370
371Bool
372uniDRICreateContext(dpy, screen, visual, context, hHWContext)
373    Display *dpy;
374    int screen;
375    Visual *visual;
376    XID *context;
377    drm_context_t *hHWContext;
378{
379    return uniDRICreateContextWithConfig(dpy, screen, visual->visualid,
380	context, hHWContext);
381}
382
383Bool
384uniDRIDestroyContext(Display * ndpy, int screen, XID context)
385{
386    Display *const dpy = (Display *) ndpy;
387    XExtDisplayInfo *info = find_display(dpy);
388    xXF86DRIDestroyContextReq *req;
389
390    TRACE("DestroyContext...");
391    uniDRICheckExtension(dpy, info, False);
392
393    LockDisplay(dpy);
394    GetReq(XF86DRIDestroyContext, req);
395    req->reqType = info->codes->major_opcode;
396    req->driReqType = X_XF86DRIDestroyContext;
397    req->screen = screen;
398    req->context = context;
399    UnlockDisplay(dpy);
400    SyncHandle();
401    TRACE("DestroyContext... return True");
402    return True;
403}
404
405Bool
406uniDRICreateDrawable(Display * ndpy, int screen,
407    Drawable drawable, drm_drawable_t * hHWDrawable)
408{
409    Display *const dpy = (Display *) ndpy;
410    XExtDisplayInfo *info = find_display(dpy);
411    xXF86DRICreateDrawableReply rep;
412    xXF86DRICreateDrawableReq *req;
413
414    TRACE("CreateDrawable...");
415    uniDRICheckExtension(dpy, info, False);
416
417    LockDisplay(dpy);
418    GetReq(XF86DRICreateDrawable, req);
419    req->reqType = info->codes->major_opcode;
420    req->driReqType = X_XF86DRICreateDrawable;
421    req->screen = screen;
422    req->drawable = drawable;
423    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
424	UnlockDisplay(dpy);
425	SyncHandle();
426	TRACE("CreateDrawable... return False");
427	return False;
428    }
429    *hHWDrawable = rep.hHWDrawable;
430    UnlockDisplay(dpy);
431    SyncHandle();
432    TRACE("CreateDrawable... return True");
433    return True;
434}
435
436Bool
437uniDRIDestroyDrawable(Display * ndpy, int screen, Drawable drawable)
438{
439    Display *const dpy = (Display *) ndpy;
440    XExtDisplayInfo *info = find_display(dpy);
441    xXF86DRIDestroyDrawableReq *req;
442
443    TRACE("DestroyDrawable...");
444    uniDRICheckExtension(dpy, info, False);
445
446    LockDisplay(dpy);
447    GetReq(XF86DRIDestroyDrawable, req);
448    req->reqType = info->codes->major_opcode;
449    req->driReqType = X_XF86DRIDestroyDrawable;
450    req->screen = screen;
451    req->drawable = drawable;
452    UnlockDisplay(dpy);
453    SyncHandle();
454    TRACE("DestroyDrawable... return True");
455    return True;
456}
457
458Bool
459uniDRIGetDrawableInfo(Display * dpy, int screen, Drawable drawable,
460    unsigned int *index, unsigned int *stamp,
461    int *X, int *Y, int *W, int *H,
462    int *numClipRects, drm_clip_rect_t ** pClipRects,
463    int *backX, int *backY,
464    int *numBackClipRects, drm_clip_rect_t ** pBackClipRects)
465{
466    XExtDisplayInfo *info = find_display(dpy);
467    xXF86DRIGetDrawableInfoReply rep;
468    xXF86DRIGetDrawableInfoReq *req;
469    int total_rects;
470
471    TRACE("GetDrawableInfo...");
472    uniDRICheckExtension(dpy, info, False);
473
474    LockDisplay(dpy);
475    GetReq(XF86DRIGetDrawableInfo, req);
476    req->reqType = info->codes->major_opcode;
477    req->driReqType = X_XF86DRIGetDrawableInfo;
478    req->screen = screen;
479    req->drawable = drawable;
480
481    if (!_XReply(dpy, (xReply *) & rep, 1, xFalse)) {
482	UnlockDisplay(dpy);
483	SyncHandle();
484	TRACE("GetDrawableInfo... return False");
485	return False;
486    }
487    *index = rep.drawableTableIndex;
488    *stamp = rep.drawableTableStamp;
489    *X = (int)rep.drawableX;
490    *Y = (int)rep.drawableY;
491    *W = (int)rep.drawableWidth;
492    *H = (int)rep.drawableHeight;
493    *numClipRects = rep.numClipRects;
494    total_rects = *numClipRects;
495
496    *backX = rep.backX;
497    *backY = rep.backY;
498    *numBackClipRects = rep.numBackClipRects;
499    total_rects += *numBackClipRects;
500
501#if 0
502    /* Because of the fix in Xserver/GL/dri/xf86dri.c, this check breaks
503     * backwards compatibility (Because of the >> 2 shift) but the fix
504     * enables multi-threaded apps to work.
505     */
506    if (rep.length != ((((SIZEOF(xXF86DRIGetDrawableInfoReply) -
507			SIZEOF(xGenericReply) +
508			total_rects * sizeof(drm_clip_rect_t)) +
509		    3) & ~3) >> 2)) {
510	_XEatData(dpy, rep.length);
511	UnlockDisplay(dpy);
512	SyncHandle();
513	TRACE("GetDrawableInfo... return False");
514	return False;
515    }
516#endif
517
518    if (*numClipRects) {
519	int len = sizeof(drm_clip_rect_t) * (*numClipRects);
520
521	*pClipRects = (drm_clip_rect_t *) Xcalloc(len, 1);
522	if (*pClipRects)
523	    _XRead(dpy, (char *)*pClipRects, len);
524    } else {
525	*pClipRects = NULL;
526    }
527
528    if (*numBackClipRects) {
529	int len = sizeof(drm_clip_rect_t) * (*numBackClipRects);
530
531	*pBackClipRects = (drm_clip_rect_t *) Xcalloc(len, 1);
532	if (*pBackClipRects)
533	    _XRead(dpy, (char *)*pBackClipRects, len);
534    } else {
535	*pBackClipRects = NULL;
536    }
537
538    UnlockDisplay(dpy);
539    SyncHandle();
540    TRACE("GetDrawableInfo... return True");
541    return True;
542}
543
544Bool
545uniDRIGetDeviceInfo(dpy, screen, hFrameBuffer,
546    fbOrigin, fbSize, fbStride, devPrivateSize, pDevPrivate)
547    Display *dpy;
548    int screen;
549    drm_handle_t *hFrameBuffer;
550    int *fbOrigin;
551    int *fbSize;
552    int *fbStride;
553    int *devPrivateSize;
554    void **pDevPrivate;
555{
556    XExtDisplayInfo *info = find_display(dpy);
557    xXF86DRIGetDeviceInfoReply rep;
558    xXF86DRIGetDeviceInfoReq *req;
559
560    TRACE("GetDeviceInfo...");
561    uniDRICheckExtension(dpy, info, False);
562
563    LockDisplay(dpy);
564    GetReq(XF86DRIGetDeviceInfo, req);
565    req->reqType = info->codes->major_opcode;
566    req->driReqType = X_XF86DRIGetDeviceInfo;
567    req->screen = screen;
568    if (!_XReply(dpy, (xReply *) & rep, 0, xFalse)) {
569	UnlockDisplay(dpy);
570	SyncHandle();
571	TRACE("GetDeviceInfo... return False");
572	return False;
573    }
574
575    *hFrameBuffer = rep.hFrameBufferLow;
576#ifdef LONG64
577    if (sizeof(drm_handle_t) == 8) {
578	*hFrameBuffer |= ((unsigned long)rep.hFrameBufferHigh) << 32;
579    }
580#endif
581
582    *fbOrigin = rep.framebufferOrigin;
583    *fbSize = rep.framebufferSize;
584    *fbStride = rep.framebufferStride;
585    *devPrivateSize = rep.devPrivateSize;
586
587    if (rep.length) {
588	if (!(*pDevPrivate = (void *)Xcalloc(rep.devPrivateSize, 1))) {
589	    _XEatData(dpy, ((rep.devPrivateSize + 3) & ~3));
590	    UnlockDisplay(dpy);
591	    SyncHandle();
592	    TRACE("GetDeviceInfo... return False");
593	    return False;
594	}
595	_XRead(dpy, (char *)*pDevPrivate, rep.devPrivateSize);
596    } else {
597	*pDevPrivate = NULL;
598    }
599
600    UnlockDisplay(dpy);
601    SyncHandle();
602    TRACE("GetDeviceInfo... return True");
603    return True;
604}
605