vmwgfx_dri2.c revision 3bfa90b6
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 = xf86ScreenToScrn(pScreen); 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 = xf86ScreenToScrn(pScreen); 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: */ 427