xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/dri/xf86dri.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /**************************************************************************
2 
3 Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas.
4 Copyright 2000 VA Linux Systems, Inc.
5 All Rights Reserved.
6 
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sub license, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice (including the
16 next paragraph) shall be included in all copies or substantial portions
17 of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
23 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 SOFTWARE 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 
66 static int DRIErrorBase;
67 
68 static void XF86DRIResetProc(ExtensionEntry *extEntry);
69 
70 static unsigned char DRIReqCode = 0;
71 
72 /*ARGSUSED*/
73 static void
XF86DRIResetProc(ExtensionEntry * extEntry)74 XF86DRIResetProc(ExtensionEntry *extEntry)
75 {
76     DRIReset();
77 }
78 
79 static int
ProcXF86DRIQueryVersion(register ClientPtr client)80 ProcXF86DRIQueryVersion(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 
103 static int
ProcXF86DRIQueryDirectRenderingCapable(register ClientPtr client)104 ProcXF86DRIQueryDirectRenderingCapable(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 
142 static int
ProcXF86DRIOpenConnection(register ClientPtr client)143 ProcXF86DRIOpenConnection(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 
187 static int
ProcXF86DRIAuthConnection(register ClientPtr client)188 ProcXF86DRIAuthConnection(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 
212 static int
ProcXF86DRICloseConnection(register ClientPtr client)213 ProcXF86DRICloseConnection(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 
227 static int
ProcXF86DRIGetClientDriverName(register ClientPtr client)228 ProcXF86DRIGetClientDriverName(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 
262 static int
ProcXF86DRICreateContext(register ClientPtr client)263 ProcXF86DRICreateContext(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 
291 static int
ProcXF86DRIDestroyContext(register ClientPtr client)292 ProcXF86DRIDestroyContext(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 
308 static int
ProcXF86DRICreateDrawable(ClientPtr client)309 ProcXF86DRICreateDrawable(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 
340 static int
ProcXF86DRIDestroyDrawable(register ClientPtr client)341 ProcXF86DRIDestroyDrawable(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 
367 static int
ProcXF86DRIGetDrawableInfo(register ClientPtr client)368 ProcXF86DRIGetDrawableInfo(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 
472 static int
ProcXF86DRIGetDeviceInfo(register ClientPtr client)473 ProcXF86DRIGetDeviceInfo(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 
519 static int
ProcXF86DRIDispatch(register ClientPtr client)520 ProcXF86DRIDispatch(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 
561 static int _X_COLD
SProcXF86DRIQueryVersion(register ClientPtr client)562 SProcXF86DRIQueryVersion(register ClientPtr client)
563 {
564     REQUEST(xXF86DRIQueryVersionReq);
565     swaps(&stuff->length);
566     return ProcXF86DRIQueryVersion(client);
567 }
568 
569 static int _X_COLD
SProcXF86DRIQueryDirectRenderingCapable(register ClientPtr client)570 SProcXF86DRIQueryDirectRenderingCapable(register ClientPtr client)
571 {
572     REQUEST(xXF86DRIQueryDirectRenderingCapableReq);
573     REQUEST_SIZE_MATCH(xXF86DRIQueryDirectRenderingCapableReq);
574     swaps(&stuff->length);
575     swapl(&stuff->screen);
576     return ProcXF86DRIQueryDirectRenderingCapable(client);
577 }
578 
579 static int _X_COLD
SProcXF86DRIDispatch(register ClientPtr client)580 SProcXF86DRIDispatch(register ClientPtr client)
581 {
582     REQUEST(xReq);
583 
584     /*
585      * Only local clients are allowed DRI access, but remote clients still need
586      * these requests to find out cleanly.
587      */
588     switch (stuff->data) {
589     case X_XF86DRIQueryVersion:
590         return SProcXF86DRIQueryVersion(client);
591     case X_XF86DRIQueryDirectRenderingCapable:
592         return SProcXF86DRIQueryDirectRenderingCapable(client);
593     default:
594         return DRIErrorBase + XF86DRIClientNotLocal;
595     }
596 }
597 
598 void
XFree86DRIExtensionInit(void)599 XFree86DRIExtensionInit(void)
600 {
601     ExtensionEntry *extEntry;
602 
603     if (DRIExtensionInit() &&
604         (extEntry = AddExtension(XF86DRINAME,
605                                  XF86DRINumberEvents,
606                                  XF86DRINumberErrors,
607                                  ProcXF86DRIDispatch,
608                                  SProcXF86DRIDispatch,
609                                  XF86DRIResetProc, StandardMinorOpcode))) {
610         DRIReqCode = (unsigned char) extEntry->base;
611         DRIErrorBase = extEntry->errorBase;
612     }
613 }
614