1 From 1301542b17a9ea3cc185e24a3e40d33daa66e8ce Mon Sep 17 00:00:00 2001
2 From: Rob Clark <rob@ti.com>
3 Date: Tue, 15 Nov 2011 14:28:06 -0600
4 Subject: [PATCH] add dri2video
6 TODO:
7 + implement OSD support.. core should register damage and automatically
8 re-call ScheduleSwapVid..
9 + automatically re-call ScheduleSwapVid on dri2 drawable resize...
10 ---
11 hw/xfree86/dri2/dri2.c | 364 +++++++++++++++++++++++++++++++++++++--------
12 hw/xfree86/dri2/dri2.h | 127 ++++++++++++++++-
13 hw/xfree86/dri2/dri2ext.c | 214 +++++++++++++++++++++++++-
14 3 files changed, 632 insertions(+), 73 deletions(-)
16 Index: xserver/hw/xfree86/dri2/dri2.c
17 ===================================================================
18 --- xserver.orig/hw/xfree86/dri2/dri2.c 2012-02-22 11:04:26.000000000 +0100
19 +++ xserver/hw/xfree86/dri2/dri2.c 2012-02-22 16:32:28.000000000 +0100
20 @@ -91,6 +91,8 @@
21 int refcnt;
22 unsigned int numDrivers;
23 const char **driverNames;
24 + unsigned int numFormats;
25 + unsigned int *formats;
26 const char *deviceName;
27 int fd;
28 unsigned int lastSequence;
29 @@ -102,12 +104,29 @@
30 DRI2GetMSCProcPtr GetMSC;
31 DRI2ScheduleWaitMSCProcPtr ScheduleWaitMSC;
32 DRI2AuthMagicProcPtr AuthMagic;
33 + DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
34 + DRI2SwapLimitValidateProcPtr SwapLimitValidate;
35 + DRI2GetExtraBufferNamesProcPtr GetExtraBufferNames;
36 + DRI2CreateBufferVidProcPtr CreateBufferVid;
37 + DRI2ScheduleSwapVidProcPtr ScheduleSwapVid;
38 + DRI2SetAttributeProcPtr SetAttribute;
39 + DRI2GetAttributeProcPtr GetAttribute;
41 HandleExposuresProcPtr HandleExposures;
43 ConfigNotifyProcPtr ConfigNotify;
44 } DRI2ScreenRec;
46 +static Bool
47 +supports_video(DRI2ScreenPtr ds)
48 +{
49 + /* it would be easier if we had a way to track the driverType in the
50 + * DRI2DrawablePtr.. but the DRI2DrawablePtr isn't created at the
51 + * time of DRI2Connect()..
52 + */
53 + return ds && ds->numFormats && ds->CreateBufferVid && ds->ScheduleSwapVid;
54 +}
55 +
56 static DRI2ScreenPtr
57 DRI2GetScreen(ScreenPtr pScreen)
58 {
59 @@ -179,6 +198,7 @@
60 pPriv->last_swap_ust = 0;
61 list_init(&pPriv->reference_list);
62 pPriv->serialNumber = DRI2DrawableSerial(pDraw);
63 + pPriv->needInvalidate = FALSE;
65 if (pDraw->type == DRAWABLE_WINDOW) {
66 pWin = (WindowPtr) pDraw;
67 @@ -191,6 +211,35 @@
68 return pPriv;
69 }
71 +Bool
72 +DRI2SwapLimit(DrawablePtr pDraw, int swap_limit)
73 +{
74 + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
75 + DRI2ScreenPtr ds;
76 + if (!pPriv)
77 + return FALSE;
78 +
79 + ds = pPriv->dri2_screen;
80 +
81 + if (!ds->SwapLimitValidate
82 + || !ds->SwapLimitValidate(pDraw, swap_limit))
83 + return FALSE;
84 +
85 + pPriv->swap_limit = swap_limit;
86 +
87 + /* Check throttling */
88 + if (pPriv->swapsPending >= pPriv->swap_limit)
89 + return TRUE;
90 +
91 + if (pPriv->target_sbc == -1 && !pPriv->blockedOnMsc) {
92 + if (pPriv->blockedClient) {
93 + AttendClient(pPriv->blockedClient);
94 + pPriv->blockedClient = NULL;
95 + }
96 + }
97 +
98 + return TRUE;
99 +}
100 typedef struct DRI2DrawableRefRec {
101 XID id;
102 XID dri2_id;
103 @@ -264,15 +313,26 @@
104 return Success;
105 }
107 +static void destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr *buffers, int count)
108 +{
109 + if (buffers != NULL) {
110 + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
111 + int i;
112 + for (i = 0; i < count; i++)
113 + if (buffers[i])
114 + (*ds->DestroyBuffer)(pDraw, buffers[i]);
115 +
116 + free(buffers);
117 + }
118 +}
119 +
120 static int DRI2DrawableGone(pointer p, XID id)
121 {
122 DRI2DrawablePtr pPriv = p;
123 - DRI2ScreenPtr ds = pPriv->dri2_screen;
124 DRI2DrawableRefPtr ref, next;
125 WindowPtr pWin;
126 PixmapPtr pPixmap;
127 DrawablePtr pDraw;
128 - int i;
130 list_for_each_entry_safe(ref, next, &pPriv->reference_list, link) {
131 if (ref->dri2_id == id) {
132 @@ -304,12 +364,7 @@
133 dixSetPrivate(&pPixmap->devPrivates, dri2PixmapPrivateKey, NULL);
134 }
136 - if (pPriv->buffers != NULL) {
137 - for (i = 0; i < pPriv->bufferCount; i++)
138 - (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
139 -
140 - free(pPriv->buffers);
141 - }
142 + destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount);
144 free(pPriv);
146 @@ -317,7 +372,7 @@
147 }
149 static int
150 -find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
151 +find_attachment(DRI2DrawablePtr pPriv, unsigned attachment, DRI2BufferPtr *buf)
152 {
153 int i;
155 @@ -328,6 +383,8 @@
156 for (i = 0; i < pPriv->bufferCount; i++) {
157 if ((pPriv->buffers[i] != NULL)
158 && (pPriv->buffers[i]->attachment == attachment)) {
159 + if (buf)
160 + *buf = pPriv->buffers[i];
161 return i;
162 }
163 }
164 @@ -336,14 +393,27 @@
165 }
167 static Bool
168 +valid_format(DRI2ScreenPtr ds, unsigned int format)
169 +{
170 + int i;
171 + for (i = 0; i < ds->numFormats; i++) {
172 + if (format == ds->formats[i]) {
173 + return TRUE;
174 + }
175 + }
176 + return FALSE;
177 +}
178 +
179 +static Bool
180 allocate_or_reuse_buffer(DrawablePtr pDraw, DRI2ScreenPtr ds,
181 DRI2DrawablePtr pPriv,
182 unsigned int attachment, unsigned int format,
183 int dimensions_match, DRI2BufferPtr *buffer)
184 {
185 - int old_buf = find_attachment(pPriv, attachment);
186 + int old_buf = find_attachment(pPriv, attachment, NULL);
188 if ((old_buf < 0)
189 + || attachment == DRI2BufferFrontLeft
190 || !dimensions_match
191 || (pPriv->buffers[old_buf]->format != format)) {
192 *buffer = (*ds->CreateBuffer)(pDraw, attachment, format);
193 @@ -352,6 +422,8 @@
195 } else {
196 *buffer = pPriv->buffers[old_buf];
197 + if (ds->ReuseBufferNotify)
198 + (*ds->ReuseBufferNotify)(pDraw, *buffer);
199 pPriv->buffers[old_buf] = NULL;
200 return FALSE;
201 }
202 @@ -361,18 +433,7 @@
203 update_dri2_drawable_buffers(DRI2DrawablePtr pPriv, DrawablePtr pDraw,
204 DRI2BufferPtr *buffers, int out_count, int *width, int *height)
205 {
206 - DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
207 - int i;
208 -
209 - if (pPriv->buffers != NULL) {
210 - for (i = 0; i < pPriv->bufferCount; i++) {
211 - if (pPriv->buffers[i] != NULL) {
212 - (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
213 - }
214 - }
215 -
216 - free(pPriv->buffers);
217 - }
218 + destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount);
220 pPriv->buffers = buffers;
221 pPriv->bufferCount = out_count;
222 @@ -417,6 +478,15 @@
223 const unsigned attachment = *(attachments++);
224 const unsigned format = (has_format) ? *(attachments++) : 0;
226 + /* note: don't require a valid format for old drivers which don't
227 + * register their supported formats..
228 + */
229 + if (has_format && (ds->numFormats > 0) && !valid_format(ds, format)) {
230 + xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR,
231 + "[DRI2] %s: bad format: %d\n", __func__, format);
232 + goto err_out;
233 + }
234 +
235 if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
236 format, dimensions_match,
237 &buffers[i]))
238 @@ -506,19 +576,11 @@
240 *out_count = 0;
242 - if (buffers) {
243 - for (i = 0; i < count; i++) {
244 - if (buffers[i] != NULL)
245 - (*ds->DestroyBuffer)(pDraw, buffers[i]);
246 - }
247 + destroy_buffers(pDraw, buffers, count);
249 - free(buffers);
250 - buffers = NULL;
251 - }
252 + update_dri2_drawable_buffers(pPriv, pDraw, NULL, *out_count, width, height);
254 - update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, height);
255 -
256 - return buffers;
257 + return NULL;
258 }
260 DRI2BufferPtr *
261 @@ -537,6 +599,95 @@
262 out_count, TRUE);
263 }
265 +DRI2BufferPtr *
266 +DRI2GetBuffersVid(DrawablePtr pDraw, int width, int height,
267 + unsigned int *attachments, int count, int *out_count)
268 +{
269 + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
270 + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
271 + DRI2BufferPtr *buffers;
272 + int i, n = 0;
273 +
274 + if (!pPriv || !supports_video(ds)) {
275 + *out_count = 0;
276 + return NULL;
277 + }
278 +
279 + buffers = calloc(count, sizeof(buffers[0]));
280 + if (!buffers)
281 + goto err_out;
282 +
283 + for (i = 0; i < count; i++) {
284 + DRI2BufferPtr buf;
285 + const unsigned attachment = *(attachments++);
286 + const unsigned format = *(attachments++);
287 +
288 + /* grow array of stored buffers if needed: */
289 + if (attachment >= pPriv->bufferCount) {
290 + int n = attachment + 1;
291 + DRI2BufferPtr *newBuffers = realloc(pPriv->buffers,
292 + sizeof(pPriv->buffers[0]) * n);
293 + if (!newBuffers) {
294 + xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR,
295 + "[DRI2] %s: allocation failed for buffer: %d\n",
296 + __func__, attachment);
297 + goto err_out;
298 + }
299 + pPriv->buffers = newBuffers;
300 + memset(&pPriv->buffers[pPriv->bufferCount], 0,
301 + (n - pPriv->bufferCount) * sizeof(pPriv->buffers[0]));
302 + pPriv->bufferCount = n;
303 + }
304 +
305 + /* destroy any previous buffer at this attachment slot */
306 + if (pPriv->buffers[attachment]) {
307 + (*ds->DestroyBuffer)(pDraw, pPriv->buffers[attachment]);
308 + pPriv->buffers[attachment] = NULL;
309 + }
310 +
311 + if ((width == 0) && (height == 0)) {
312 + /* client just wanted us to delete the buffer */
313 + continue;
314 + }
315 +
316 + if (!valid_format(ds, format)) {
317 + xf86DrvMsg(pDraw->pScreen->myNum, X_ERROR,
318 + "[DRI2] %s: bad format: %d\n", __func__, format);
319 + goto err_out;
320 + }
321 +
322 + if (attachment == DRI2BufferFrontLeft) {
323 + buf = (*ds->CreateBuffer)(pDraw, attachment, format);
324 + /* note: don't expose front buffer to client */
325 + } else {
326 + buf = (*ds->CreateBufferVid)(pDraw, attachment, format, width, height);
327 + buffers[n++] = buf;
328 + }
329 +
330 + if (! buf) {
331 + goto err_out;
332 + }
333 +
334 + pPriv->buffers[attachment] = buf;
335 + }
336 +
337 + *out_count = n;
338 +
339 + return buffers;
340 +
341 +err_out:
342 +
343 + *out_count = 0;
344 +
345 + for (i = 0; i < n; i++)
346 + if (buffers[i])
347 + pPriv->buffers[buffers[i]->attachment] = NULL;
348 +
349 + destroy_buffers(pDraw, buffers, n);
350 +
351 + return NULL;
352 +}
353 +
354 static void
355 DRI2InvalidateDrawable(DrawablePtr pDraw)
356 {
357 @@ -549,7 +700,7 @@
358 pPriv->needInvalidate = FALSE;
360 list_for_each_entry(ref, &pPriv->reference_list, link)
361 - ref->invalidate(pDraw, ref->priv);
362 + ref->invalidate(pDraw, ref->priv, ref->id);
363 }
365 /*
366 @@ -609,22 +760,14 @@
367 {
368 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
369 DRI2DrawablePtr pPriv;
370 - DRI2BufferPtr pDestBuffer, pSrcBuffer;
371 - int i;
372 + DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
374 pPriv = DRI2GetDrawable(pDraw);
375 if (pPriv == NULL)
376 return BadDrawable;
378 - pDestBuffer = NULL;
379 - pSrcBuffer = NULL;
380 - for (i = 0; i < pPriv->bufferCount; i++)
381 - {
382 - if (pPriv->buffers[i]->attachment == dest)
383 - pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
384 - if (pPriv->buffers[i]->attachment == src)
385 - pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
386 - }
387 + find_attachment(pPriv, dest, &pDestBuffer);
388 + find_attachment(pPriv, src, &pSrcBuffer);
389 if (pSrcBuffer == NULL || pDestBuffer == NULL)
390 return BadValue;
392 @@ -792,31 +935,41 @@
393 return FALSE;
394 }
396 -int
397 -DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
398 - CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
399 - DRI2SwapEventPtr func, void *data)
400 +/*
401 + * A TraverseTree callback to invalidate all windows using the same
402 + * pixmap
403 + */
404 +static int
405 +DRI2InvalidateWalk(WindowPtr pWin, pointer data)
406 +{
407 + if (pWin->drawable.pScreen->GetWindowPixmap(pWin) != data)
408 + return WT_DONTWALKCHILDREN;
409 + DRI2InvalidateDrawable(&pWin->drawable);
410 + return WT_WALKCHILDREN;
411 +}
412 +
413 +static int
414 +swap_buffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
415 + CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
416 + DRI2SwapEventPtr func, void *data,
417 + Bool vid, unsigned int source, BoxPtr b)
418 {
419 ScreenPtr pScreen = pDraw->pScreen;
420 DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
421 - DRI2DrawablePtr pPriv;
422 + DRI2DrawablePtr pPriv = DRI2GetDrawable(pDraw);
423 DRI2BufferPtr pDestBuffer = NULL, pSrcBuffer = NULL;
424 - int ret, i;
425 + int ret;
426 CARD64 ust, current_msc;
428 - pPriv = DRI2GetDrawable(pDraw);
429 - if (pPriv == NULL) {
430 + if ((pPriv == NULL) || (vid && !supports_video(ds))) {
431 xf86DrvMsg(pScreen->myNum, X_ERROR,
432 "[DRI2] %s: bad drawable\n", __func__);
433 return BadDrawable;
434 }
436 - for (i = 0; i < pPriv->bufferCount; i++) {
437 - if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
438 - pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
439 - if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
440 - pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
441 - }
442 + find_attachment(pPriv, DRI2BufferFrontLeft, &pDestBuffer);
443 + find_attachment(pPriv, source, &pSrcBuffer);
444 +
445 if (pSrcBuffer == NULL || pDestBuffer == NULL) {
446 xf86DrvMsg(pScreen->myNum, X_ERROR,
447 "[DRI2] %s: drawable has no back or front?\n", __func__);
448 @@ -824,7 +977,7 @@
449 }
451 /* Old DDX or no swap interval, just blit */
452 - if (!ds->ScheduleSwap || !pPriv->swap_interval) {
453 + if ((!ds->ScheduleSwap || !pPriv->swap_interval) && !vid) {
454 BoxRec box;
455 RegionRec region;
457 @@ -860,7 +1013,6 @@
459 if (current_msc < pPriv->last_swap_target)
460 pPriv->last_swap_target = current_msc;
461 -
462 }
464 /*
465 @@ -876,8 +1028,14 @@
466 }
468 pPriv->swapsPending++;
469 - ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
470 - swap_target, divisor, remainder, func, data);
471 + if (vid) {
472 + DrawablePtr osd = NULL; // TODO
473 + ret = (*ds->ScheduleSwapVid)(client, pDraw, pDestBuffer, pSrcBuffer,
474 + b, osd, swap_target, divisor, remainder, func, data);
475 + } else {
476 + ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
477 + swap_target, divisor, remainder, func, data);
478 + }
479 if (!ret) {
480 pPriv->swapsPending--; /* didn't schedule */
481 xf86DrvMsg(pScreen->myNum, X_ERROR,
482 @@ -892,11 +1050,50 @@
483 */
484 *swap_target = pPriv->swap_count + pPriv->swapsPending;
486 + if (vid) {
487 + return Success;
488 + }
489 +
490 + if (pDraw->type == DRAWABLE_WINDOW) {
491 + WindowPtr pWin = (WindowPtr) pDraw;
492 + PixmapPtr pPixmap = pScreen->GetWindowPixmap(pWin);
493 +
494 + /*
495 + * Find the top-most window using this pixmap
496 + */
497 + while (pWin->parent && pScreen->GetWindowPixmap(pWin->parent) == pPixmap)
498 + pWin = pWin->parent;
499 +
500 + /*
501 + * Walk the sub-tree to invalidate all of the
502 + * windows using the same pixmap
503 + */
504 + TraverseTree(pWin, DRI2InvalidateWalk, pPixmap);
505 + DRI2InvalidateDrawable(&pPixmap->drawable);
506 + } else
507 DRI2InvalidateDrawable(pDraw);
509 return Success;
510 }
512 +int
513 +DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
514 + CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
515 + DRI2SwapEventPtr func, void *data)
516 +{
517 + return swap_buffers(client, pDraw, target_msc, divisor, remainder,
518 + swap_target, func, data, FALSE, DRI2BufferBackLeft, NULL);
519 +}
520 +
521 +int
522 +DRI2SwapBuffersVid(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
523 + CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
524 + unsigned int source, BoxPtr b, DRI2SwapEventPtr func, void *data)
525 +{
526 + return swap_buffers(client, pDraw, target_msc, divisor, remainder,
527 + swap_target, func, data, TRUE, source, b);
528 +}
529 +
530 void
531 DRI2SwapInterval(DrawablePtr pDrawable, int interval)
532 {
533 @@ -1014,6 +1211,77 @@
534 return ds->ScheduleSwap && ds->GetMSC;
535 }
537 +#define ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
538 +
539 +/* length in multiple of CARD32's, passed in value should be copied by
540 + * receiver
541 + */
542 +int
543 +DRI2SetAttribute(DrawablePtr pDraw, Atom attribute, int len, const CARD32 *val)
544 +{
545 + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
546 + int ret = BadMatch;
547 +
548 + if (!supports_video(ds)) {
549 + return BadDrawable;
550 + }
551 +
552 + if (attribute == ATOM("XV_OSD")) {
553 + } else if (ds->SetAttribute) {
554 + ret = (*ds->SetAttribute)(pDraw, attribute, len, val);
555 + }
556 +
557 + return ret;
558 +}
559 +
560 +/* length in multiple of CARD32's, returned val should *not* be free'd
561 + * (unlike similar function on client side) to avoid temporary allocation
562 + * and extra copy.
563 + */
564 +int
565 +DRI2GetAttribute(DrawablePtr pDraw, Atom attribute, int *len, const CARD32 **val)
566 +{
567 + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
568 + int ret = BadMatch;
569 +
570 + if (!supports_video(ds)) {
571 + return BadDrawable;
572 + }
573 +
574 + if (attribute == ATOM("XV_OSD")) {
575 + } else if (ds->GetAttribute) {
576 + ret = (*ds->GetAttribute)(pDraw, attribute, len, val);
577 + }
578 +
579 + return ret;
580 +}
581 +
582 +int
583 +DRI2GetFormats(ScreenPtr pScreen, unsigned int *nformats, unsigned int **formats)
584 +{
585 + DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
586 +
587 + if (! supports_video(ds)) {
588 + return BadDrawable;
589 + }
590 +
591 + *nformats = ds->numFormats;
592 + *formats = ds->formats;
593 +
594 + return Success;
595 +}
596 +
597 +unsigned int
598 +DRI2GetExtraBufferNames(DrawablePtr pDraw, DRI2BufferPtr buf,
599 + unsigned int **names, unsigned int **pitches)
600 +{
601 + DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
602 + if (ds->GetExtraBufferNames) {
603 + return (*ds->GetExtraBufferNames)(pDraw, buf, names, pitches);
604 + }
605 + return 0;
606 +}
607 +
608 Bool
609 DRI2Connect(ScreenPtr pScreen, unsigned int driverType, int *fd,
610 const char **driverName, const char **deviceName)
611 @@ -1081,9 +1349,10 @@
612 const char* driverTypeNames[] = {
613 "DRI", /* DRI2DriverDRI */
614 "VDPAU", /* DRI2DriverVDPAU */
615 + "XV", /* DRI2DriverXV */
616 };
617 unsigned int i;
618 - CARD8 cur_minor;
619 + CARD8 cur_minor = 1;
621 if (info->version < 3)
622 return FALSE;
623 @@ -1121,14 +1390,45 @@
624 ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
625 ds->GetMSC = info->GetMSC;
626 cur_minor = 3;
627 - } else {
628 - cur_minor = 1;
629 }
631 if (info->version >= 5) {
632 ds->AuthMagic = info->AuthMagic;
633 }
635 + if (info->version >= 6) {
636 + ds->ReuseBufferNotify = info->ReuseBufferNotify;
637 + ds->SwapLimitValidate = info->SwapLimitValidate;
638 + }
639 +
640 + if (info->version >= 7) {
641 + if ((info->numDrivers > DRI2DriverXV) &&
642 + info->driverNames[DRI2DriverXV]) {
643 + /* if driver claims to support DRI2DriverXV, then ensure
644 + * it provides the required fxn ptrs:
645 + */
646 + if (!info->CreateBufferVid || !info->ScheduleSwapVid) {
647 + xf86DrvMsg(pScreen->myNum, X_WARNING,
648 + "[DRI2] DRI2DriverXV must implement "
649 + "CreateBuffersVid and ScheduleSwapVid.\n");
650 + goto err_out;
651 + }
652 + }
653 + ds->numFormats = info->numFormats;
654 + ds->formats = malloc(info->numFormats * sizeof(*ds->formats));
655 + if (!ds->formats)
656 + goto err_out;
657 + memcpy(ds->formats, info->formats,
658 + info->numFormats * sizeof(*ds->formats));
659 + ds->GetExtraBufferNames = info->GetExtraBufferNames;
660 + ds->CreateBufferVid = info->CreateBufferVid;
661 + ds->ScheduleSwapVid = info->ScheduleSwapVid;
662 + ds->SetAttribute = info->SetAttribute;
663 + ds->GetAttribute = info->GetAttribute;
664 +
665 + cur_minor = 4;
666 + }
667 +
668 /*
669 * if the driver doesn't provide an AuthMagic function or the info struct
670 * version is too low, it relies on the old method (using libdrm) or fail
671 @@ -1178,6 +1478,10 @@
672 err_out:
673 xf86DrvMsg(pScreen->myNum, X_WARNING,
674 "[DRI2] Initialization failed for info version %d.\n", info->version);
675 + if (ds) {
676 + free(ds->formats);
677 + free(ds->driverNames);
678 + }
679 free(ds);
680 return FALSE;
681 }
682 Index: xserver/hw/xfree86/dri2/dri2.h
683 ===================================================================
684 --- xserver.orig/hw/xfree86/dri2/dri2.h 2012-02-22 11:04:26.000000000 +0100
685 +++ xserver/hw/xfree86/dri2/dri2.h 2012-02-22 16:31:43.000000000 +0100
686 @@ -104,12 +104,73 @@
687 CARD64 remainder,
688 DRI2SwapEventPtr func,
689 void *data);
690 +
691 +/**
692 + * Schedule a video buffer swap
693 + *
694 + * Drivers should queue an event for the frame count that satisfies the
695 + * parameters passed in. If the event is in the future (i.e. the conditions
696 + * aren't currently satisfied), the server may block the client at the next
697 + * GLX request using DRI2WaitSwap. When the event arrives, drivers should call
698 + * \c DRI2SwapComplete, which will handle waking the client and returning
699 + * the appropriate data.
700 + *
701 + * The DDX is responsible for doing an overlay buffer flip/exchange, or
702 + * scaling/colorconvert blit when the corresponding event arrives.
703 + *
704 + * If the target drawable is resized/damaged, or the osd pixmap is changed/
705 + * damaged, ScheduleSwapVid can be re-invoked by the core with the same
706 + * source buffer to repair the dri2 video drawable.
707 + * XXX TODO this part isn't implemented in core yet..
708 + *
709 + * \param client client pointer (used for block/unblock)
710 + * \param pDraw drawable whose count we want
711 + * \param pDestBuffer current front buffer
712 + * \param pSrcBuffer current back buffer
713 + * \param b the crop box
714 + * \param osd the on-screen-display overlay pixmap, should be an ARGB pixmap
715 + * that is blended on top of the video as part of swap. Multiple layers
716 + * to blend over the video should be flattened into a single layer by the
717 + * client
718 + * \param target_msc frame count to wait for
719 + * \param divisor divisor for condition equation
720 + * \param remainder remainder for division equation
721 + * \param func function to call when the swap completes
722 + * \param data data for the callback \p func.
723 + */
724 +typedef int (*DRI2ScheduleSwapVidProcPtr)(ClientPtr client,
725 + DrawablePtr pDraw,
726 + DRI2BufferPtr pDestBuffer,
727 + DRI2BufferPtr pSrcBuffer,
728 + BoxPtr b,
729 + DrawablePtr osd,
730 + CARD64 *target_msc,
731 + CARD64 divisor,
732 + CARD64 remainder,
733 + DRI2SwapEventPtr func,
734 + void *data);
735 +
736 typedef DRI2BufferPtr (*DRI2CreateBufferProcPtr)(DrawablePtr pDraw,
737 unsigned int attachment,
738 unsigned int format);
739 +typedef DRI2BufferPtr (*DRI2CreateBufferVidProcPtr)(DrawablePtr pDraw,
740 + unsigned int attachment,
741 + unsigned int format,
742 + unsigned int width,
743 + unsigned int height);
744 typedef void (*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw,
745 DRI2BufferPtr buffer);
746 /**
747 + * Notifies driver when DRI2GetBuffers reuses a dri2 buffer.
748 + *
749 + * Driver may rename the dri2 buffer in this notify if it is required.
750 + *
751 + * \param pDraw drawable whose count we want
752 + * \param buffer buffer that will be returned to client
753 + */
754 +typedef void (*DRI2ReuseBufferNotifyProcPtr)(DrawablePtr pDraw,
755 + DRI2BufferPtr buffer);
756 +/**
757 * Get current media stamp counter values
758 *
759 * This callback is used to support the SGI_video_sync and OML_sync_control
760 @@ -156,12 +217,62 @@
761 CARD64 remainder);
763 typedef void (*DRI2InvalidateProcPtr)(DrawablePtr pDraw,
764 - void *data);
765 + void *data,
766 + XID id);
767 +
768 +/**
769 + * DRI2 calls this hook when ever swap_limit is going to be changed. Default
770 + * implementation for the hook only accepts one as swap_limit. If driver can
771 + * support other swap_limits it has to implement supported limits with this
772 + * callback.
773 + *
774 + * \param pDraw drawable whos swap_limit is going to be changed
775 + * \param swap_limit new swap_limit that going to be set
776 + * \return TRUE if limit is support, FALSE if not.
777 + */
778 +typedef Bool (*DRI2SwapLimitValidateProcPtr)(DrawablePtr pDraw,
779 + int swap_limit);
780 +
781 +
782 +/**
783 + * An ugly approach to avoid changing DRI2BufferPtr and cause ABI breakage
784 + * between driver and xserver. This only needs to be implemented by drivers
785 + * supporting planar formats with one buffer per plane.
786 + *
787 + * This might be a good argument for having drivers in-tree ;-)
788 + *
789 + * \param pDraw drawable that the buffer belongs to
790 + * \param buf the DRI2 buffer
791 + * \param names array of buffer names
792 + * \param pitches array of buffer pitches
793 + * \return the number of additional buffers, ie. for I420 tri-planar buffer,
794 + * if represented as multiple buffer names, the Y buffer name would be in
795 + * buf->name, this function would return 2, and return the U and V buffer
796 + * names by reference.
797 + */
798 +typedef unsigned int (*DRI2GetExtraBufferNamesProcPtr)(DrawablePtr pDraw,
799 + DRI2BufferPtr buf, unsigned int **names, unsigned int **pitches);
800 +
801 +/**
802 + * Length in multiple of CARD32's, passed in value should be copied by
803 + * receiver
804 + */
805 +typedef int (*DRI2SetAttributeProcPtr)(DrawablePtr pDraw, Atom attribute,
806 + int len, const CARD32 *val);
807 +
808 +/**
809 + * Length in multiple of CARD32's, returned val should *not* be free'd
810 + * (unlike similar function on client side) to avoid temporary allocation
811 + * and extra copy.
812 + */
813 +typedef int (*DRI2GetAttributeProcPtr)(DrawablePtr pDraw, Atom attribute,
814 + int *len, const CARD32 **val);
815 +
817 /**
818 * Version of the DRI2InfoRec structure defined in this header
819 */
820 -#define DRI2INFOREC_VERSION 5
821 +#define DRI2INFOREC_VERSION 7
823 typedef struct {
824 unsigned int version; /**< Version of this struct */
825 @@ -189,6 +300,20 @@
826 /* added in version 5 */
828 DRI2AuthMagicProcPtr AuthMagic;
829 + /* added in version 6 */
830 +
831 + DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
832 + DRI2SwapLimitValidateProcPtr SwapLimitValidate;
833 +
834 + /* added in version 7 */
835 +
836 + unsigned int numFormats;
837 + const unsigned int *formats;
838 + DRI2GetExtraBufferNamesProcPtr GetExtraBufferNames;
839 + DRI2CreateBufferVidProcPtr CreateBufferVid;
840 + DRI2ScheduleSwapVidProcPtr ScheduleSwapVid;
841 + DRI2SetAttributeProcPtr SetAttribute;
842 + DRI2GetAttributeProcPtr GetAttribute;
843 } DRI2InfoRec, *DRI2InfoPtr;
845 extern _X_EXPORT int DRI2EventBase;
846 @@ -250,11 +375,19 @@
847 int *width, int *height, unsigned int *attachments, int count,
848 int *out_count);
850 +extern _X_EXPORT DRI2BufferPtr * DRI2GetBuffersVid(DrawablePtr pDraw,
851 + int width, int height, unsigned int *attachments, int count,
852 + int *out_count);
853 +
854 extern _X_EXPORT void DRI2SwapInterval(DrawablePtr pDrawable, int interval);
855 +extern _X_EXPORT Bool DRI2SwapLimit(DrawablePtr pDraw, int swap_limit);
856 extern _X_EXPORT int DRI2SwapBuffers(ClientPtr client, DrawablePtr pDrawable,
857 CARD64 target_msc, CARD64 divisor,
858 CARD64 remainder, CARD64 *swap_target,
859 DRI2SwapEventPtr func, void *data);
860 +extern _X_EXPORT int DRI2SwapBuffersVid(ClientPtr client, DrawablePtr pDraw,
861 + CARD64 target_msc, CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
862 + unsigned int source, BoxPtr b, DRI2SwapEventPtr func, void *data);
863 extern _X_EXPORT Bool DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable);
865 extern _X_EXPORT int DRI2GetMSC(DrawablePtr pDrawable, CARD64 *ust,
866 @@ -284,4 +417,22 @@
867 int frame, unsigned int tv_sec,
868 unsigned int tv_usec);
870 +extern _X_EXPORT int DRI2SetAttribute(DrawablePtr pDraw, Atom attribute,
871 + int len, const CARD32 *val);
872 +extern _X_EXPORT int DRI2GetAttribute(DrawablePtr pDraw, Atom attribute,
873 + int *len, const CARD32 **val);
874 +extern _X_EXPORT int DRI2GetFormats(ScreenPtr pScreen,
875 + unsigned int *nformats, unsigned int **formats);
876 +
877 +extern _X_EXPORT unsigned int DRI2GetExtraBufferNames(DrawablePtr pDraw,
878 + DRI2BufferPtr buf, unsigned int **names, unsigned int **pitches);
879 +
880 +
881 +/* some utility macros.. maybe could go elsewhere? */
882 +#define FOURCC(a, b, c, d) (((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 )))
883 +#define FOURCC_STR(str) FOURCC(str[0], str[1], str[2], str[3])
884 +#ifndef ARRAY_SIZE
885 +# define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0]))
886 +#endif
887 +
888 #endif
889 Index: xserver/hw/xfree86/dri2/dri2ext.c
890 ===================================================================
891 --- xserver.orig/hw/xfree86/dri2/dri2ext.c 2012-02-22 11:04:26.000000000 +0100
892 +++ xserver/hw/xfree86/dri2/dri2ext.c 2012-02-22 16:37:21.000000000 +0100
893 @@ -78,6 +78,7 @@
894 swaps(&stuff->length, n);
896 REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
897 +
898 rep.type = X_Reply;
899 rep.length = 0;
900 rep.sequenceNumber = client->sequence;
901 @@ -157,7 +158,7 @@
902 }
904 static void
905 -DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv)
906 +DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv, XID id)
907 {
908 xDRI2InvalidateBuffers event;
909 ClientPtr client = priv;
910 @@ -206,12 +207,13 @@
913 static int
914 -send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
915 +send_buffers_reply(ClientPtr client, DrawablePtr pDrawable, int vid,
916 DRI2BufferPtr *buffers, int count, int width, int height)
917 {
918 xDRI2GetBuffersReply rep;
919 - int skip = 0;
920 - int i;
921 + int skip = 0, extra = 0;
922 + unsigned int *names, *pitches;
923 + int i, j;
925 if (buffers == NULL)
926 return BadAlloc;
927 @@ -227,8 +229,24 @@
928 }
929 }
931 + if (vid) {
932 + extra = 4 * (count - skip);
933 +
934 + for (i = 0; i < count; i++) {
935 + /* Do not send the real front buffer of a window to the client.
936 + */
937 + if ((pDrawable->type == DRAWABLE_WINDOW)
938 + && (buffers[i]->attachment == DRI2BufferFrontLeft)) {
939 + continue;
940 + }
941 +
942 + extra += 8 * DRI2GetExtraBufferNames(pDrawable, buffers[i],
943 + &names, &pitches);
944 + }
945 + }
946 +
947 rep.type = X_Reply;
948 - rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4;
949 + rep.length = ((count - skip) * sizeof(xDRI2Buffer) + extra) / 4;
950 rep.sequenceNumber = client->sequence;
951 rep.width = width;
952 rep.height = height;
953 @@ -251,6 +269,17 @@
954 buffer.cpp = buffers[i]->cpp;
955 buffer.flags = buffers[i]->flags;
956 WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
957 +
958 + if (vid) {
959 + CARD32 n = DRI2GetExtraBufferNames(pDrawable, buffers[i],
960 + &names, &pitches);
961 + WriteToClient(client, sizeof(n), &n);
962 + for (j = 0; j < n; j++) {
963 + CARD32 name = names[j], pitch = pitches[j];
964 + WriteToClient(client, sizeof(name), &name);
965 + WriteToClient(client, sizeof(pitch), &pitch);
966 + }
967 + }
968 }
969 return Success;
970 }
971 @@ -278,8 +307,8 @@
972 attachments, stuff->count, &count);
975 - return send_buffers_reply(client, pDrawable, buffers, count, width, height);
976 -
977 + return send_buffers_reply(client, pDrawable, FALSE,
978 + buffers, count, width, height);
979 }
981 static int
982 @@ -303,7 +332,40 @@
983 buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
984 attachments, stuff->count, &count);
986 - return send_buffers_reply(client, pDrawable, buffers, count, width, height);
987 + return send_buffers_reply(client, pDrawable, FALSE,
988 + buffers, count, width, height);
989 +}
990 +
991 +static int
992 +ProcDRI2GetBuffersVid(ClientPtr client)
993 +{
994 + REQUEST(xDRI2GetBuffersVidReq);
995 + DrawablePtr pDrawable;
996 + DRI2BufferPtr *buffers;
997 + int status, count;
998 + unsigned int *attachments;
999 +
1000 + REQUEST_FIXED_SIZE(xDRI2GetBuffersVidReq, stuff->count * (2 * 4));
1001 + if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
1002 + &pDrawable, &status))
1003 + return status;
1004 +
1005 + if (DRI2ThrottleClient(client, pDrawable))
1006 + return Success;
1007 +
1008 + attachments = (unsigned int *) &stuff[1];
1009 + buffers = DRI2GetBuffersVid(pDrawable, stuff->width, stuff->height,
1010 + attachments, stuff->count, &count);
1011 +
1012 + status = send_buffers_reply(client, pDrawable, TRUE, buffers, count, 0, 0);
1013 +
1014 + /* note, unlike other DRI2GetBuffers variants, we allow requesting/
1015 + * returning just a subset of buffers.. so array that is returned is
1016 + * not the one held in pPriv, so must be free'd
1017 + */
1018 + free(buffers);
1019 +
1020 + return status;
1021 }
1023 static int
1024 @@ -416,6 +478,53 @@
1025 return Success;
1026 }
1028 +static int
1029 +ProcDRI2SwapBuffersVid(ClientPtr client)
1030 +{
1031 + REQUEST(xDRI2SwapBuffersVidReq);
1032 + xDRI2SwapBuffersReply rep;
1033 + DrawablePtr pDrawable;
1034 + CARD64 target_msc, divisor, remainder, swap_target;
1035 + BoxRec b;
1036 + int status;
1037 +
1038 + REQUEST_SIZE_MATCH(xDRI2SwapBuffersVidReq);
1039 +
1040 + if (!validDrawable(client, stuff->drawable,
1041 + DixReadAccess | DixWriteAccess, &pDrawable, &status))
1042 + return status;
1043 +
1044 + /*
1045 + * Ensures an out of control client can't exhaust our swap queue, and
1046 + * also orders swaps.
1047 + */
1048 + if (DRI2ThrottleClient(client, pDrawable))
1049 + return Success;
1050 +
1051 + target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
1052 + divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
1053 + remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
1054 +
1055 + b.x1 = stuff->x1;
1056 + b.y1 = stuff->y1;
1057 + b.x2 = stuff->x2;
1058 + b.y2 = stuff->y2;
1059 +
1060 + status = DRI2SwapBuffersVid(client, pDrawable, target_msc, divisor, remainder,
1061 + &swap_target, stuff->source, &b, DRI2SwapEvent, pDrawable);
1062 + if (status != Success)
1063 + return BadDrawable;
1064 +
1065 + rep.type = X_Reply;
1066 + rep.length = 0;
1067 + rep.sequenceNumber = client->sequence;
1068 + load_swap_reply(&rep, swap_target);
1069 +
1070 + WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
1071 +
1072 + return Success;
1073 +}
1074 +
1075 static void
1076 load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc)
1077 {
1078 @@ -539,6 +648,87 @@
1079 }
1081 static int
1082 +ProcDRI2SetAttribute(ClientPtr client)
1083 +{
1084 + REQUEST(xDRI2SetAttributeReq);
1085 + DrawablePtr pDrawable;
1086 + int status;
1087 + int len = (stuff->length * 4 - sizeof(xDRI2SetAttributeReq)) / 4;
1088 +
1089 + REQUEST_FIXED_SIZE(xDRI2SetAttributeReq, len * 4);
1090 +
1091 + if (!validDrawable(client, stuff->drawable,
1092 + DixReadAccess | DixWriteAccess, &pDrawable, &status))
1093 + return status;
1094 +
1095 + status = DRI2SetAttribute(pDrawable, stuff->attribute, len,
1096 + (const CARD32 *)&stuff[1]);
1097 + if (status != Success)
1098 + return status;
1099 +
1100 + return Success;
1101 +}
1102 +
1103 +static int
1104 +ProcDRI2GetAttribute(ClientPtr client)
1105 +{
1106 + REQUEST(xDRI2GetAttributeReq);
1107 + xDRI2GetAttributeReply rep;
1108 + DrawablePtr pDrawable;
1109 + const CARD32 *val;
1110 + int status, len;
1111 +
1112 + REQUEST_SIZE_MATCH(xDRI2GetAttributeReq);
1113 +
1114 + if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
1115 + &status))
1116 + return status;
1117 +
1118 + status = DRI2GetAttribute(pDrawable, stuff->attribute, &len, &val);
1119 + if (status != Success)
1120 + return status;
1121 +
1122 + rep.type = X_Reply;
1123 + rep.length = len;
1124 + rep.sequenceNumber = client->sequence;
1125 + WriteToClient(client, sizeof(xDRI2GetAttributeReply), &rep);
1126 + WriteToClient(client, len * 4, val);
1127 +
1128 + return Success;
1129 +}
1130 +
1131 +static int
1132 +ProcDRI2GetFormats(ClientPtr client)
1133 +{
1134 + REQUEST(xDRI2GetFormatsReq);
1135 + xDRI2GetFormatsReply rep;
1136 + DrawablePtr pDrawable;
1137 + unsigned int i, nformats, *formats;
1138 + int status;
1139 +
1140 + REQUEST_SIZE_MATCH(xDRI2GetFormatsReq);
1141 +
1142 + if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
1143 + &status))
1144 + return status;
1145 +
1146 + status = DRI2GetFormats(pDrawable->pScreen, &nformats, &formats);
1147 + if (status != Success)
1148 + return status;
1149 +
1150 + rep.type = X_Reply;
1151 + rep.length = nformats * sizeof(*formats) / 4;
1152 + rep.sequenceNumber = client->sequence;
1153 + WriteToClient(client, sizeof(xDRI2GetFormatsReply), &rep);
1154 +
1155 + for (i = 0; i < nformats; i++) {
1156 + WriteToClient(client, sizeof(formats[i]), &formats[i]);
1157 + }
1158 +
1159 + return Success;
1160 +}
1161 +
1162 +static int
1163 ProcDRI2Dispatch (ClientPtr client)
1164 {
1165 REQUEST(xReq);
1166 @@ -576,6 +766,16 @@
1167 return ProcDRI2WaitSBC(client);
1168 case X_DRI2SwapInterval:
1169 return ProcDRI2SwapInterval(client);
1170 + case X_DRI2GetBuffersVid:
1171 + return ProcDRI2GetBuffersVid(client);
1172 + case X_DRI2SwapBuffersVid:
1173 + return ProcDRI2SwapBuffersVid(client);
1174 + case X_DRI2SetAttribute:
1175 + return ProcDRI2SetAttribute(client);
1176 + case X_DRI2GetAttribute:
1177 + return ProcDRI2GetAttribute(client);
1178 + case X_DRI2GetFormats:
1179 + return ProcDRI2GetFormats(client);
1180 default:
1181 return BadRequest;
1182 }