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