Initial DRI2 support.
[nouveau] / src / nouveau_dri2.c
1 #include "nv_include.h"
2 #include "dri2.h"
3
4 struct nouveau_dri2_buffer {
5         PixmapPtr pPixmap;
6 };
7
8 DRI2BufferPtr
9 nouveau_dri2_create_buffers(DrawablePtr pDraw, unsigned int *attachments,
10                             int count)
11 {
12         ScreenPtr pScreen = pDraw->pScreen;
13         DRI2BufferPtr dri2_bufs;
14         struct nouveau_dri2_buffer *nv_bufs;
15         PixmapPtr ppix, pzpix;
16         int i;
17
18         dri2_bufs = xcalloc(count, sizeof(*dri2_bufs));
19         if (!dri2_bufs)
20                 return NULL;
21
22         nv_bufs = xcalloc(count, sizeof(*nv_bufs));
23         if (!nv_bufs) {
24                 xfree(dri2_bufs);
25                 return NULL;
26         }
27
28         pzpix = NULL;
29         for (i = 0; i < count; i++) {
30                 if (attachments[i] == DRI2BufferFrontLeft) {
31                         if (pDraw->type == DRAWABLE_PIXMAP) {
32                                 ppix = (PixmapPtr)pDraw;
33                         } else {
34                                 WindowPtr pwin = (WindowPtr)pDraw;
35                                 ppix = pScreen->GetWindowPixmap(pwin);
36                         }
37
38                         ppix->refcnt++;
39                 } else
40                 if (attachments[i] == DRI2BufferStencil && pzpix) {
41                         ppix = pzpix;
42                         ppix->refcnt++;
43                 } else {
44                         ppix = pScreen->CreatePixmap(pScreen, pDraw->width,
45                                                      pDraw->height,
46                                                      pDraw->depth, 0);
47                 }
48
49                 if (attachments[i] == DRI2BufferDepth)
50                         pzpix = ppix;
51
52                 dri2_bufs[i].attachment = attachments[i];
53                 dri2_bufs[i].pitch = ppix->devKind;
54                 dri2_bufs[i].cpp = ppix->drawable.bitsPerPixel / 8;
55                 dri2_bufs[i].driverPrivate = &nv_bufs[i];
56                 dri2_bufs[i].flags = 0;
57                 nv_bufs[i].pPixmap = ppix;
58
59                 nouveau_bo_handle_get(nouveau_pixmap(ppix)->bo,
60                                       &dri2_bufs[i].name);
61         }
62
63         return dri2_bufs;
64 }
65
66 void
67 nouveau_dri2_destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr buffers,
68                              int count)
69 {
70         struct nouveau_dri2_buffer *nvbuf;
71
72         while (count--) {
73                 nvbuf = buffers[count].driverPrivate;
74                 pDraw->pScreen->DestroyPixmap(nvbuf->pPixmap);
75         }
76
77         if (buffers) {
78                 xfree(buffers[0].driverPrivate);
79                 xfree(buffers);
80         }
81 }
82
83 void
84 nouveau_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
85                          DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
86 {
87         struct nouveau_dri2_buffer *nvbuf = pSrcBuffer->driverPrivate;
88         ScreenPtr pScreen = pDraw->pScreen;
89         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
90         NVPtr pNv = NVPTR(pScrn);
91         RegionPtr pCopyClip;
92         GCPtr pGC;
93
94         pGC = GetScratchGC(pDraw->depth, pScreen);
95         pCopyClip = REGION_CREATE(pScreen, NULL, 0);
96         REGION_COPY(pScreen, pCopyClip, pRegion);
97         pGC->funcs->ChangeClip(pGC, CT_REGION, pCopyClip, 0);
98         ValidateGC(pDraw, pGC);
99         pGC->ops->CopyArea(&nvbuf->pPixmap->drawable, pDraw, pGC, 0, 0,
100                            pDraw->width, pDraw->height, 0, 0);
101         FreeScratchGC(pGC);
102
103         FIRE_RING(pNv->chan);
104 }
105
106 Bool
107 nouveau_dri2_init(ScreenPtr pScreen)
108 {
109         ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
110         NVPtr pNv = NVPTR(pScrn);
111         DRI2InfoRec dri2;
112
113         dri2.version = 1;
114         dri2.fd = nouveau_device(pNv->dev)->fd;
115         dri2.driverName = "nouveau";
116         dri2.deviceName = "/dev/dri/card0";
117         dri2.CreateBuffers = nouveau_dri2_create_buffers;
118         dri2.DestroyBuffers = nouveau_dri2_destroy_buffers;
119         dri2.CopyRegion = nouveau_dri2_copy_region;
120
121         return DRI2ScreenInit(pScreen, &dri2);
122 }
123
124 void
125 nouveau_dri2_takedown(ScreenPtr pScreen)
126 {
127         DRI2CloseScreen(pScreen);
128 }
129