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