xf86dri.c revision 4642e01f
1/**************************************************************************
2
3Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4Copyright 2000 VA Linux Systems, Inc.
5All Rights Reserved.
6
7Permission is hereby granted, free of charge, to any person obtaining a
8copy of this software and associated documentation files (the
9"Software"), to deal in the Software without restriction, including
10without limitation the rights to use, copy, modify, merge, publish,
11distribute, sub license, and/or sell copies of the Software, and to
12permit persons to whom the Software is furnished to do so, subject to
13the following conditions:
14
15The above copyright notice and this permission notice (including the
16next paragraph) shall be included in all copies or substantial portions
17of the Software.
18
19THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
27**************************************************************************/
28
29/*
30 * Authors:
31 *   Kevin E. Martin <martin@valinux.com>
32 *   Jens Owen <jens@tungstengraphics.com>
33 *   Rickard E. (Rik) Faith <faith@valinux.com>
34 *
35 */
36
37#ifdef HAVE_XORG_CONFIG_H
38#include <xorg-config.h>
39#endif
40
41#include <string.h>
42
43#include "xf86.h"
44
45#define NEED_REPLIES
46#define NEED_EVENTS
47#include <X11/X.h>
48#include <X11/Xproto.h>
49#include "misc.h"
50#include "dixstruct.h"
51#include "extnsionst.h"
52#include "colormapst.h"
53#include "cursorstr.h"
54#include "scrnintstr.h"
55#include "servermd.h"
56#define _XF86DRI_SERVER_
57#include "xf86dristr.h"
58#include "swaprep.h"
59#include "xf86str.h"
60#include "dri.h"
61#include "sarea.h"
62#include "dristruct.h"
63#include "xf86.h"
64#include "xf86drm.h"
65
66static int DRIErrorBase;
67
68static DISPATCH_PROC(ProcXF86DRIQueryVersion);
69static DISPATCH_PROC(ProcXF86DRIQueryDirectRenderingCapable);
70static DISPATCH_PROC(ProcXF86DRIOpenConnection);
71static DISPATCH_PROC(ProcXF86DRICloseConnection);
72static DISPATCH_PROC(ProcXF86DRIGetClientDriverName);
73static DISPATCH_PROC(ProcXF86DRICreateContext);
74static DISPATCH_PROC(ProcXF86DRIDestroyContext);
75static DISPATCH_PROC(ProcXF86DRICreateDrawable);
76static DISPATCH_PROC(ProcXF86DRIDestroyDrawable);
77static DISPATCH_PROC(ProcXF86DRIGetDrawableInfo);
78static DISPATCH_PROC(ProcXF86DRIGetDeviceInfo);
79static DISPATCH_PROC(ProcXF86DRIDispatch);
80static DISPATCH_PROC(ProcXF86DRIAuthConnection);
81
82static DISPATCH_PROC(SProcXF86DRIQueryVersion);
83static DISPATCH_PROC(SProcXF86DRIQueryDirectRenderingCapable);
84static DISPATCH_PROC(SProcXF86DRIDispatch);
85
86static void XF86DRIResetProc(ExtensionEntry* extEntry);
87
88static unsigned char DRIReqCode = 0;
89
90extern void XFree86DRIExtensionInit(void);
91
92void
93XFree86DRIExtensionInit(void)
94{
95    ExtensionEntry* extEntry;
96
97#ifdef XF86DRI_EVENTS
98    EventType = CreateNewResourceType(XF86DRIFreeEvents);
99#endif
100
101    if (
102	DRIExtensionInit() &&
103#ifdef XF86DRI_EVENTS
104        EventType && ScreenPrivateIndex != -1 &&
105#endif
106	(extEntry = AddExtension(XF86DRINAME,
107				 XF86DRINumberEvents,
108				 XF86DRINumberErrors,
109				 ProcXF86DRIDispatch,
110				 SProcXF86DRIDispatch,
111				 XF86DRIResetProc,
112				 StandardMinorOpcode))) {
113	DRIReqCode = (unsigned char)extEntry->base;
114	DRIErrorBase = extEntry->errorBase;
115    }
116}
117
118/*ARGSUSED*/
119static void
120XF86DRIResetProc (
121    ExtensionEntry* extEntry
122)
123{
124    DRIReset();
125}
126
127static int
128ProcXF86DRIQueryVersion(
129    register ClientPtr client
130)
131{
132    xXF86DRIQueryVersionReply rep;
133    register int n;
134
135    REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq);
136    rep.type = X_Reply;
137    rep.length = 0;
138    rep.sequenceNumber = client->sequence;
139    rep.majorVersion = XF86DRI_MAJOR_VERSION;
140    rep.minorVersion = XF86DRI_MINOR_VERSION;
141    rep.patchVersion = XF86DRI_PATCH_VERSION;
142    if (client->swapped) {
143    	swaps(&rep.sequenceNumber, n);
144    	swapl(&rep.length, n);
145	swaps(&rep.majorVersion, n);
146	swaps(&rep.minorVersion, n);
147	swapl(&rep.patchVersion, n);
148    }
149    WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep);
150    return (client->noClientException);
151}
152
153static int
154ProcXF86DRIQueryDirectRenderingCapable(
155    register ClientPtr client
156)
157{
158    xXF86DRIQueryDirectRenderingCapableReply	rep;
159    Bool isCapable;
160    register int n;
161
162    REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
163    REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq);
164    if (stuff->screen >= screenInfo.numScreens) {
165	client->errorValue = stuff->screen;
166	return BadValue;
167    }
168
169    rep.type = X_Reply;
170    rep.length = 0;
171    rep.sequenceNumber = client->sequence;
172
173    if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen],
174					 &isCapable)) {
175	return BadValue;
176    }
177    rep.isCapable = isCapable;
178
179    if (!LocalClient(client) || client->swapped)
180	rep.isCapable = 0;
181
182    if (client->swapped) {
183    	swaps(&rep.sequenceNumber, n);
184    	swapl(&rep.length, n);
185    }
186
187    WriteToClient(client,
188	sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep);
189    return (client->noClientException);
190}
191
192static int
193ProcXF86DRIOpenConnection(
194    register ClientPtr client
195)
196{
197    xXF86DRIOpenConnectionReply rep;
198    drm_handle_t			hSAREA;
199    char*			busIdString;
200
201    REQUEST(xXF86DRIOpenConnectionReq);
202    REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq);
203    if (stuff->screen >= screenInfo.numScreens) {
204	client->errorValue = stuff->screen;
205	return BadValue;
206    }
207
208    if (!DRIOpenConnection( screenInfo.screens[stuff->screen],
209			    &hSAREA,
210			    &busIdString)) {
211	return BadValue;
212    }
213
214    rep.type = X_Reply;
215    rep.sequenceNumber = client->sequence;
216    rep.busIdStringLength = 0;
217    if (busIdString)
218	rep.busIdStringLength = strlen(busIdString);
219    rep.length = (SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) +
220                  ((rep.busIdStringLength + 3) & ~3)) >> 2;
221
222    rep.hSAREALow  = (CARD32)(hSAREA & 0xffffffff);
223#if defined(LONG64) && !defined(__linux__)
224    rep.hSAREAHigh = (CARD32)(hSAREA >> 32);
225#else
226    rep.hSAREAHigh = 0;
227#endif
228
229    WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep);
230    if (rep.busIdStringLength)
231	WriteToClient(client, rep.busIdStringLength, busIdString);
232    return (client->noClientException);
233}
234
235static int
236ProcXF86DRIAuthConnection(
237    register ClientPtr client
238)
239{
240    xXF86DRIAuthConnectionReply rep;
241
242    REQUEST(xXF86DRIAuthConnectionReq);
243    REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq);
244    if (stuff->screen >= screenInfo.numScreens) {
245	client->errorValue = stuff->screen;
246	return BadValue;
247    }
248
249    rep.type = X_Reply;
250    rep.length = 0;
251    rep.sequenceNumber = client->sequence;
252    rep.authenticated = 1;
253
254    if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) {
255        ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic);
256	rep.authenticated = 0;
257    }
258    WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep);
259    return (client->noClientException);
260}
261
262static int
263ProcXF86DRICloseConnection(
264    register ClientPtr client
265)
266{
267    REQUEST(xXF86DRICloseConnectionReq);
268    REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq);
269    if (stuff->screen >= screenInfo.numScreens) {
270	client->errorValue = stuff->screen;
271	return BadValue;
272    }
273
274    DRICloseConnection( screenInfo.screens[stuff->screen]);
275
276    return (client->noClientException);
277}
278
279static int
280ProcXF86DRIGetClientDriverName(
281    register ClientPtr client
282)
283{
284    xXF86DRIGetClientDriverNameReply	rep;
285    char* clientDriverName;
286
287    REQUEST(xXF86DRIGetClientDriverNameReq);
288    REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq);
289    if (stuff->screen >= screenInfo.numScreens) {
290	client->errorValue = stuff->screen;
291	return BadValue;
292    }
293
294    DRIGetClientDriverName( screenInfo.screens[stuff->screen],
295			    (int *)&rep.ddxDriverMajorVersion,
296			    (int *)&rep.ddxDriverMinorVersion,
297			    (int *)&rep.ddxDriverPatchVersion,
298			    &clientDriverName);
299
300    rep.type = X_Reply;
301    rep.sequenceNumber = client->sequence;
302    rep.clientDriverNameLength = 0;
303    if (clientDriverName)
304	rep.clientDriverNameLength = strlen(clientDriverName);
305    rep.length = (SIZEOF(xXF86DRIGetClientDriverNameReply) -
306			SIZEOF(xGenericReply) +
307			((rep.clientDriverNameLength + 3) & ~3)) >> 2;
308
309    WriteToClient(client,
310	sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep);
311    if (rep.clientDriverNameLength)
312	WriteToClient(client,
313                      rep.clientDriverNameLength,
314                      clientDriverName);
315    return (client->noClientException);
316}
317
318static int
319ProcXF86DRICreateContext(
320    register ClientPtr client
321)
322{
323    xXF86DRICreateContextReply	rep;
324    ScreenPtr pScreen;
325
326    REQUEST(xXF86DRICreateContextReq);
327    REQUEST_SIZE_MATCH(xXF86DRICreateContextReq);
328    if (stuff->screen >= screenInfo.numScreens) {
329	client->errorValue = stuff->screen;
330	return BadValue;
331    }
332
333    rep.type = X_Reply;
334    rep.length = 0;
335    rep.sequenceNumber = client->sequence;
336
337    pScreen = screenInfo.screens[stuff->screen];
338
339    if (!DRICreateContext( pScreen,
340			   NULL,
341			   stuff->context,
342			   (drm_context_t *)&rep.hHWContext)) {
343	return BadValue;
344    }
345
346    WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep);
347    return (client->noClientException);
348}
349
350static int
351ProcXF86DRIDestroyContext(
352    register ClientPtr client
353)
354{
355    REQUEST(xXF86DRIDestroyContextReq);
356    REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq);
357    if (stuff->screen >= screenInfo.numScreens) {
358	client->errorValue = stuff->screen;
359	return BadValue;
360    }
361
362    if (!DRIDestroyContext( screenInfo.screens[stuff->screen],
363			    stuff->context)) {
364	return BadValue;
365    }
366
367    return (client->noClientException);
368}
369
370static int
371ProcXF86DRICreateDrawable(
372    ClientPtr client
373)
374{
375    xXF86DRICreateDrawableReply	rep;
376    DrawablePtr pDrawable;
377    int rc;
378
379    REQUEST(xXF86DRICreateDrawableReq);
380    REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq);
381    if (stuff->screen >= screenInfo.numScreens) {
382	client->errorValue = stuff->screen;
383	return BadValue;
384    }
385
386    rep.type = X_Reply;
387    rep.length = 0;
388    rep.sequenceNumber = client->sequence;
389
390    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
391			   DixReadAccess);
392    if (rc != Success)
393	return rc;
394
395    if (!DRICreateDrawable(screenInfo.screens[stuff->screen], client,
396			   pDrawable, (drm_drawable_t *)&rep.hHWDrawable)) {
397	return BadValue;
398    }
399
400    WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep);
401    return (client->noClientException);
402}
403
404static int
405ProcXF86DRIDestroyDrawable(
406    register ClientPtr client
407)
408{
409    REQUEST(xXF86DRIDestroyDrawableReq);
410    DrawablePtr pDrawable;
411    REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq);
412    int rc;
413
414    if (stuff->screen >= screenInfo.numScreens) {
415	client->errorValue = stuff->screen;
416	return BadValue;
417    }
418
419    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
420			   DixReadAccess);
421    if (rc != Success)
422	return rc;
423
424    if (!DRIDestroyDrawable(screenInfo.screens[stuff->screen], client,
425			    pDrawable)) {
426	return BadValue;
427    }
428
429    return (client->noClientException);
430}
431
432static int
433ProcXF86DRIGetDrawableInfo(
434    register ClientPtr client
435)
436{
437    xXF86DRIGetDrawableInfoReply	rep;
438    DrawablePtr pDrawable;
439    int X, Y, W, H;
440    drm_clip_rect_t * pClipRects, *pClippedRects;
441    drm_clip_rect_t * pBackClipRects;
442    int backX, backY, rc;
443
444    REQUEST(xXF86DRIGetDrawableInfoReq);
445    REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq);
446    if (stuff->screen >= screenInfo.numScreens) {
447	client->errorValue = stuff->screen;
448	return BadValue;
449    }
450
451    rep.type = X_Reply;
452    rep.length = 0;
453    rep.sequenceNumber = client->sequence;
454
455    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
456			   DixReadAccess);
457    if (rc != Success)
458	return rc;
459
460    if (!DRIGetDrawableInfo( screenInfo.screens[stuff->screen],
461			     pDrawable,
462			     (unsigned int*)&rep.drawableTableIndex,
463			     (unsigned int*)&rep.drawableTableStamp,
464			     (int*)&X,
465			     (int*)&Y,
466			     (int*)&W,
467			     (int*)&H,
468			     (int*)&rep.numClipRects,
469			     &pClipRects,
470			     &backX,
471			     &backY,
472			     (int*)&rep.numBackClipRects,
473			     &pBackClipRects)) {
474	return BadValue;
475    }
476
477    rep.drawableX = X;
478    rep.drawableY = Y;
479    rep.drawableWidth = W;
480    rep.drawableHeight = H;
481    rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) -
482		  SIZEOF(xGenericReply));
483
484    rep.backX = backX;
485    rep.backY = backY;
486
487    if (rep.numBackClipRects)
488       rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects;
489
490    pClippedRects = pClipRects;
491
492    if (rep.numClipRects) {
493       /* Clip cliprects to screen dimensions (redirected windows) */
494       pClippedRects = xalloc(rep.numClipRects * sizeof(drm_clip_rect_t));
495
496       if (pClippedRects) {
497	    ScreenPtr pScreen = screenInfo.screens[stuff->screen];
498	    int i, j;
499
500	    for (i = 0, j = 0; i < rep.numClipRects; i++) {
501		pClippedRects[j].x1 = max(pClipRects[i].x1, 0);
502		pClippedRects[j].y1 = max(pClipRects[i].y1, 0);
503		pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width);
504		pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height);
505
506		if (pClippedRects[j].x1 < pClippedRects[j].x2 &&
507		    pClippedRects[j].y1 < pClippedRects[j].y2) {
508		    j++;
509		}
510	    }
511
512	    rep.numClipRects = j;
513       } else {
514	    rep.numClipRects = 0;
515       }
516
517       rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects;
518    }
519
520    rep.length = ((rep.length + 3) & ~3) >> 2;
521
522    WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep);
523
524    if (rep.numClipRects) {
525	WriteToClient(client,
526		      sizeof(drm_clip_rect_t) * rep.numClipRects,
527		      (char *)pClippedRects);
528	xfree(pClippedRects);
529    }
530
531    if (rep.numBackClipRects) {
532       WriteToClient(client,
533		     sizeof(drm_clip_rect_t) * rep.numBackClipRects,
534		     (char *)pBackClipRects);
535    }
536
537    return (client->noClientException);
538}
539
540static int
541ProcXF86DRIGetDeviceInfo(
542    register ClientPtr client
543)
544{
545    xXF86DRIGetDeviceInfoReply	rep;
546    drm_handle_t hFrameBuffer;
547    void *pDevPrivate;
548
549    REQUEST(xXF86DRIGetDeviceInfoReq);
550    REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq);
551    if (stuff->screen >= screenInfo.numScreens) {
552	client->errorValue = stuff->screen;
553	return BadValue;
554    }
555
556    rep.type = X_Reply;
557    rep.length = 0;
558    rep.sequenceNumber = client->sequence;
559
560    if (!DRIGetDeviceInfo( screenInfo.screens[stuff->screen],
561			   &hFrameBuffer,
562			   (int*)&rep.framebufferOrigin,
563			   (int*)&rep.framebufferSize,
564			   (int*)&rep.framebufferStride,
565			   (int*)&rep.devPrivateSize,
566			   &pDevPrivate)) {
567	return BadValue;
568    }
569
570    rep.hFrameBufferLow  = (CARD32)(hFrameBuffer & 0xffffffff);
571#if defined(LONG64) && !defined(__linux__)
572    rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32);
573#else
574    rep.hFrameBufferHigh = 0;
575#endif
576
577    rep.length = 0;
578    if (rep.devPrivateSize) {
579	rep.length = (SIZEOF(xXF86DRIGetDeviceInfoReply) -
580		      SIZEOF(xGenericReply) +
581		      ((rep.devPrivateSize + 3) & ~3)) >> 2;
582    }
583
584    WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep);
585    if (rep.length) {
586	WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate);
587    }
588    return (client->noClientException);
589}
590
591static int
592ProcXF86DRIDispatch (
593    register ClientPtr	client
594)
595{
596    REQUEST(xReq);
597
598    switch (stuff->data)
599    {
600    case X_XF86DRIQueryVersion:
601	return ProcXF86DRIQueryVersion(client);
602    case X_XF86DRIQueryDirectRenderingCapable:
603	return ProcXF86DRIQueryDirectRenderingCapable(client);
604    }
605
606    if (!LocalClient(client))
607	return DRIErrorBase + XF86DRIClientNotLocal;
608
609    switch (stuff->data)
610    {
611    case X_XF86DRIOpenConnection:
612	return ProcXF86DRIOpenConnection(client);
613    case X_XF86DRICloseConnection:
614	return ProcXF86DRICloseConnection(client);
615    case X_XF86DRIGetClientDriverName:
616	return ProcXF86DRIGetClientDriverName(client);
617    case X_XF86DRICreateContext:
618	return ProcXF86DRICreateContext(client);
619    case X_XF86DRIDestroyContext:
620	return ProcXF86DRIDestroyContext(client);
621    case X_XF86DRICreateDrawable:
622	return ProcXF86DRICreateDrawable(client);
623    case X_XF86DRIDestroyDrawable:
624	return ProcXF86DRIDestroyDrawable(client);
625    case X_XF86DRIGetDrawableInfo:
626	return ProcXF86DRIGetDrawableInfo(client);
627    case X_XF86DRIGetDeviceInfo:
628	return ProcXF86DRIGetDeviceInfo(client);
629    case X_XF86DRIAuthConnection:
630	return ProcXF86DRIAuthConnection(client);
631    /* {Open,Close}FullScreen are deprecated now */
632    default:
633	return BadRequest;
634    }
635}
636
637static int
638SProcXF86DRIQueryVersion(
639    register ClientPtr	client
640)
641{
642    register int n;
643    REQUEST(xXF86DRIQueryVersionReq);
644    swaps(&stuff->length, n);
645    return ProcXF86DRIQueryVersion(client);
646}
647
648static int
649SProcXF86DRIQueryDirectRenderingCapable(
650    register ClientPtr client
651)
652{
653    register int n;
654    REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
655    swaps(&stuff->length, n);
656    swapl(&stuff->screen, n);
657    return ProcXF86DRIQueryDirectRenderingCapable(client);
658}
659
660static int
661SProcXF86DRIDispatch (
662    register ClientPtr	client
663)
664{
665    REQUEST(xReq);
666
667    /*
668     * Only local clients are allowed DRI access, but remote clients still need
669     * these requests to find out cleanly.
670     */
671    switch (stuff->data)
672    {
673    case X_XF86DRIQueryVersion:
674	return SProcXF86DRIQueryVersion(client);
675    case X_XF86DRIQueryDirectRenderingCapable:
676	return SProcXF86DRIQueryDirectRenderingCapable(client);
677    default:
678	return DRIErrorBase + XF86DRIClientNotLocal;
679    }
680}
681