xf86dri.c revision 9ace9065
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#include <X11/X.h>
46#include <X11/Xproto.h>
47#include "misc.h"
48#include "dixstruct.h"
49#include "extnsionst.h"
50#include "colormapst.h"
51#include "cursorstr.h"
52#include "scrnintstr.h"
53#include "servermd.h"
54#define _XF86DRI_SERVER_
55#include <X11/dri/xf86driproto.h>
56#include "swaprep.h"
57#include "xf86str.h"
58#include "dri.h"
59#include "sarea.h"
60#include "dristruct.h"
61#include "xf86.h"
62#include "xf86drm.h"
63#include "protocol-versions.h"
64
65static int DRIErrorBase;
66
67
68
69static void XF86DRIResetProc(ExtensionEntry* extEntry);
70
71static unsigned char DRIReqCode = 0;
72
73extern void XFree86DRIExtensionInit(void);
74
75/*ARGSUSED*/
76static void
77XF86DRIResetProc (
78    ExtensionEntry* extEntry
79)
80{
81    DRIReset();
82}
83
84static int
85ProcXF86DRIQueryVersion(
86    register ClientPtr client
87)
88{
89    xXF86DRIQueryVersionReply rep;
90    register int n;
91
92    REQUEST_SIZE_MATCH(xXF86DRIQueryVersionReq);
93    rep.type = X_Reply;
94    rep.length = 0;
95    rep.sequenceNumber = client->sequence;
96    rep.majorVersion = SERVER_XF86DRI_MAJOR_VERSION;
97    rep.minorVersion = SERVER_XF86DRI_MINOR_VERSION;
98    rep.patchVersion = SERVER_XF86DRI_PATCH_VERSION;
99    if (client->swapped) {
100    	swaps(&rep.sequenceNumber, n);
101    	swapl(&rep.length, n);
102	swaps(&rep.majorVersion, n);
103	swaps(&rep.minorVersion, n);
104	swapl(&rep.patchVersion, n);
105    }
106    WriteToClient(client, sizeof(xXF86DRIQueryVersionReply), (char *)&rep);
107    return Success;
108}
109
110static int
111ProcXF86DRIQueryDirectRenderingCapable(
112    register ClientPtr client
113)
114{
115    xXF86DRIQueryDirectRenderingCapableReply	rep;
116    Bool isCapable;
117    register int n;
118
119    REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
120    REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq);
121    if (stuff->screen >= screenInfo.numScreens) {
122	client->errorValue = stuff->screen;
123	return BadValue;
124    }
125
126    rep.type = X_Reply;
127    rep.length = 0;
128    rep.sequenceNumber = client->sequence;
129
130    if (!DRIQueryDirectRenderingCapable( screenInfo.screens[stuff->screen],
131					 &isCapable)) {
132	return BadValue;
133    }
134    rep.isCapable = isCapable;
135
136    if (!LocalClient(client) || client->swapped)
137	rep.isCapable = 0;
138
139    if (client->swapped) {
140    	swaps(&rep.sequenceNumber, n);
141    	swapl(&rep.length, n);
142    }
143
144    WriteToClient(client,
145	sizeof(xXF86DRIQueryDirectRenderingCapableReply), (char *)&rep);
146    return Success;
147}
148
149static int
150ProcXF86DRIOpenConnection(
151    register ClientPtr client
152)
153{
154    xXF86DRIOpenConnectionReply rep;
155    drm_handle_t			hSAREA;
156    char*			busIdString;
157
158    REQUEST(xXF86DRIOpenConnectionReq);
159    REQUEST_SIZE_MATCH(xXF86DRIOpenConnectionReq);
160    if (stuff->screen >= screenInfo.numScreens) {
161	client->errorValue = stuff->screen;
162	return BadValue;
163    }
164
165    if (!DRIOpenConnection( screenInfo.screens[stuff->screen],
166			    &hSAREA,
167			    &busIdString)) {
168	return BadValue;
169    }
170
171    rep.type = X_Reply;
172    rep.sequenceNumber = client->sequence;
173    rep.busIdStringLength = 0;
174    if (busIdString)
175	rep.busIdStringLength = strlen(busIdString);
176    rep.length = bytes_to_int32(SIZEOF(xXF86DRIOpenConnectionReply) - SIZEOF(xGenericReply) +
177                  pad_to_int32(rep.busIdStringLength));
178
179    rep.hSAREALow  = (CARD32)(hSAREA & 0xffffffff);
180#if defined(LONG64) && !defined(__linux__)
181    rep.hSAREAHigh = (CARD32)(hSAREA >> 32);
182#else
183    rep.hSAREAHigh = 0;
184#endif
185
186    WriteToClient(client, sizeof(xXF86DRIOpenConnectionReply), (char *)&rep);
187    if (rep.busIdStringLength)
188	WriteToClient(client, rep.busIdStringLength, busIdString);
189    return Success;
190}
191
192static int
193ProcXF86DRIAuthConnection(
194    register ClientPtr client
195)
196{
197    xXF86DRIAuthConnectionReply rep;
198
199    REQUEST(xXF86DRIAuthConnectionReq);
200    REQUEST_SIZE_MATCH(xXF86DRIAuthConnectionReq);
201    if (stuff->screen >= screenInfo.numScreens) {
202	client->errorValue = stuff->screen;
203	return BadValue;
204    }
205
206    rep.type = X_Reply;
207    rep.length = 0;
208    rep.sequenceNumber = client->sequence;
209    rep.authenticated = 1;
210
211    if (!DRIAuthConnection( screenInfo.screens[stuff->screen], stuff->magic)) {
212        ErrorF("Failed to authenticate %lu\n", (unsigned long)stuff->magic);
213	rep.authenticated = 0;
214    }
215    WriteToClient(client, sizeof(xXF86DRIAuthConnectionReply), (char *)&rep);
216    return Success;
217}
218
219static int
220ProcXF86DRICloseConnection(
221    register ClientPtr client
222)
223{
224    REQUEST(xXF86DRICloseConnectionReq);
225    REQUEST_SIZE_MATCH(xXF86DRICloseConnectionReq);
226    if (stuff->screen >= screenInfo.numScreens) {
227	client->errorValue = stuff->screen;
228	return BadValue;
229    }
230
231    DRICloseConnection( screenInfo.screens[stuff->screen]);
232
233    return Success;
234}
235
236static int
237ProcXF86DRIGetClientDriverName(
238    register ClientPtr client
239)
240{
241    xXF86DRIGetClientDriverNameReply	rep;
242    char* clientDriverName;
243
244    REQUEST(xXF86DRIGetClientDriverNameReq);
245    REQUEST_SIZE_MATCH(xXF86DRIGetClientDriverNameReq);
246    if (stuff->screen >= screenInfo.numScreens) {
247	client->errorValue = stuff->screen;
248	return BadValue;
249    }
250
251    DRIGetClientDriverName( screenInfo.screens[stuff->screen],
252			    (int *)&rep.ddxDriverMajorVersion,
253			    (int *)&rep.ddxDriverMinorVersion,
254			    (int *)&rep.ddxDriverPatchVersion,
255			    &clientDriverName);
256
257    rep.type = X_Reply;
258    rep.sequenceNumber = client->sequence;
259    rep.clientDriverNameLength = 0;
260    if (clientDriverName)
261	rep.clientDriverNameLength = strlen(clientDriverName);
262    rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetClientDriverNameReply) -
263			SIZEOF(xGenericReply) +
264			pad_to_int32(rep.clientDriverNameLength));
265
266    WriteToClient(client,
267	sizeof(xXF86DRIGetClientDriverNameReply), (char *)&rep);
268    if (rep.clientDriverNameLength)
269	WriteToClient(client,
270                      rep.clientDriverNameLength,
271                      clientDriverName);
272    return Success;
273}
274
275static int
276ProcXF86DRICreateContext(
277    register ClientPtr client
278)
279{
280    xXF86DRICreateContextReply	rep;
281    ScreenPtr pScreen;
282
283    REQUEST(xXF86DRICreateContextReq);
284    REQUEST_SIZE_MATCH(xXF86DRICreateContextReq);
285    if (stuff->screen >= screenInfo.numScreens) {
286	client->errorValue = stuff->screen;
287	return BadValue;
288    }
289
290    rep.type = X_Reply;
291    rep.length = 0;
292    rep.sequenceNumber = client->sequence;
293
294    pScreen = screenInfo.screens[stuff->screen];
295
296    if (!DRICreateContext( pScreen,
297			   NULL,
298			   stuff->context,
299			   (drm_context_t *)&rep.hHWContext)) {
300	return BadValue;
301    }
302
303    WriteToClient(client, sizeof(xXF86DRICreateContextReply), (char *)&rep);
304    return Success;
305}
306
307static int
308ProcXF86DRIDestroyContext(
309    register ClientPtr client
310)
311{
312    REQUEST(xXF86DRIDestroyContextReq);
313    REQUEST_SIZE_MATCH(xXF86DRIDestroyContextReq);
314    if (stuff->screen >= screenInfo.numScreens) {
315	client->errorValue = stuff->screen;
316	return BadValue;
317    }
318
319    if (!DRIDestroyContext( screenInfo.screens[stuff->screen],
320			    stuff->context)) {
321	return BadValue;
322    }
323
324    return Success;
325}
326
327static int
328ProcXF86DRICreateDrawable(
329    ClientPtr client
330)
331{
332    xXF86DRICreateDrawableReply	rep;
333    DrawablePtr pDrawable;
334    int rc;
335
336    REQUEST(xXF86DRICreateDrawableReq);
337    REQUEST_SIZE_MATCH(xXF86DRICreateDrawableReq);
338    if (stuff->screen >= screenInfo.numScreens) {
339	client->errorValue = stuff->screen;
340	return BadValue;
341    }
342
343    rep.type = X_Reply;
344    rep.length = 0;
345    rep.sequenceNumber = client->sequence;
346
347    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
348			   DixReadAccess);
349    if (rc != Success)
350	return rc;
351
352    if (!DRICreateDrawable(screenInfo.screens[stuff->screen], client,
353			   pDrawable, (drm_drawable_t *)&rep.hHWDrawable)) {
354	return BadValue;
355    }
356
357    WriteToClient(client, sizeof(xXF86DRICreateDrawableReply), (char *)&rep);
358    return Success;
359}
360
361static int
362ProcXF86DRIDestroyDrawable(
363    register ClientPtr client
364)
365{
366    REQUEST(xXF86DRIDestroyDrawableReq);
367    DrawablePtr pDrawable;
368    int rc;
369    REQUEST_SIZE_MATCH(xXF86DRIDestroyDrawableReq);
370
371    if (stuff->screen >= screenInfo.numScreens) {
372	client->errorValue = stuff->screen;
373	return BadValue;
374    }
375
376    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
377			   DixReadAccess);
378    if (rc != Success)
379	return rc;
380
381    if (!DRIDestroyDrawable(screenInfo.screens[stuff->screen], client,
382			    pDrawable)) {
383	return BadValue;
384    }
385
386    return Success;
387}
388
389static int
390ProcXF86DRIGetDrawableInfo(
391    register ClientPtr client
392)
393{
394    xXF86DRIGetDrawableInfoReply	rep;
395    DrawablePtr pDrawable;
396    int X, Y, W, H;
397    drm_clip_rect_t * pClipRects, *pClippedRects;
398    drm_clip_rect_t * pBackClipRects;
399    int backX, backY, rc;
400
401    REQUEST(xXF86DRIGetDrawableInfoReq);
402    REQUEST_SIZE_MATCH(xXF86DRIGetDrawableInfoReq);
403    if (stuff->screen >= screenInfo.numScreens) {
404	client->errorValue = stuff->screen;
405	return BadValue;
406    }
407
408    rep.type = X_Reply;
409    rep.length = 0;
410    rep.sequenceNumber = client->sequence;
411
412    rc = dixLookupDrawable(&pDrawable, stuff->drawable, client, 0,
413			   DixReadAccess);
414    if (rc != Success)
415	return rc;
416
417    if (!DRIGetDrawableInfo( screenInfo.screens[stuff->screen],
418			     pDrawable,
419			     (unsigned int*)&rep.drawableTableIndex,
420			     (unsigned int*)&rep.drawableTableStamp,
421			     (int*)&X,
422			     (int*)&Y,
423			     (int*)&W,
424			     (int*)&H,
425			     (int*)&rep.numClipRects,
426			     &pClipRects,
427			     &backX,
428			     &backY,
429			     (int*)&rep.numBackClipRects,
430			     &pBackClipRects)) {
431	return BadValue;
432    }
433
434    rep.drawableX = X;
435    rep.drawableY = Y;
436    rep.drawableWidth = W;
437    rep.drawableHeight = H;
438    rep.length = (SIZEOF(xXF86DRIGetDrawableInfoReply) -
439		  SIZEOF(xGenericReply));
440
441    rep.backX = backX;
442    rep.backY = backY;
443
444    if (rep.numBackClipRects)
445       rep.length += sizeof(drm_clip_rect_t) * rep.numBackClipRects;
446
447    pClippedRects = pClipRects;
448
449    if (rep.numClipRects) {
450       /* Clip cliprects to screen dimensions (redirected windows) */
451       pClippedRects = malloc(rep.numClipRects * sizeof(drm_clip_rect_t));
452
453       if (pClippedRects) {
454	    ScreenPtr pScreen = screenInfo.screens[stuff->screen];
455	    int i, j;
456
457	    for (i = 0, j = 0; i < rep.numClipRects; i++) {
458		pClippedRects[j].x1 = max(pClipRects[i].x1, 0);
459		pClippedRects[j].y1 = max(pClipRects[i].y1, 0);
460		pClippedRects[j].x2 = min(pClipRects[i].x2, pScreen->width);
461		pClippedRects[j].y2 = min(pClipRects[i].y2, pScreen->height);
462
463		if (pClippedRects[j].x1 < pClippedRects[j].x2 &&
464		    pClippedRects[j].y1 < pClippedRects[j].y2) {
465		    j++;
466		}
467	    }
468
469	    rep.numClipRects = j;
470       } else {
471	    rep.numClipRects = 0;
472       }
473
474       rep.length += sizeof(drm_clip_rect_t) * rep.numClipRects;
475    }
476
477    rep.length = bytes_to_int32(rep.length);
478
479    WriteToClient(client, sizeof(xXF86DRIGetDrawableInfoReply), (char *)&rep);
480
481    if (rep.numClipRects) {
482	WriteToClient(client,
483		      sizeof(drm_clip_rect_t) * rep.numClipRects,
484		      (char *)pClippedRects);
485	free(pClippedRects);
486    }
487
488    if (rep.numBackClipRects) {
489       WriteToClient(client,
490		     sizeof(drm_clip_rect_t) * rep.numBackClipRects,
491		     (char *)pBackClipRects);
492    }
493
494    return Success;
495}
496
497static int
498ProcXF86DRIGetDeviceInfo(
499    register ClientPtr client
500)
501{
502    xXF86DRIGetDeviceInfoReply	rep;
503    drm_handle_t hFrameBuffer;
504    void *pDevPrivate;
505
506    REQUEST(xXF86DRIGetDeviceInfoReq);
507    REQUEST_SIZE_MATCH(xXF86DRIGetDeviceInfoReq);
508    if (stuff->screen >= screenInfo.numScreens) {
509	client->errorValue = stuff->screen;
510	return BadValue;
511    }
512
513    rep.type = X_Reply;
514    rep.length = 0;
515    rep.sequenceNumber = client->sequence;
516
517    if (!DRIGetDeviceInfo( screenInfo.screens[stuff->screen],
518			   &hFrameBuffer,
519			   (int*)&rep.framebufferOrigin,
520			   (int*)&rep.framebufferSize,
521			   (int*)&rep.framebufferStride,
522			   (int*)&rep.devPrivateSize,
523			   &pDevPrivate)) {
524	return BadValue;
525    }
526
527    rep.hFrameBufferLow  = (CARD32)(hFrameBuffer & 0xffffffff);
528#if defined(LONG64) && !defined(__linux__)
529    rep.hFrameBufferHigh = (CARD32)(hFrameBuffer >> 32);
530#else
531    rep.hFrameBufferHigh = 0;
532#endif
533
534    rep.length = 0;
535    if (rep.devPrivateSize) {
536	rep.length = bytes_to_int32(SIZEOF(xXF86DRIGetDeviceInfoReply) -
537		      SIZEOF(xGenericReply) +
538		      pad_to_int32(rep.devPrivateSize));
539    }
540
541    WriteToClient(client, sizeof(xXF86DRIGetDeviceInfoReply), (char *)&rep);
542    if (rep.length) {
543	WriteToClient(client, rep.devPrivateSize, (char *)pDevPrivate);
544    }
545    return Success;
546}
547
548static int
549ProcXF86DRIDispatch (
550    register ClientPtr	client
551)
552{
553    REQUEST(xReq);
554
555    switch (stuff->data)
556    {
557    case X_XF86DRIQueryVersion:
558	return ProcXF86DRIQueryVersion(client);
559    case X_XF86DRIQueryDirectRenderingCapable:
560	return ProcXF86DRIQueryDirectRenderingCapable(client);
561    }
562
563    if (!LocalClient(client))
564	return DRIErrorBase + XF86DRIClientNotLocal;
565
566    switch (stuff->data)
567    {
568    case X_XF86DRIOpenConnection:
569	return ProcXF86DRIOpenConnection(client);
570    case X_XF86DRICloseConnection:
571	return ProcXF86DRICloseConnection(client);
572    case X_XF86DRIGetClientDriverName:
573	return ProcXF86DRIGetClientDriverName(client);
574    case X_XF86DRICreateContext:
575	return ProcXF86DRICreateContext(client);
576    case X_XF86DRIDestroyContext:
577	return ProcXF86DRIDestroyContext(client);
578    case X_XF86DRICreateDrawable:
579	return ProcXF86DRICreateDrawable(client);
580    case X_XF86DRIDestroyDrawable:
581	return ProcXF86DRIDestroyDrawable(client);
582    case X_XF86DRIGetDrawableInfo:
583	return ProcXF86DRIGetDrawableInfo(client);
584    case X_XF86DRIGetDeviceInfo:
585	return ProcXF86DRIGetDeviceInfo(client);
586    case X_XF86DRIAuthConnection:
587	return ProcXF86DRIAuthConnection(client);
588    /* {Open,Close}FullScreen are deprecated now */
589    default:
590	return BadRequest;
591    }
592}
593
594static int
595SProcXF86DRIQueryVersion(
596    register ClientPtr	client
597)
598{
599    register int n;
600    REQUEST(xXF86DRIQueryVersionReq);
601    swaps(&stuff->length, n);
602    return ProcXF86DRIQueryVersion(client);
603}
604
605static int
606SProcXF86DRIQueryDirectRenderingCapable(
607    register ClientPtr client
608)
609{
610    register int n;
611    REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
612    swaps(&stuff->length, n);
613    swapl(&stuff->screen, n);
614    return ProcXF86DRIQueryDirectRenderingCapable(client);
615}
616
617static int
618SProcXF86DRIDispatch (
619    register ClientPtr	client
620)
621{
622    REQUEST(xReq);
623
624    /*
625     * Only local clients are allowed DRI access, but remote clients still need
626     * these requests to find out cleanly.
627     */
628    switch (stuff->data)
629    {
630    case X_XF86DRIQueryVersion:
631	return SProcXF86DRIQueryVersion(client);
632    case X_XF86DRIQueryDirectRenderingCapable:
633	return SProcXF86DRIQueryDirectRenderingCapable(client);
634    default:
635	return DRIErrorBase + XF86DRIClientNotLocal;
636    }
637}
638
639void
640XFree86DRIExtensionInit(void)
641{
642    ExtensionEntry* extEntry;
643
644#ifdef XF86DRI_EVENTS
645    EventType = CreateNewResourceType(XF86DRIFreeEvents, "DRIEvent");
646#endif
647
648    if (
649	DRIExtensionInit() &&
650#ifdef XF86DRI_EVENTS
651        EventType && ScreenPrivateIndex != -1 &&
652#endif
653	(extEntry = AddExtension(XF86DRINAME,
654				 XF86DRINumberEvents,
655				 XF86DRINumberErrors,
656				 ProcXF86DRIDispatch,
657				 SProcXF86DRIDispatch,
658				 XF86DRIResetProc,
659				 StandardMinorOpcode))) {
660	DRIReqCode = (unsigned char)extEntry->base;
661	DRIErrorBase = extEntry->errorBase;
662    }
663}
664