Added DRI2 Video Support
[glsdk/xserver.git] / debian / patches / 0001-add-dri2video.patch
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;
40  
41      HandleExposuresProcPtr       HandleExposures;
42  
43      ConfigNotifyProcPtr                 ConfigNotify;
44  } DRI2ScreenRec;
45  
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;
64  
65      if (pDraw->type == DRAWABLE_WINDOW) {
66         pWin = (WindowPtr) pDraw;
67 @@ -191,6 +211,35 @@
68      return pPriv;
69  }
70  
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  }
106  
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]);
116 +       free(buffers);
117 +    }
118 +}
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;
129  
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      }
135  
136 -    if (pPriv->buffers != NULL) {
137 -       for (i = 0; i < pPriv->bufferCount; i++)
138 -           (*ds->DestroyBuffer)(pDraw, pPriv->buffers[i]);
140 -       free(pPriv->buffers);
141 -    }
142 +    destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount);
143  
144      free(pPriv);
145  
146 @@ -317,7 +372,7 @@
147  }
148  
149  static int
150 -find_attachment(DRI2DrawablePtr pPriv, unsigned attachment)
151 +find_attachment(DRI2DrawablePtr pPriv, unsigned attachment, DRI2BufferPtr *buf)
152  {
153      int i;
154  
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  }
166  
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 +}
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);
187  
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 @@
194  
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;
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 -       }
216 -       free(pPriv->buffers);
217 -    }
218 +    destroy_buffers(pDraw, pPriv->buffers, pPriv->bufferCount);
219  
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;
225  
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 +       }
235         if (allocate_or_reuse_buffer(pDraw, ds, pPriv, attachment,
236                                      format, dimensions_match,
237                                      &buffers[i]))
238 @@ -506,19 +576,11 @@
239  
240      *out_count = 0;
241  
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);
248  
249 -       free(buffers);
250 -       buffers = NULL;
251 -    }
252 +    update_dri2_drawable_buffers(pPriv, pDraw, NULL, *out_count, width, height);
253  
254 -    update_dri2_drawable_buffers(pPriv, pDraw, buffers, *out_count, width, height);
256 -    return buffers;
257 +    return NULL;
258  }
259  
260  DRI2BufferPtr *
261 @@ -537,6 +599,95 @@
262                           out_count, TRUE);
263  }
264  
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;
274 +    if (!pPriv || !supports_video(ds)) {
275 +       *out_count = 0;
276 +       return NULL;
277 +    }
279 +    buffers = calloc(count, sizeof(buffers[0]));
280 +    if (!buffers)
281 +       goto err_out;
283 +    for (i = 0; i < count; i++) {
284 +       DRI2BufferPtr buf;
285 +       const unsigned attachment = *(attachments++);
286 +       const unsigned format = *(attachments++);
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 +       }
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 +       }
311 +       if ((width == 0) && (height == 0)) {
312 +           /* client just wanted us to delete the buffer */
313 +           continue;
314 +       }
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 +       }
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 +       }
330 +       if (! buf) {
331 +           goto err_out;
332 +       }
334 +       pPriv->buffers[attachment] = buf;
335 +    }
337 +    *out_count = n;
339 +    return buffers;
341 +err_out:
343 +    *out_count = 0;
345 +    for (i = 0; i < n; i++)
346 +       if (buffers[i])
347 +           pPriv->buffers[buffers[i]->attachment] = NULL;
349 +    destroy_buffers(pDraw, buffers, n);
351 +    return NULL;
352 +}
354  static void
355  DRI2InvalidateDrawable(DrawablePtr pDraw)
356  {
357 @@ -549,7 +700,7 @@
358      pPriv->needInvalidate = FALSE;
359  
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  }
364  
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;
373  
374      pPriv = DRI2GetDrawable(pDraw);
375      if (pPriv == NULL)
376         return BadDrawable;
377  
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;
391  
392 @@ -792,31 +935,41 @@
393      return FALSE;
394  }
395  
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 +}
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;
427  
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      }
435  
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);
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      }
450  
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;
456  
457 @@ -860,7 +1013,6 @@
458  
459             if (current_msc < pPriv->last_swap_target)
460                 pPriv->last_swap_target = current_msc;
462         }
463  
464         /*
465 @@ -876,8 +1028,14 @@
466      }
467  
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;
485  
486 +    if (vid) {
487 +       return Success;
488 +    }
490 +    if (pDraw->type == DRAWABLE_WINDOW) {
491 +       WindowPtr       pWin = (WindowPtr) pDraw;
492 +       PixmapPtr       pPixmap = pScreen->GetWindowPixmap(pWin);
494 +       /*
495 +        * Find the top-most window using this pixmap
496 +        */
497 +       while (pWin->parent && pScreen->GetWindowPixmap(pWin->parent) == pPixmap)
498 +           pWin = pWin->parent;
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);
508  
509      return Success;
510  }
511  
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 +}
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 +}
530  void
531  DRI2SwapInterval(DrawablePtr pDrawable, int interval)
532  {
533 @@ -1014,6 +1211,77 @@
534      return ds->ScheduleSwap && ds->GetMSC;
535  }
536  
537 +#define ATOM(a) MakeAtom(a, sizeof(a) - 1, TRUE)
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;
548 +    if (!supports_video(ds)) {
549 +       return BadDrawable;
550 +    }
552 +    if (attribute == ATOM("XV_OSD")) {
553 +    } else if (ds->SetAttribute) {
554 +       ret = (*ds->SetAttribute)(pDraw, attribute, len, val);
555 +    }
557 +    return ret;
558 +}
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;
570 +    if (!supports_video(ds)) {
571 +       return BadDrawable;
572 +    }
574 +    if (attribute == ATOM("XV_OSD")) {
575 +    } else if (ds->GetAttribute) {
576 +       ret = (*ds->GetAttribute)(pDraw, attribute, len, val);
577 +    }
579 +    return ret;
580 +}
582 +int
583 +DRI2GetFormats(ScreenPtr pScreen, unsigned int *nformats, unsigned int **formats)
584 +{
585 +    DRI2ScreenPtr ds = DRI2GetScreen(pScreen);
587 +    if (! supports_video(ds)) {
588 +       return BadDrawable;
589 +    }
591 +    *nformats = ds->numFormats;
592 +    *formats  = ds->formats;
594 +    return Success;
595 +}
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 +}
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;
620  
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      }
630  
631      if (info->version >= 5) {
632          ds->AuthMagic = info->AuthMagic;
633      }
634  
635 +    if (info->version >= 6) {
636 +       ds->ReuseBufferNotify = info->ReuseBufferNotify;
637 +       ds->SwapLimitValidate = info->SwapLimitValidate;
638 +    }
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;
665 +       cur_minor = 4;
666 +    }
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);
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);
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);
762  
763  typedef void           (*DRI2InvalidateProcPtr)(DrawablePtr pDraw,
764 -                                                void *data);
765 +                                                void *data,
766 +                                                XID id);
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);
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);
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);
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);
816  
817  /**
818   * Version of the DRI2InfoRec structure defined in this header
819   */
820 -#define DRI2INFOREC_VERSION 5
821 +#define DRI2INFOREC_VERSION 7
822  
823  typedef struct {
824      unsigned int version;      /**< Version of this struct */
825 @@ -189,6 +300,20 @@
826      /* added in version 5 */
827  
828      DRI2AuthMagicProcPtr       AuthMagic;
829 +    /* added in version 6 */
831 +    DRI2ReuseBufferNotifyProcPtr ReuseBufferNotify;
832 +    DRI2SwapLimitValidateProcPtr SwapLimitValidate;
834 +    /* added in version 7 */
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;
844  
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);
849  
850 +extern _X_EXPORT DRI2BufferPtr * DRI2GetBuffersVid(DrawablePtr pDraw,
851 +       int width, int height, unsigned int *attachments, int count,
852 +       int *out_count);
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);
864  
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);
869  
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);
877 +extern _X_EXPORT unsigned int DRI2GetExtraBufferNames(DrawablePtr pDraw,
878 +       DRI2BufferPtr buf, unsigned int **names, unsigned int **pitches);
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
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);
895  
896      REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
898      rep.type = X_Reply;
899      rep.length = 0;
900      rep.sequenceNumber = client->sequence;
901 @@ -157,7 +158,7 @@
902  }
903  
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 @@
911  
912  
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;
924  
925      if (buffers == NULL)
926             return BadAlloc;
927 @@ -227,8 +229,24 @@
928         }
929      }
930  
931 +    if (vid) {
932 +       extra = 4 * (count - skip);
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 +           }
942 +           extra += 8 * DRI2GetExtraBufferNames(pDrawable, buffers[i],
943 +                   &names, &pitches);
944 +       }
945 +    }
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);
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);
973  
974  
975 -    return send_buffers_reply(client, pDrawable, buffers, count, width, height);
977 +    return send_buffers_reply(client, pDrawable, FALSE,
978 +           buffers, count, width, height);
979  }
980  
981  static int
982 @@ -303,7 +332,40 @@
983      buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
984                                        attachments, stuff->count, &count);
985  
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 +}
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;
1000 +    REQUEST_FIXED_SIZE(xDRI2GetBuffersVidReq, stuff->count * (2 * 4));
1001 +    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
1002 +                      &pDrawable, &status))
1003 +       return status;
1005 +    if (DRI2ThrottleClient(client, pDrawable))
1006 +       return Success;
1008 +    attachments = (unsigned int *) &stuff[1];
1009 +    buffers = DRI2GetBuffersVid(pDrawable, stuff->width, stuff->height,
1010 +                               attachments, stuff->count, &count);
1012 +    status = send_buffers_reply(client, pDrawable, TRUE, buffers, count, 0, 0);
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);
1020 +    return status;
1021  }
1022  
1023  static int
1024 @@ -416,6 +478,53 @@
1025      return Success;
1026  }
1027  
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;
1038 +    REQUEST_SIZE_MATCH(xDRI2SwapBuffersVidReq);
1040 +    if (!validDrawable(client, stuff->drawable,
1041 +                      DixReadAccess | DixWriteAccess, &pDrawable, &status))
1042 +       return status;
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;
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);
1055 +    b.x1 = stuff->x1;
1056 +    b.y1 = stuff->y1;
1057 +    b.x2 = stuff->x2;
1058 +    b.y2 = stuff->y2;
1060 +    status = DRI2SwapBuffersVid(client, pDrawable, target_msc, divisor, remainder,
1061 +           &swap_target, stuff->source, &b, DRI2SwapEvent, pDrawable);
1062 +    if (status != Success)
1063 +       return BadDrawable;
1065 +    rep.type = X_Reply;
1066 +    rep.length = 0;
1067 +    rep.sequenceNumber = client->sequence;
1068 +    load_swap_reply(&rep, swap_target);
1070 +    WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
1072 +    return Success;
1073 +}
1075  static void
1076  load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc)
1077  {
1078 @@ -539,6 +648,87 @@
1079  }
1080  
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;
1089 +    REQUEST_FIXED_SIZE(xDRI2SetAttributeReq, len * 4);
1091 +    if (!validDrawable(client, stuff->drawable,
1092 +           DixReadAccess | DixWriteAccess, &pDrawable, &status))
1093 +       return status;
1095 +    status = DRI2SetAttribute(pDrawable, stuff->attribute, len,
1096 +           (const CARD32 *)&stuff[1]);
1097 +    if (status != Success)
1098 +       return status;
1100 +    return Success;
1101 +}
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;
1112 +    REQUEST_SIZE_MATCH(xDRI2GetAttributeReq);
1114 +    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
1115 +           &status))
1116 +       return status;
1118 +    status = DRI2GetAttribute(pDrawable, stuff->attribute, &len, &val);
1119 +    if (status != Success)
1120 +       return status;
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);
1128 +    return Success;
1129 +}
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;
1140 +    REQUEST_SIZE_MATCH(xDRI2GetFormatsReq);
1142 +    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
1143 +           &status))
1144 +       return status;
1146 +    status = DRI2GetFormats(pDrawable->pScreen, &nformats, &formats);
1147 +    if (status != Success)
1148 +       return status;
1150 +    rep.type = X_Reply;
1151 +    rep.length = nformats * sizeof(*formats) / 4;
1152 +    rep.sequenceNumber = client->sequence;
1153 +    WriteToClient(client, sizeof(xDRI2GetFormatsReply), &rep);
1155 +    for (i = 0; i < nformats; i++) {
1156 +       WriteToClient(client, sizeof(formats[i]), &formats[i]);
1157 +    }
1159 +    return Success;
1160 +}
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      }