diff options
Diffstat (limited to 'vmwgfx/vmwgfx_dri2.c')
-rw-r--r-- | vmwgfx/vmwgfx_dri2.c | 426 |
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 | |||
49 | typedef 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 | |||
62 | static unsigned int | ||
63 | vmwgfx_color_format_to_depth(unsigned int format) | ||
64 | { | ||
65 | return format; | ||
66 | } | ||
67 | |||
68 | static unsigned int | ||
69 | vmwgfx_zs_format_to_depth(unsigned int format) | ||
70 | { | ||
71 | if (format == 24) | ||
72 | return 32; | ||
73 | return format; | ||
74 | } | ||
75 | |||
76 | static unsigned int | ||
77 | vmwgfx_z_format_to_depth(unsigned int format) | ||
78 | { | ||
79 | return format; | ||
80 | } | ||
81 | |||
82 | static Bool | ||
83 | dri2_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 | |||
216 | static void | ||
217 | dri2_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 | |||
243 | static DRI2Buffer2Ptr | ||
244 | dri2_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); | ||
265 | fail: | ||
266 | free(buffer); | ||
267 | return NULL; | ||
268 | } | ||
269 | |||
270 | static void | ||
271 | dri2_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 | |||
280 | static void | ||
281 | dri2_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 | |||
371 | Bool | ||
372 | xorg_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 | |||
420 | void | ||
421 | xorg_dri2_close(ScreenPtr pScreen) | ||
422 | { | ||
423 | DRI2CloseScreen(pScreen); | ||
424 | } | ||
425 | |||
426 | /* vim: set sw=4 ts=8 sts=4: */ | ||