xf86dri.c revision 05b261ec
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    VisualPtr visual;
326    int i;
327
328    REQUEST(xXF86DRICreateContextReq);
329    REQUEST_SIZE_MATCH(xXF86DRICreateContextReq);
330    if (stuff->screen >= screenInfo.numScreens) {
331	client->errorValue = stuff->screen;
332	return BadValue;
333    }
334
335    rep.type = X_Reply;
336    rep.length = 0;
337    rep.sequenceNumber = client->sequence;
338
339    pScreen = screenInfo.screens[stuff->screen];
340    visual = pScreen->visuals;
341
342    /* Find the requested X visual */
343    for (i = 0; i < pScreen->numVisuals; i++, visual++)
344	if (visual->vid == stuff->visual)
345	    break;
346    if (i == pScreen->numVisuals) {
347	/* No visual found */
348	return BadValue;
349    }
350
351    if (!DRICreateContext( pScreen,
352			   visual,
353			   stuff->context,
354			   (drm_context_t *)&rep.hHWContext)) {
355	return BadValue;
356    }
357
358    WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep);
359    return (client->noClientException);
360}
361
362static int
363ProcXF86DRIDestroyContext(
364    register ClientPtr client
365)
366{
367    REQUEST(xXF86DRIDestroyContextReq);
368    REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq);
369    if (stuff->screen >= screenInfo.numScreens) {
370	client->errorValue = stuff->screen;
371	return BadValue;
372    }
373
374    if (!DRIDestroyContext( screenInfo.screens[stuff->screen],
375			    stuff->context)) {
376	return BadValue;
377    }
378
379    return (client->noClientException);
380}
381
382static int
383ProcXF86DRICreateDrawable(
384    ClientPtr client
385)
386{
387    xXF86DRICreateDrawableReply	rep;
388    DrawablePtr pDrawable;
389    int rc;
390
391    REQUEST(xXF86DRICreateDrawableReq);
392    REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq);
393    if (stuff->screen >= screenInfo.numScreens) {
394	client->errorValue = stuff->screen;
395	return BadValue;
396    }
397
398    rep.type = X_Reply;
399    rep.length = 0;
400    rep.sequenceNumber = client->sequence;
401
402    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
403			   DixReadAccess);
404    if (rc != Success)
405	return rc;
406
407    if (!DRICreateDrawable(screenInfo.screens[stuff->screen], client,
408			   pDrawable, (drm_drawable_t *)&rep.hHWDrawable)) {
409	return BadValue;
410    }
411
412    WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep);
413    return (client->noClientException);
414}
415
416static int
417ProcXF86DRIDestroyDrawable(
418    register ClientPtr client
419)
420{
421    REQUEST(xXF86DRIDestroyDrawableReq);
422    DrawablePtr pDrawable;
423    REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq);
424    int rc;
425
426    if (stuff->screen >= screenInfo.numScreens) {
427	client->errorValue = stuff->screen;
428	return BadValue;
429    }
430
431    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
432			   DixReadAccess);
433    if (rc != Success)
434	return rc;
435
436    if (!DRIDestroyDrawable(screenInfo.screens[stuff->screen], client,
437			    pDrawable)) {
438	return BadValue;
439    }
440
441    return (client->noClientException);
442}
443
444static int
445ProcXF86DRIGetDrawableInfo(
446    register ClientPtr client
447)
448{
449    xXF86DRIGetDrawableInfoReply	rep;
450    DrawablePtr pDrawable;
451    int X, Y, W, H;
452    drm_clip_rect_t * pClipRects, *pClippedRects;
453    drm_clip_rect_t * pBackClipRects;
454    int backX, backY, rc;
455
456    REQUEST(xXF86DRIGetDrawableInfoReq);
457    REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq);
458    if (stuff->screen >= screenInfo.numScreens) {
459	client->errorValue = stuff->screen;
460	return BadValue;
461    }
462
463    rep.type = X_Reply;
464    rep.length = 0;
465    rep.sequenceNumber = client->sequence;
466
467    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
468			   DixReadAccess);
469    if (rc != Success)
470	return rc;
471
472    if (!DRIGetDrawableInfo( screenInfo.screens[stuff->screen],
473			     pDrawable,
474			     (unsigned int*)&rep.drawableTableIndex,
475			     (unsigned int*)&rep.drawableTableStamp,
476			     (int*)&X,
477			     (int*)&Y,
478			     (int*)&W,
479			     (int*)&H,
480			     (int*)&rep.numClipRects,
481			     &pClipRects,
482			     &backX,
483			     &backY,
484			     (int*)&rep.numBackClipRects,
485			     &pBackClipRects)) {
486	return BadValue;
487    }
488
489    rep.drawableX = X;
490    rep.drawableY = Y;
491    rep.drawableWidth = W;
492    rep.drawableHeight = H;
493    rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) -
494		  SIZEOF(xGenericReply));
495
496    rep.backX = backX;
497    rep.backY = backY;
498
499    if (rep.numBackClipRects)
500       rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects;
501
502    pClippedRects = pClipRects;
503
504    if (rep.numClipRects) {
505       /* Clip cliprects to screen dimensions (redirected windows) */
506       pClippedRects = xalloc(rep.numClipRects * sizeof(drm_clip_rect_t));
507
508       if (pClippedRects) {
509	    ScreenPtr pScreen = screenInfo.screens[stuff->screen];
510	    int i, j;
511
512	    for (i = 0, j = 0; i < rep.numClipRects; i++) {
513		pClippedRects[j].x1 = max(pClipRects[i].x1, 0);
514		pClippedRects[j].y1 = max(pClipRects[i].y1, 0);
515		pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width);
516		pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height);
517
518		if (pClippedRects[j].x1 < pClippedRects[j].x2 &&
519		    pClippedRects[j].y1 < pClippedRects[j].y2) {
520		    j++;
521		}
522	    }
523
524	    rep.numClipRects = j;
525       } else {
526	    rep.numClipRects = 0;
527       }
528
529       rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects;
530    }
531
532    rep.length = ((rep.length + 3) & ~3) >> 2;
533
534    WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep);
535
536    if (rep.numClipRects) {
537	WriteToClient(client,
538		      sizeof(drm_clip_rect_t) * rep.numClipRects,
539		      (char *)pClippedRects);
540	xfree(pClippedRects);
541    }
542
543    if (rep.numBackClipRects) {
544       WriteToClient(client,
545		     sizeof(drm_clip_rect_t) * rep.numBackClipRects,
546		     (char *)pBackClipRects);
547    }
548
549    return (client->noClientException);
550}
551
552static int
553ProcXF86DRIGetDeviceInfo(
554    register ClientPtr client
555)
556{
557    xXF86DRIGetDeviceInfoReply	rep;
558    drm_handle_t hFrameBuffer;
559    void *pDevPrivate;
560
561    REQUEST(xXF86DRIGetDeviceInfoReq);
562    REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq);
563    if (stuff->screen >= screenInfo.numScreens) {
564	client->errorValue = stuff->screen;
565	return BadValue;
566    }
567
568    rep.type = X_Reply;
569    rep.length = 0;
570    rep.sequenceNumber = client->sequence;
571
572    if (!DRIGetDeviceInfo( screenInfo.screens[stuff->screen],
573			   &hFrameBuffer,
574			   (int*)&rep.framebufferOrigin,
575			   (int*)&rep.framebufferSize,
576			   (int*)&rep.framebufferStride,
577			   (int*)&rep.devPrivateSize,
578			   &pDevPrivate)) {
579	return BadValue;
580    }
581
582    rep.hFrameBufferLow  = (CARD32)(hFrameBuffer & 0xffffffff);
583#if defined(LONG64) && !defined(__linux__)
584    rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32);
585#else
586    rep.hFrameBufferHigh = 0;
587#endif
588
589    rep.length = 0;
590    if (rep.devPrivateSize) {
591	rep.length = (SIZEOF(xXF86DRIGetDeviceInfoReply) -
592		      SIZEOF(xGenericReply) +
593		      ((rep.devPrivateSize + 3) & ~3)) >> 2;
594    }
595
596    WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep);
597    if (rep.length) {
598	WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate);
599    }
600    return (client->noClientException);
601}
602
603static int
604ProcXF86DRIDispatch (
605    register ClientPtr	client
606)
607{
608    REQUEST(xReq);
609
610    switch (stuff->data)
611    {
612    case X_XF86DRIQueryVersion:
613	return ProcXF86DRIQueryVersion(client);
614    case X_XF86DRIQueryDirectRenderingCapable:
615	return ProcXF86DRIQueryDirectRenderingCapable(client);
616    }
617
618    if (!LocalClient(client))
619	return DRIErrorBase + XF86DRIClientNotLocal;
620
621    switch (stuff->data)
622    {
623    case X_XF86DRIOpenConnection:
624	return ProcXF86DRIOpenConnection(client);
625    case X_XF86DRICloseConnection:
626	return ProcXF86DRICloseConnection(client);
627    case X_XF86DRIGetClientDriverName:
628	return ProcXF86DRIGetClientDriverName(client);
629    case X_XF86DRICreateContext:
630	return ProcXF86DRICreateContext(client);
631    case X_XF86DRIDestroyContext:
632	return ProcXF86DRIDestroyContext(client);
633    case X_XF86DRICreateDrawable:
634	return ProcXF86DRICreateDrawable(client);
635    case X_XF86DRIDestroyDrawable:
636	return ProcXF86DRIDestroyDrawable(client);
637    case X_XF86DRIGetDrawableInfo:
638	return ProcXF86DRIGetDrawableInfo(client);
639    case X_XF86DRIGetDeviceInfo:
640	return ProcXF86DRIGetDeviceInfo(client);
641    case X_XF86DRIAuthConnection:
642	return ProcXF86DRIAuthConnection(client);
643    /* {Open,Close}FullScreen are deprecated now */
644    default:
645	return BadRequest;
646    }
647}
648
649static int
650SProcXF86DRIQueryVersion(
651    register ClientPtr	client
652)
653{
654    register int n;
655    REQUEST(xXF86DRIQueryVersionReq);
656    swaps(&stuff->length, n);
657    return ProcXF86DRIQueryVersion(client);
658}
659
660static int
661SProcXF86DRIQueryDirectRenderingCapable(
662    register ClientPtr client
663)
664{
665    register int n;
666    REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
667    swaps(&stuff->length, n);
668    swapl(&stuff->screen, n);
669    return ProcXF86DRIQueryDirectRenderingCapable(client);
670}
671
672static int
673SProcXF86DRIDispatch (
674    register ClientPtr	client
675)
676{
677    REQUEST(xReq);
678
679    /*
680     * Only local clients are allowed DRI access, but remote clients still need
681     * these requests to find out cleanly.
682     */
683    switch (stuff->data)
684    {
685    case X_XF86DRIQueryVersion:
686	return SProcXF86DRIQueryVersion(client);
687    case X_XF86DRIQueryDirectRenderingCapable:
688	return SProcXF86DRIQueryDirectRenderingCapable(client);
689    default:
690	return DRIErrorBase + XF86DRIClientNotLocal;
691    }
692}
693