]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/xserver.git/blob - hw/xfree86/dri2/dri2ext.c
a2198e2558fa1428da0a37df7d5cb3b99d07148e
[glsdk/xserver.git] / hw / xfree86 / dri2 / dri2ext.c
1 /*
2  * Copyright © 2008 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Soft-
6  * ware"), to deal in the Software without restriction, including without
7  * limitation the rights to use, copy, modify, merge, publish, distribute,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, provided that the above copyright
10  * notice(s) and this permission notice appear in all copies of the Soft-
11  * ware and that both the above copyright notice(s) and this permission
12  * notice appear in supporting documentation.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
16  * ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
17  * RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
18  * THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
19  * QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
22  * MANCE OF THIS SOFTWARE.
23  *
24  * Except as contained in this notice, the name of a copyright holder shall
25  * not be used in advertising or otherwise to promote the sale, use or
26  * other dealings in this Software without prior written authorization of
27  * the copyright holder.
28  *
29  * Authors:
30  *   Kristian Høgsberg (krh@redhat.com)
31  */
33 #ifdef HAVE_XORG_CONFIG_H
34 #include <xorg-config.h>
35 #endif
37 #include <X11/X.h>
38 #include <X11/Xproto.h>
39 #include <X11/extensions/dri2proto.h>
40 #include <X11/extensions/xfixeswire.h>
41 #include "dixstruct.h"
42 #include "scrnintstr.h"
43 #include "pixmapstr.h"
44 #include "extnsionst.h"
45 #include "xfixes.h"
46 #include "dri2.h"
47 #include "protocol-versions.h"
49 /* The only xf86 include */
50 #include "xf86Module.h"
52 static ExtensionEntry   *dri2Extension;
53 extern Bool DRI2ModuleSetup(void);
55 static Bool
56 validDrawable(ClientPtr client, XID drawable, Mask access_mode,
57               DrawablePtr *pDrawable, int *status)
58 {
59     *status = dixLookupDrawable(pDrawable, drawable, client,
60                                 M_DRAWABLE_WINDOW | M_DRAWABLE_PIXMAP,
61                                 access_mode);
62     if (*status != Success) {
63         client->errorValue = drawable;
64         return FALSE;
65     }
67     return TRUE;
68 }
70 static int
71 ProcDRI2QueryVersion(ClientPtr client)
72 {
73     REQUEST(xDRI2QueryVersionReq);
74     xDRI2QueryVersionReply rep;
75     int n;
77     if (client->swapped)
78         swaps(&stuff->length, n);
80     REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
81     rep.type = X_Reply;
82     rep.length = 0;
83     rep.sequenceNumber = client->sequence;
84     rep.majorVersion = dri2_major;
85     rep.minorVersion = dri2_minor;
87     if (client->swapped) {
88         swaps(&rep.sequenceNumber, n);
89         swapl(&rep.length, n);
90         swapl(&rep.majorVersion, n);
91         swapl(&rep.minorVersion, n);
92     }
94     WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
96     return Success;
97 }
99 static int
100 ProcDRI2Connect(ClientPtr client)
102     REQUEST(xDRI2ConnectReq);
103     xDRI2ConnectReply rep;
104     DrawablePtr pDraw;
105     int fd, status;
106     const char *driverName;
107     const char *deviceName;
109     REQUEST_SIZE_MATCH(xDRI2ConnectReq);
110     if (!validDrawable(client, stuff->window, DixGetAttrAccess,
111                        &pDraw, &status))
112         return status;
113     
114     rep.type = X_Reply;
115     rep.length = 0;
116     rep.sequenceNumber = client->sequence;
117     rep.driverNameLength = 0;
118     rep.deviceNameLength = 0;
120     if (!DRI2Connect(pDraw->pScreen,
121                      stuff->driverType, &fd, &driverName, &deviceName))
122         goto fail;
124     rep.driverNameLength = strlen(driverName);
125     rep.deviceNameLength = strlen(deviceName);
126     rep.length = (rep.driverNameLength + 3) / 4 +
127             (rep.deviceNameLength + 3) / 4;
129  fail:
130     WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
131     WriteToClient(client, rep.driverNameLength, driverName);
132     WriteToClient(client, rep.deviceNameLength, deviceName);
134     return Success;
137 static int
138 ProcDRI2Authenticate(ClientPtr client)
140     REQUEST(xDRI2AuthenticateReq);
141     xDRI2AuthenticateReply rep;
142     DrawablePtr pDraw;
143     int status;
145     REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
146     if (!validDrawable(client, stuff->window, DixGetAttrAccess,
147                        &pDraw, &status))
148         return status;
150     rep.type = X_Reply;
151     rep.sequenceNumber = client->sequence;
152     rep.length = 0;
153     rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic);
154     WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
156     return Success;
159 static void
160 DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv)
162     xDRI2InvalidateBuffers event;
163     ClientPtr client = priv;
165     event.type = DRI2EventBase + DRI2_InvalidateBuffers;
166     event.drawable = pDraw->id;
168     WriteEventsToClient(client, 1, (xEvent *)&event);
171 static int
172 ProcDRI2CreateDrawable(ClientPtr client)
174     REQUEST(xDRI2CreateDrawableReq);
175     DrawablePtr pDrawable;
176     int status;
178     REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
180     if (!validDrawable(client, stuff->drawable, DixAddAccess,
181                        &pDrawable, &status))
182         return status;
184     status = DRI2CreateDrawable(client, pDrawable, stuff->drawable,
185                                 DRI2InvalidateBuffersEvent, client);
186     if (status != Success)
187         return status;
189     return Success;
192 static int
193 ProcDRI2DestroyDrawable(ClientPtr client)
195     REQUEST(xDRI2DestroyDrawableReq);
196     DrawablePtr pDrawable;
197     int status;
199     REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
200     if (!validDrawable(client, stuff->drawable, DixRemoveAccess,
201                        &pDrawable, &status))
202         return status;
204     return Success;
208 static int
209 send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
210                    DRI2BufferPtr *buffers, int count, int width, int height)
212     xDRI2GetBuffersReply rep;
213     int skip = 0;
214     int i;
216     if (buffers == NULL)
217             return BadAlloc;
219     if (pDrawable->type == DRAWABLE_WINDOW) {
220         for (i = 0; i < count; i++) {
221             /* Do not send the real front buffer of a window to the client.
222              */
223             if (buffers[i]->attachment == DRI2BufferFrontLeft) {
224                 skip++;
225                 continue;
226             }
227         }
228     }
230     rep.type = X_Reply;
231     rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4;
232     rep.sequenceNumber = client->sequence;
233     rep.width = width;
234     rep.height = height;
235     rep.count = count - skip;
236     WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
238     for (i = 0; i < count; i++) {
239         xDRI2Buffer buffer;
241         /* Do not send the real front buffer of a window to the client.
242          */
243         if ((pDrawable->type == DRAWABLE_WINDOW)
244             && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
245             continue;
246         }
248         buffer.attachment = buffers[i]->attachment;
249         buffer.name = buffers[i]->name;
250         buffer.pitch = buffers[i]->pitch;
251         buffer.cpp = buffers[i]->cpp;
252         buffer.flags = buffers[i]->flags;
253         WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
254     }
255     return Success;
259 static int
260 ProcDRI2GetBuffers(ClientPtr client)
262     REQUEST(xDRI2GetBuffersReq);
263     DrawablePtr pDrawable;
264     DRI2BufferPtr *buffers;
265     int status, width, height, count;
266     unsigned int *attachments;
268     REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
269     if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
270                        &pDrawable, &status))
271         return status;
273     if (DRI2ThrottleClient(client, pDrawable))
274         return Success;
276     attachments = (unsigned int *) &stuff[1];
277     buffers = DRI2GetBuffers(pDrawable, &width, &height,
278                              attachments, stuff->count, &count);
281     return send_buffers_reply(client, pDrawable, buffers, count, width, height);
285 static int
286 ProcDRI2GetBuffersWithFormat(ClientPtr client)
288     REQUEST(xDRI2GetBuffersReq);
289     DrawablePtr pDrawable;
290     DRI2BufferPtr *buffers;
291     int status, width, height, count;
292     unsigned int *attachments;
294     REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4));
295     if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
296                        &pDrawable, &status))
297         return status;
299     if (DRI2ThrottleClient(client, pDrawable))
300         return Success;
302     attachments = (unsigned int *) &stuff[1];
303     buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
304                                        attachments, stuff->count, &count);
306     return send_buffers_reply(client, pDrawable, buffers, count, width, height);
309 static int
310 ProcDRI2CopyRegion(ClientPtr client)
312     REQUEST(xDRI2CopyRegionReq);
313     xDRI2CopyRegionReply rep;
314     DrawablePtr pDrawable;
315     int status;
316     RegionPtr pRegion;
318     REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
320     if (!validDrawable(client, stuff->drawable, DixWriteAccess,
321                        &pDrawable, &status))
322         return status;
324     VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
326     status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src);
327     if (status != Success)
328         return status;
330     /* CopyRegion needs to be a round trip to make sure the X server
331      * queues the swap buffer rendering commands before the DRI client
332      * continues rendering.  The reply has a bitmask to signal the
333      * presense of optional return values as well, but we're not using
334      * that yet.
335      */
337     rep.type = X_Reply;
338     rep.length = 0;
339     rep.sequenceNumber = client->sequence;
341     WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
343     return Success;
346 static void
347 load_swap_reply(xDRI2SwapBuffersReply *rep, CARD64 sbc)
349     rep->swap_hi = sbc >> 32;
350     rep->swap_lo = sbc & 0xffffffff;
353 static CARD64
354 vals_to_card64(CARD32 lo, CARD32 hi)
356     return (CARD64)hi << 32 | lo;
359 static void
360 DRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc,
361               CARD32 sbc)
363     xDRI2BufferSwapComplete2 event;
364     DrawablePtr pDrawable = data;
366     event.type = DRI2EventBase + DRI2_BufferSwapComplete;
367     event.event_type = type;
368     event.drawable = pDrawable->id;
369     event.ust_hi = (CARD64)ust >> 32;
370     event.ust_lo = ust & 0xffffffff;
371     event.msc_hi = (CARD64)msc >> 32;
372     event.msc_lo = msc & 0xffffffff;
373     event.sbc = sbc;
375     WriteEventsToClient(client, 1, (xEvent *)&event);
378 static int
379 ProcDRI2SwapBuffers(ClientPtr client)
381     REQUEST(xDRI2SwapBuffersReq);
382     xDRI2SwapBuffersReply rep;
383     DrawablePtr pDrawable;
384     CARD64 target_msc, divisor, remainder, swap_target;
385     int status;
387     REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq);
389     if (!validDrawable(client, stuff->drawable,
390                        DixReadAccess | DixWriteAccess, &pDrawable, &status))
391         return status;
393     /*
394      * Ensures an out of control client can't exhaust our swap queue, and
395      * also orders swaps.
396      */
397     if (DRI2ThrottleClient(client, pDrawable))
398         return Success;
400     target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
401     divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
402     remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
404     status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
405                              &swap_target, DRI2SwapEvent, pDrawable);
406     if (status != Success)
407         return BadDrawable;
409     rep.type = X_Reply;
410     rep.length = 0;
411     rep.sequenceNumber = client->sequence;
412     load_swap_reply(&rep, swap_target);
414     WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
416     return Success;
419 static void
420 load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc)
422     rep->ust_hi = ust >> 32;
423     rep->ust_lo = ust & 0xffffffff;
424     rep->msc_hi = msc >> 32;
425     rep->msc_lo = msc & 0xffffffff;
426     rep->sbc_hi = sbc >> 32;
427     rep->sbc_lo = sbc & 0xffffffff;
430 static int
431 ProcDRI2GetMSC(ClientPtr client)
433     REQUEST(xDRI2GetMSCReq);
434     xDRI2MSCReply rep;
435     DrawablePtr pDrawable;
436     CARD64 ust, msc, sbc;
437     int status;
439     REQUEST_SIZE_MATCH(xDRI2GetMSCReq);
441     if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
442                        &status))
443         return status;
445     status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc);
446     if (status != Success)
447         return status;
449     rep.type = X_Reply;
450     rep.length = 0;
451     rep.sequenceNumber = client->sequence;
452     load_msc_reply(&rep, ust, msc, sbc);
454     WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
456     return Success;
459 static int
460 ProcDRI2WaitMSC(ClientPtr client)
462     REQUEST(xDRI2WaitMSCReq);
463     DrawablePtr pDrawable;
464     CARD64 target, divisor, remainder;
465     int status;
467     /* FIXME: in restart case, client may be gone at this point */
469     REQUEST_SIZE_MATCH(xDRI2WaitMSCReq);
471     if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
472                        &status))
473         return status;
475     target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
476     divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
477     remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
479     status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder);
480     if (status != Success)
481         return status;
483     return Success;
486 int
487 ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc)
489     xDRI2MSCReply rep;
491     rep.type = X_Reply;
492     rep.length = 0;
493     rep.sequenceNumber = client->sequence;
494     load_msc_reply(&rep, ust, msc, sbc);
496     WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
498     return Success;
501 static int
502 ProcDRI2SwapInterval(ClientPtr client)
504     REQUEST(xDRI2SwapIntervalReq);
505     DrawablePtr pDrawable;
506     int status;
508     /* FIXME: in restart case, client may be gone at this point */
510     REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq);
512     if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
513                        &pDrawable, &status))
514         return status;
516     DRI2SwapInterval(pDrawable, stuff->interval);
518     return Success;
521 static int
522 ProcDRI2WaitSBC(ClientPtr client)
524     REQUEST(xDRI2WaitSBCReq);
525     DrawablePtr pDrawable;
526     CARD64 target;
527     int status;
529     REQUEST_SIZE_MATCH(xDRI2WaitSBCReq);
531     if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
532                        &status))
533         return status;
535     target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi);
536     status = DRI2WaitSBC(client, pDrawable, target);
538     return status;
541 static int
542 ProcDRI2Dispatch (ClientPtr client)
544     REQUEST(xReq);
545     
546     switch (stuff->data) {
547     case X_DRI2QueryVersion:
548         return ProcDRI2QueryVersion(client);
549     }
551     if (!LocalClient(client))
552         return BadRequest;
554     switch (stuff->data) {
555     case X_DRI2Connect:
556         return ProcDRI2Connect(client);
557     case X_DRI2Authenticate:
558         return ProcDRI2Authenticate(client);
559     case X_DRI2CreateDrawable:
560         return ProcDRI2CreateDrawable(client);
561     case X_DRI2DestroyDrawable:
562         return ProcDRI2DestroyDrawable(client);
563     case X_DRI2GetBuffers:
564         return ProcDRI2GetBuffers(client);
565     case X_DRI2CopyRegion:
566         return ProcDRI2CopyRegion(client);
567     case X_DRI2GetBuffersWithFormat:
568         return ProcDRI2GetBuffersWithFormat(client);
569     case X_DRI2SwapBuffers:
570         return ProcDRI2SwapBuffers(client);
571     case X_DRI2GetMSC:
572         return ProcDRI2GetMSC(client);
573     case X_DRI2WaitMSC:
574         return ProcDRI2WaitMSC(client);
575     case X_DRI2WaitSBC:
576         return ProcDRI2WaitSBC(client);
577     case X_DRI2SwapInterval:
578         return ProcDRI2SwapInterval(client);
579     default:
580         return BadRequest;
581     }
584 static int
585 SProcDRI2Connect(ClientPtr client)
587     REQUEST(xDRI2ConnectReq);
588     xDRI2ConnectReply rep;
589     int n;
591     /* If the client is swapped, it's not local.  Talk to the hand. */
593     swaps(&stuff->length, n);
594     if (sizeof(*stuff) / 4 != client->req_len)
595         return BadLength;
597     rep.sequenceNumber = client->sequence;
598     swaps(&rep.sequenceNumber, n);
599     rep.length = 0;
600     rep.driverNameLength = 0;
601     rep.deviceNameLength = 0;
603     return Success;
606 static int
607 SProcDRI2Dispatch (ClientPtr client)
609     REQUEST(xReq);
611     /*
612      * Only local clients are allowed DRI access, but remote clients
613      * still need these requests to find out cleanly.
614      */
615     switch (stuff->data)
616     {
617     case X_DRI2QueryVersion:
618         return ProcDRI2QueryVersion(client);
619     case X_DRI2Connect:
620         return SProcDRI2Connect(client);
621     default:
622         return BadRequest;
623     }
626 int DRI2EventBase;
628 static void
629 DRI2ExtensionInit(void)
631     dri2Extension = AddExtension(DRI2_NAME,
632                                  DRI2NumberEvents,
633                                  DRI2NumberErrors,
634                                  ProcDRI2Dispatch,
635                                  SProcDRI2Dispatch,
636                                  NULL,
637                                  StandardMinorOpcode);
639     DRI2EventBase = dri2Extension->eventBase;
641     DRI2ModuleSetup();
644 extern Bool noDRI2Extension;
646 _X_HIDDEN ExtensionModule dri2ExtensionModule = {
647     DRI2ExtensionInit,
648     DRI2_NAME,
649     &noDRI2Extension,
650     NULL,
651     NULL
652 };