summaryrefslogtreecommitdiff
path: root/vmwgfx/vmwgfx_dri2.c
diff options
context:
space:
mode:
Diffstat (limited to 'vmwgfx/vmwgfx_dri2.c')
-rw-r--r--vmwgfx/vmwgfx_dri2.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/vmwgfx/vmwgfx_dri2.c b/vmwgfx/vmwgfx_dri2.c
new file mode 100644
index 0000000..1b82ac4
--- /dev/null
+++ b/vmwgfx/vmwgfx_dri2.c
@@ -0,0 +1,426 @@
1/*
2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3 * Copyright 2011 VMWare, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 *
27 * Author: Alan Hourihane <alanh@tungstengraphics.com>
28 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
29 * Author: Thomas Hellstrom <thellstrom@vmware.com>
30 *
31 */
32
33#include "xorg-server.h"
34#include "xf86.h"
35#include "xf86_OSproc.h"
36
37#include "vmwgfx_driver.h"
38#include "../saa/saa.h"
39
40#include "dri2.h"
41#include "gcstruct.h"
42#include "gc.h"
43#include "vmwgfx_saa.h"
44#include "wsbm_util.h"
45#include <unistd.h>
46
47#define VMWGFX_FD_PATH_LEN 80
48
49typedef struct {
50 int refcount;
51 PixmapPtr pPixmap;
52 struct xa_surface *srf;
53 unsigned int dri2_depth;
54} *BufferPrivatePtr;
55
56
57/*
58 * Attempt to guess what the dri state tracker is up to.
59 * Currently it sends only bpp as format.
60 */
61
62static unsigned int
63vmwgfx_color_format_to_depth(unsigned int format)
64{
65 return format;
66}
67
68static unsigned int
69vmwgfx_zs_format_to_depth(unsigned int format)
70{
71 if (format == 24)
72 return 32;
73 return format;
74}
75
76static unsigned int
77vmwgfx_z_format_to_depth(unsigned int format)
78{
79 return format;
80}
81
82static Bool
83dri2_do_create_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer, unsigned int format)
84{
85 ScreenPtr pScreen = pDraw->pScreen;
86 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
87 modesettingPtr ms = modesettingPTR(pScrn);
88 BufferPrivatePtr private = buffer->driverPrivate;
89 PixmapPtr pPixmap;
90 struct vmwgfx_saa_pixmap *vpix;
91 struct xa_surface *srf = NULL;
92 unsigned int depth;
93
94
95 if (pDraw->type == DRAWABLE_PIXMAP)
96 pPixmap = (PixmapPtr) pDraw;
97 else
98 pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw);
99
100 vpix = vmwgfx_saa_pixmap(pPixmap);
101 private->refcount = 0;
102
103 switch (buffer->attachment) {
104 default:
105 depth = (format) ? vmwgfx_color_format_to_depth(format) :
106 pDraw->depth;
107
108 if (buffer->attachment != DRI2BufferFakeFrontLeft ||
109 &pPixmap->drawable != pDraw) {
110
111 pPixmap = (*pScreen->CreatePixmap)(pScreen,
112 pDraw->width,
113 pDraw->height,
114 depth,
115 0);
116 if (pPixmap == NullPixmap)
117 return FALSE;
118
119 private->pPixmap = pPixmap;
120 private->dri2_depth = depth;
121 vpix = vmwgfx_saa_pixmap(pPixmap);
122 }
123 break;
124 case DRI2BufferFrontLeft:
125 if (&pPixmap->drawable == pDraw)
126 break;
127 buffer->name = 0;
128 buffer->pitch = 0;
129 buffer->cpp = pDraw->bitsPerPixel / 8;
130 buffer->driverPrivate = private;
131 buffer->flags = 0; /* not tiled */
132 buffer->format = pDraw->bitsPerPixel;
133 if (!private->pPixmap) {
134 private->dri2_depth = 0;
135 private->pPixmap = pPixmap;
136 pPixmap->refcnt++;
137 }
138 return TRUE;
139 case DRI2BufferStencil:
140 case DRI2BufferDepthStencil:
141
142 depth = (format) ? vmwgfx_zs_format_to_depth(format) : 32;
143
144 /*
145 * The SVGA device uses the zs ordering.
146 */
147
148 srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
149 depth, xa_type_zs, xa_format_unknown,
150 XA_FLAG_SHARED );
151 if (!srf)
152 return FALSE;
153
154 private->dri2_depth = depth;
155
156 break;
157 case DRI2BufferDepth:
158 depth = (format) ? vmwgfx_z_format_to_depth(format) :
159 pDraw->bitsPerPixel;
160
161 if (depth == 24)
162 srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
163 depth, xa_type_zs, xa_format_unknown,
164 XA_FLAG_SHARED );
165 else
166 srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height,
167 depth,
168 xa_type_z, xa_format_unknown,
169 XA_FLAG_SHARED);
170 if (!srf)
171 return FALSE;
172
173 private->dri2_depth = depth;
174
175 break;
176 }
177
178 if (!private->pPixmap) {
179 private->pPixmap = pPixmap;
180 pPixmap->refcnt++;
181 }
182
183 if (!srf) {
184 depth = (format) ? vmwgfx_color_format_to_depth(format) :
185 pDraw->depth;
186
187 if (!vmwgfx_hw_dri2_validate(pPixmap, depth))
188 return FALSE;
189
190 srf = vpix->hw;
191 private->refcount++;
192 private->dri2_depth = depth;
193
194 /*
195 * Compiz workaround. See vmwgfx_dirty();
196 */
197
198 if (buffer->attachment == DRI2BufferFrontLeft ||
199 buffer->attachment == DRI2BufferFakeFrontLeft)
200 vpix->hw_is_dri2_fronts++;
201 }
202
203 private->srf = srf;
204 if (xa_surface_handle(srf, &buffer->name, &buffer->pitch) != 0)
205 return FALSE;
206
207 buffer->cpp = xa_format_depth(xa_surface_format(srf)) / 8;
208 buffer->driverPrivate = private;
209 buffer->flags = 0; /* not tiled */
210 buffer->format = format;
211 private->refcount++;
212
213 return TRUE;
214}
215
216static void
217dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
218{
219 BufferPrivatePtr private = buffer->driverPrivate;
220 struct xa_surface *srf = private->srf;
221 ScreenPtr pScreen = pDraw->pScreen;
222 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(private->pPixmap);
223
224 if (--private->refcount == 0 && srf) {
225 xa_surface_destroy(srf);
226 }
227
228 /*
229 * Compiz workaround. See vmwgfx_dirty();
230 */
231
232 if ((buffer->attachment == DRI2BufferFrontLeft ||
233 buffer->attachment == DRI2BufferFakeFrontLeft) &&
234 private->refcount == 1 &&
235 --vpix->hw_is_dri2_fronts == 0)
236 WSBMLISTDELINIT(&vpix->sync_x_head);
237
238 private->srf = NULL;
239 pScreen->DestroyPixmap(private->pPixmap);
240}
241
242
243static DRI2Buffer2Ptr
244dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format)
245{
246 DRI2Buffer2Ptr buffer;
247 BufferPrivatePtr private;
248
249 buffer = calloc(1, sizeof *buffer);
250 if (!buffer)
251 return NULL;
252
253 private = calloc(1, sizeof *private);
254 if (!private) {
255 goto fail;
256 }
257
258 buffer->attachment = attachment;
259 buffer->driverPrivate = private;
260
261 if (dri2_do_create_buffer(pDraw, buffer, format))
262 return buffer;
263
264 free(private);
265fail:
266 free(buffer);
267 return NULL;
268}
269
270static void
271dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer)
272{
273 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */
274 dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer);
275
276 free(buffer->driverPrivate);
277 free(buffer);
278}
279
280static void
281dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion,
282 DRI2Buffer2Ptr pDestBuffer, DRI2Buffer2Ptr pSrcBuffer)
283{
284
285
286 ScreenPtr pScreen = pDraw->pScreen;
287 BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate;
288 BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate;
289 DrawablePtr src_draw;
290 DrawablePtr dst_draw;
291 RegionPtr myClip;
292 GCPtr gc;
293
294 /*
295 * In driCreateBuffers we dewrap windows into the
296 * backing pixmaps in order to get to the texture.
297 * We need to use the real drawable in CopyArea
298 * so that cliprects and offsets are correct.
299 */
300 src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
301 &src_priv->pPixmap->drawable;
302 dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw :
303 &dst_priv->pPixmap->drawable;
304
305 /*
306 * The clients implements glXWaitX with a copy front to fake and then
307 * waiting on the server to signal its completion of it. While
308 * glXWaitGL is a client side flush and a copy from fake to front.
309 * This is how it is done in the DRI2 protocol, how ever depending
310 * which type of drawables the server does things a bit differently
311 * then what the protocol says as the fake and front are the same.
312 *
313 * for pixmaps glXWaitX is a server flush.
314 * for pixmaps glXWaitGL is a client flush.
315 * for windows glXWaitX is a copy from front to fake then a server flush.
316 * for windows glXWaitGL is a client flush then a copy from fake to front.
317 *
318 * XXX in the windows case this code always flushes but that isn't a
319 * must in the glXWaitGL case but we don't know if this is a glXWaitGL
320 * or a glFlush/glFinish call.
321 */
322 if (dst_priv->pPixmap == src_priv->pPixmap) {
323 /* pixmap glXWaitX */
324 if (pSrcBuffer->attachment == DRI2BufferFrontLeft &&
325 pDestBuffer->attachment == DRI2BufferFakeFrontLeft) {
326
327 if (!vmwgfx_hw_dri2_validate(dst_priv->pPixmap,
328 dst_priv->dri2_depth))
329 return;
330 }
331 /* pixmap glXWaitGL */
332 if (pDestBuffer->attachment == DRI2BufferFrontLeft &&
333 pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) {
334 return;
335 } else {
336 vmwgfx_flush_dri2(pScreen);
337 return;
338 }
339 }
340
341 gc = GetScratchGC(pDraw->depth, pScreen);
342 myClip = REGION_CREATE(pScreen, REGION_RECTS(pRegion),
343 REGION_NUM_RECTS(pRegion));
344 (*gc->funcs->ChangeClip) (gc, CT_REGION, myClip, 0);
345 ValidateGC(dst_draw, gc);
346
347 /*
348 * Damage the src drawable in order for damageCopyArea to pick up
349 * that something changed.
350 */
351 DamageRegionAppend(src_draw, pRegion);
352 if (pSrcBuffer->attachment != DRI2BufferFrontLeft)
353 saa_drawable_dirty(src_draw, TRUE, pRegion);
354 DamageRegionProcessPending(src_draw);
355
356 /*
357 * Call CopyArea. This usually means a call to damageCopyArea that
358 * is wrapping saa_copy_area. The damageCopyArea function will make
359 * sure the destination drawable is appropriately damaged.
360 */
361 (*gc->ops->CopyArea)(src_draw, dst_draw, gc,
362 0, 0, pDraw->width, pDraw->height, 0, 0);
363
364 /*
365 * FreeScratchGC will free myClip as well.
366 */
367 myClip = NULL;
368 FreeScratchGC(gc);
369}
370
371Bool
372xorg_dri2_init(ScreenPtr pScreen)
373{
374 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
375 modesettingPtr ms = modesettingPTR(pScrn);
376 DRI2InfoRec dri2info;
377 int major, minor;
378 char fdPath[VMWGFX_FD_PATH_LEN];
379 ssize_t numChar;
380
381 if (xf86LoaderCheckSymbol("DRI2Version")) {
382 DRI2Version(&major, &minor);
383 } else {
384 /* Assume version 1.0 */
385 major = 1;
386 minor = 0;
387 }
388
389 dri2info.version = min(DRI2INFOREC_VERSION, 3);
390 dri2info.fd = ms->fd;
391 dri2info.driverName = "vmwgfx";
392
393 /*
394 * This way of obtaining the DRM device name is a bit
395 * os-specific. It would be better to obtain it from
396 * drmOpen. Currently this works only for Linux.
397 */
398 memset(fdPath, 0, VMWGFX_FD_PATH_LEN);
399 snprintf(fdPath, VMWGFX_FD_PATH_LEN - 1, "/proc/self/fd/%d", ms->fd);
400 numChar = readlink(fdPath, ms->dri2_device_name, VMWGFX_DRI_DEVICE_LEN);
401 if (numChar <= 0 || numChar >= VMWGFX_DRI_DEVICE_LEN) {
402 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
403 "Could not find the drm device name. Disabling dri2.\n");
404 return FALSE;
405 }
406 ms->dri2_device_name[numChar] = 0;
407 dri2info.deviceName = ms->dri2_device_name;
408 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
409 "Path of drm device is \"%s\".\n", ms->dri2_device_name);
410
411 dri2info.CreateBuffer = dri2_create_buffer;
412 dri2info.DestroyBuffer = dri2_destroy_buffer;
413
414 dri2info.CopyRegion = dri2_copy_region;
415 dri2info.Wait = NULL;
416
417 return DRI2ScreenInit(pScreen, &dri2info);
418}
419
420void
421xorg_dri2_close(ScreenPtr pScreen)
422{
423 DRI2CloseScreen(pScreen);
424}
425
426/* vim: set sw=4 ts=8 sts=4: */