2 * Copyright © 2008 Red Hat, Inc.
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.
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.
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.
30 * Kristian Høgsberg (krh@redhat.com)
33 #ifdef HAVE_XORG_CONFIG_H
34 #include <xorg-config.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"
48 #include "protocol-versions.h"
50 /* The only xf86 includes */
51 #include "xf86Module.h"
52 #include "xf86Extensions.h"
54 static int DRI2EventBase
;
58 validDrawable(ClientPtr client
, XID drawable
, Mask access_mode
,
59 DrawablePtr
*pDrawable
, int *status
)
61 *status
= dixLookupDrawable(pDrawable
, drawable
, client
,
62 M_DRAWABLE_WINDOW
| M_DRAWABLE_PIXMAP
,
64 if (*status
!= Success
) {
65 client
->errorValue
= drawable
;
73 ProcDRI2QueryVersion(ClientPtr client
)
75 REQUEST(xDRI2QueryVersionReq
);
76 xDRI2QueryVersionReply rep
= {
78 .sequenceNumber
= client
->sequence
,
80 .majorVersion
= dri2_major
,
81 .minorVersion
= dri2_minor
85 swaps(&stuff
->length
);
87 REQUEST_SIZE_MATCH(xDRI2QueryVersionReq
);
89 if (client
->swapped
) {
90 swaps(&rep
.sequenceNumber
);
92 swapl(&rep
.majorVersion
);
93 swapl(&rep
.minorVersion
);
96 WriteToClient(client
, sizeof(xDRI2QueryVersionReply
), &rep
);
102 ProcDRI2Connect(ClientPtr client
)
104 REQUEST(xDRI2ConnectReq
);
105 xDRI2ConnectReply rep
= {
107 .sequenceNumber
= client
->sequence
,
109 .driverNameLength
= 0,
110 .deviceNameLength
= 0
114 const char *driverName
;
115 const char *deviceName
;
117 REQUEST_SIZE_MATCH(xDRI2ConnectReq
);
118 if (!validDrawable(client
, stuff
->window
, DixGetAttrAccess
,
122 if (!DRI2Connect(client
, pDraw
->pScreen
,
123 stuff
->driverType
, &fd
, &driverName
, &deviceName
))
126 rep
.driverNameLength
= strlen(driverName
);
127 rep
.deviceNameLength
= strlen(deviceName
);
128 rep
.length
= (rep
.driverNameLength
+ 3) / 4 +
129 (rep
.deviceNameLength
+ 3) / 4;
132 WriteToClient(client
, sizeof(xDRI2ConnectReply
), &rep
);
133 WriteToClient(client
, rep
.driverNameLength
, driverName
);
134 WriteToClient(client
, rep
.deviceNameLength
, deviceName
);
140 ProcDRI2Authenticate(ClientPtr client
)
142 REQUEST(xDRI2AuthenticateReq
);
143 xDRI2AuthenticateReply rep
;
147 REQUEST_SIZE_MATCH(xDRI2AuthenticateReq
);
148 if (!validDrawable(client
, stuff
->window
, DixGetAttrAccess
,
152 rep
= (xDRI2AuthenticateReply
) {
154 .sequenceNumber
= client
->sequence
,
156 .authenticated
= DRI2Authenticate(client
, pDraw
->pScreen
, stuff
->magic
)
158 WriteToClient(client
, sizeof(xDRI2AuthenticateReply
), &rep
);
164 DRI2InvalidateBuffersEvent(DrawablePtr pDraw
, void *priv
, XID id
)
166 ClientPtr client
= priv
;
167 xDRI2InvalidateBuffers event
= {
168 .type
= DRI2EventBase
+ DRI2_InvalidateBuffers
,
172 WriteEventsToClient(client
, 1, (xEvent
*) &event
);
176 ProcDRI2CreateDrawable(ClientPtr client
)
178 REQUEST(xDRI2CreateDrawableReq
);
179 DrawablePtr pDrawable
;
182 REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq
);
184 if (!validDrawable(client
, stuff
->drawable
, DixAddAccess
,
185 &pDrawable
, &status
))
188 status
= DRI2CreateDrawable(client
, pDrawable
, stuff
->drawable
,
189 DRI2InvalidateBuffersEvent
, client
);
190 if (status
!= Success
)
197 ProcDRI2DestroyDrawable(ClientPtr client
)
199 REQUEST(xDRI2DestroyDrawableReq
);
200 DrawablePtr pDrawable
;
203 REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq
);
204 if (!validDrawable(client
, stuff
->drawable
, DixRemoveAccess
,
205 &pDrawable
, &status
))
212 send_buffers_reply(ClientPtr client
, DrawablePtr pDrawable
,
213 DRI2BufferPtr
* buffers
, int count
, int width
, int height
)
215 xDRI2GetBuffersReply rep
;
222 if (pDrawable
->type
== DRAWABLE_WINDOW
) {
223 for (i
= 0; i
< count
; i
++) {
224 /* Do not send the real front buffer of a window to the client.
226 if (buffers
[i
]->attachment
== DRI2BufferFrontLeft
) {
233 rep
= (xDRI2GetBuffersReply
) {
235 .sequenceNumber
= client
->sequence
,
236 .length
= (count
- skip
) * sizeof(xDRI2Buffer
) / 4,
239 .count
= count
- skip
241 WriteToClient(client
, sizeof(xDRI2GetBuffersReply
), &rep
);
243 for (i
= 0; i
< count
; i
++) {
246 /* Do not send the real front buffer of a window to the client.
248 if ((pDrawable
->type
== DRAWABLE_WINDOW
)
249 && (buffers
[i
]->attachment
== DRI2BufferFrontLeft
)) {
253 buffer
.attachment
= buffers
[i
]->attachment
;
254 buffer
.name
= buffers
[i
]->name
;
255 buffer
.pitch
= buffers
[i
]->pitch
;
256 buffer
.cpp
= buffers
[i
]->cpp
;
257 buffer
.flags
= buffers
[i
]->flags
;
258 WriteToClient(client
, sizeof(xDRI2Buffer
), &buffer
);
264 ProcDRI2GetBuffers(ClientPtr client
)
266 REQUEST(xDRI2GetBuffersReq
);
267 DrawablePtr pDrawable
;
268 DRI2BufferPtr
*buffers
;
269 int status
, width
, height
, count
;
270 unsigned int *attachments
;
272 REQUEST_FIXED_SIZE(xDRI2GetBuffersReq
, stuff
->count
* 4);
273 if (!validDrawable(client
, stuff
->drawable
, DixReadAccess
| DixWriteAccess
,
274 &pDrawable
, &status
))
277 if (DRI2ThrottleClient(client
, pDrawable
))
280 attachments
= (unsigned int *) &stuff
[1];
281 buffers
= DRI2GetBuffers(pDrawable
, &width
, &height
,
282 attachments
, stuff
->count
, &count
);
284 return send_buffers_reply(client
, pDrawable
, buffers
, count
, width
, height
);
289 ProcDRI2GetBuffersWithFormat(ClientPtr client
)
291 REQUEST(xDRI2GetBuffersReq
);
292 DrawablePtr pDrawable
;
293 DRI2BufferPtr
*buffers
;
294 int status
, width
, height
, count
;
295 unsigned int *attachments
;
297 REQUEST_FIXED_SIZE(xDRI2GetBuffersReq
, stuff
->count
* (2 * 4));
298 if (!validDrawable(client
, stuff
->drawable
, DixReadAccess
| DixWriteAccess
,
299 &pDrawable
, &status
))
302 if (DRI2ThrottleClient(client
, pDrawable
))
305 attachments
= (unsigned int *) &stuff
[1];
306 buffers
= DRI2GetBuffersWithFormat(pDrawable
, &width
, &height
,
307 attachments
, stuff
->count
, &count
);
309 return send_buffers_reply(client
, pDrawable
, buffers
, count
, width
, height
);
313 ProcDRI2CopyRegion(ClientPtr client
)
315 REQUEST(xDRI2CopyRegionReq
);
316 xDRI2CopyRegionReply rep
;
317 DrawablePtr pDrawable
;
321 REQUEST_SIZE_MATCH(xDRI2CopyRegionReq
);
323 if (!validDrawable(client
, stuff
->drawable
, DixWriteAccess
,
324 &pDrawable
, &status
))
327 VERIFY_REGION(pRegion
, stuff
->region
, client
, DixReadAccess
);
329 status
= DRI2CopyRegion(pDrawable
, pRegion
, stuff
->dest
, stuff
->src
);
330 if (status
!= Success
)
333 /* CopyRegion needs to be a round trip to make sure the X server
334 * queues the swap buffer rendering commands before the DRI client
335 * continues rendering. The reply has a bitmask to signal the
336 * presense of optional return values as well, but we're not using
340 rep
= (xDRI2CopyRegionReply
) {
342 .sequenceNumber
= client
->sequence
,
346 WriteToClient(client
, sizeof(xDRI2CopyRegionReply
), &rep
);
352 load_swap_reply(xDRI2SwapBuffersReply
* rep
, CARD64 sbc
)
354 rep
->swap_hi
= sbc
>> 32;
355 rep
->swap_lo
= sbc
& 0xffffffff;
359 vals_to_card64(CARD32 lo
, CARD32 hi
)
361 return (CARD64
) hi
<< 32 | lo
;
365 DRI2SwapEvent(ClientPtr client
, void *data
, int type
, CARD64 ust
, CARD64 msc
,
368 DrawablePtr pDrawable
= data
;
369 xDRI2BufferSwapComplete2 event
= {
370 .type
= DRI2EventBase
+ DRI2_BufferSwapComplete
,
372 .drawable
= pDrawable
->id
,
373 .ust_hi
= (CARD64
) ust
>> 32,
374 .ust_lo
= ust
& 0xffffffff,
375 .msc_hi
= (CARD64
) msc
>> 32,
376 .msc_lo
= msc
& 0xffffffff,
380 WriteEventsToClient(client
, 1, (xEvent
*) &event
);
384 ProcDRI2SwapBuffers(ClientPtr client
)
386 REQUEST(xDRI2SwapBuffersReq
);
387 xDRI2SwapBuffersReply rep
= {
389 .sequenceNumber
= client
->sequence
,
392 DrawablePtr pDrawable
;
393 CARD64 target_msc
, divisor
, remainder
, swap_target
;
396 REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq
);
398 if (!validDrawable(client
, stuff
->drawable
,
399 DixReadAccess
| DixWriteAccess
, &pDrawable
, &status
))
403 * Ensures an out of control client can't exhaust our swap queue, and
406 if (DRI2ThrottleClient(client
, pDrawable
))
409 target_msc
= vals_to_card64(stuff
->target_msc_lo
, stuff
->target_msc_hi
);
410 divisor
= vals_to_card64(stuff
->divisor_lo
, stuff
->divisor_hi
);
411 remainder
= vals_to_card64(stuff
->remainder_lo
, stuff
->remainder_hi
);
413 status
= DRI2SwapBuffers(client
, pDrawable
, target_msc
, divisor
, remainder
,
414 &swap_target
, DRI2SwapEvent
, pDrawable
);
415 if (status
!= Success
)
418 load_swap_reply(&rep
, swap_target
);
420 WriteToClient(client
, sizeof(xDRI2SwapBuffersReply
), &rep
);
426 load_msc_reply(xDRI2MSCReply
* rep
, CARD64 ust
, CARD64 msc
, CARD64 sbc
)
428 rep
->ust_hi
= ust
>> 32;
429 rep
->ust_lo
= ust
& 0xffffffff;
430 rep
->msc_hi
= msc
>> 32;
431 rep
->msc_lo
= msc
& 0xffffffff;
432 rep
->sbc_hi
= sbc
>> 32;
433 rep
->sbc_lo
= sbc
& 0xffffffff;
437 ProcDRI2GetMSC(ClientPtr client
)
439 REQUEST(xDRI2GetMSCReq
);
440 xDRI2MSCReply rep
= {
442 .sequenceNumber
= client
->sequence
,
445 DrawablePtr pDrawable
;
446 CARD64 ust
, msc
, sbc
;
449 REQUEST_SIZE_MATCH(xDRI2GetMSCReq
);
451 if (!validDrawable(client
, stuff
->drawable
, DixReadAccess
, &pDrawable
,
455 status
= DRI2GetMSC(pDrawable
, &ust
, &msc
, &sbc
);
456 if (status
!= Success
)
459 load_msc_reply(&rep
, ust
, msc
, sbc
);
461 WriteToClient(client
, sizeof(xDRI2MSCReply
), &rep
);
467 ProcDRI2WaitMSC(ClientPtr client
)
469 REQUEST(xDRI2WaitMSCReq
);
470 DrawablePtr pDrawable
;
471 CARD64 target
, divisor
, remainder
;
474 /* FIXME: in restart case, client may be gone at this point */
476 REQUEST_SIZE_MATCH(xDRI2WaitMSCReq
);
478 if (!validDrawable(client
, stuff
->drawable
, DixReadAccess
, &pDrawable
,
482 target
= vals_to_card64(stuff
->target_msc_lo
, stuff
->target_msc_hi
);
483 divisor
= vals_to_card64(stuff
->divisor_lo
, stuff
->divisor_hi
);
484 remainder
= vals_to_card64(stuff
->remainder_lo
, stuff
->remainder_hi
);
486 status
= DRI2WaitMSC(client
, pDrawable
, target
, divisor
, remainder
);
487 if (status
!= Success
)
494 ProcDRI2WaitMSCReply(ClientPtr client
, CARD64 ust
, CARD64 msc
, CARD64 sbc
)
496 xDRI2MSCReply rep
= {
498 .sequenceNumber
= client
->sequence
,
502 load_msc_reply(&rep
, ust
, msc
, sbc
);
504 WriteToClient(client
, sizeof(xDRI2MSCReply
), &rep
);
510 ProcDRI2SwapInterval(ClientPtr client
)
512 REQUEST(xDRI2SwapIntervalReq
);
513 DrawablePtr pDrawable
;
516 /* FIXME: in restart case, client may be gone at this point */
518 REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq
);
520 if (!validDrawable(client
, stuff
->drawable
, DixReadAccess
| DixWriteAccess
,
521 &pDrawable
, &status
))
524 DRI2SwapInterval(pDrawable
, stuff
->interval
);
530 ProcDRI2WaitSBC(ClientPtr client
)
532 REQUEST(xDRI2WaitSBCReq
);
533 DrawablePtr pDrawable
;
537 REQUEST_SIZE_MATCH(xDRI2WaitSBCReq
);
539 if (!validDrawable(client
, stuff
->drawable
, DixReadAccess
, &pDrawable
,
543 target
= vals_to_card64(stuff
->target_sbc_lo
, stuff
->target_sbc_hi
);
544 status
= DRI2WaitSBC(client
, pDrawable
, target
);
550 ProcDRI2GetParam(ClientPtr client
)
552 REQUEST(xDRI2GetParamReq
);
553 xDRI2GetParamReply rep
= {
555 .sequenceNumber
= client
->sequence
,
558 DrawablePtr pDrawable
;
562 REQUEST_SIZE_MATCH(xDRI2GetParamReq
);
564 if (!validDrawable(client
, stuff
->drawable
, DixReadAccess
,
565 &pDrawable
, &status
))
568 status
= DRI2GetParam(client
, pDrawable
, stuff
->param
,
569 &rep
.is_param_recognized
, &value
);
570 rep
.value_hi
= value
>> 32;
571 rep
.value_lo
= value
& 0xffffffff;
573 if (status
!= Success
)
576 WriteToClient(client
, sizeof(xDRI2GetParamReply
), &rep
);
582 ProcDRI2Dispatch(ClientPtr client
)
586 switch (stuff
->data
) {
587 case X_DRI2QueryVersion
:
588 return ProcDRI2QueryVersion(client
);
594 switch (stuff
->data
) {
596 return ProcDRI2Connect(client
);
597 case X_DRI2Authenticate
:
598 return ProcDRI2Authenticate(client
);
599 case X_DRI2CreateDrawable
:
600 return ProcDRI2CreateDrawable(client
);
601 case X_DRI2DestroyDrawable
:
602 return ProcDRI2DestroyDrawable(client
);
603 case X_DRI2GetBuffers
:
604 return ProcDRI2GetBuffers(client
);
605 case X_DRI2CopyRegion
:
606 return ProcDRI2CopyRegion(client
);
607 case X_DRI2GetBuffersWithFormat
:
608 return ProcDRI2GetBuffersWithFormat(client
);
609 case X_DRI2SwapBuffers
:
610 return ProcDRI2SwapBuffers(client
);
612 return ProcDRI2GetMSC(client
);
614 return ProcDRI2WaitMSC(client
);
616 return ProcDRI2WaitSBC(client
);
617 case X_DRI2SwapInterval
:
618 return ProcDRI2SwapInterval(client
);
620 return ProcDRI2GetParam(client
);
627 SProcDRI2Connect(ClientPtr client
)
629 REQUEST(xDRI2ConnectReq
);
630 xDRI2ConnectReply rep
= {
632 .sequenceNumber
= client
->sequence
,
634 .driverNameLength
= 0,
635 .deviceNameLength
= 0
638 /* If the client is swapped, it's not local. Talk to the hand. */
640 swaps(&stuff
->length
);
641 if (sizeof(*stuff
) / 4 != client
->req_len
)
644 swaps(&rep
.sequenceNumber
);
646 WriteToClient(client
, sizeof(xDRI2ConnectReply
), &rep
);
652 SProcDRI2Dispatch(ClientPtr client
)
657 * Only local clients are allowed DRI access, but remote clients
658 * still need these requests to find out cleanly.
660 switch (stuff
->data
) {
661 case X_DRI2QueryVersion
:
662 return ProcDRI2QueryVersion(client
);
664 return SProcDRI2Connect(client
);
671 DRI2ExtensionInit(void)
673 ExtensionEntry
*dri2Extension
;
676 if (!noPanoramiXExtension
)
680 dri2Extension
= AddExtension(DRI2_NAME
,
684 SProcDRI2Dispatch
, NULL
, StandardMinorOpcode
);
686 DRI2EventBase
= dri2Extension
->eventBase
;