vmwgfx_dri2.c revision 22f7e8e5
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#include "vmwgfx_hosted.h" 47 48#define VMWGFX_FD_PATH_LEN 80 49 50typedef struct { 51 int refcount; 52 PixmapPtr pPixmap; 53 struct xa_surface *srf; 54 unsigned int dri2_depth; 55} *BufferPrivatePtr; 56 57 58/* 59 * Attempt to guess what the dri state tracker is up to. 60 * Currently it sends only bpp as format. 61 */ 62 63static unsigned int 64vmwgfx_color_format_to_depth(unsigned int format) 65{ 66 return format; 67} 68 69static unsigned int 70vmwgfx_zs_format_to_depth(unsigned int format) 71{ 72 if (format == 24) 73 return 32; 74 return format; 75} 76 77static unsigned int 78vmwgfx_z_format_to_depth(unsigned int format) 79{ 80 return format; 81} 82 83static Bool 84dri2_do_create_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer, unsigned int format) 85{ 86 ScreenPtr pScreen = pDraw->pScreen; 87 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 88 modesettingPtr ms = modesettingPTR(pScrn); 89 BufferPrivatePtr private = buffer->driverPrivate; 90 PixmapPtr pPixmap; 91 struct vmwgfx_saa_pixmap *vpix; 92 struct xa_surface *srf = NULL; 93 unsigned int depth; 94 95 96 if (pDraw->type == DRAWABLE_PIXMAP) 97 pPixmap = (PixmapPtr) pDraw; 98 else 99 pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw); 100 101 vpix = vmwgfx_saa_pixmap(pPixmap); 102 private->refcount = 0; 103 104 switch (buffer->attachment) { 105 default: 106 depth = (format) ? vmwgfx_color_format_to_depth(format) : 107 pDraw->depth; 108 109 if (buffer->attachment != DRI2BufferFakeFrontLeft || 110 &pPixmap->drawable != pDraw) { 111 112 pPixmap = (*pScreen->CreatePixmap)(pScreen, 113 pDraw->width, 114 pDraw->height, 115 depth, 116 0); 117 if (pPixmap == NullPixmap) 118 return FALSE; 119 120 private->pPixmap = pPixmap; 121 private->dri2_depth = depth; 122 vpix = vmwgfx_saa_pixmap(pPixmap); 123 } 124 break; 125 case DRI2BufferFrontLeft: 126 if (&pPixmap->drawable == pDraw) 127 break; 128 buffer->name = 0; 129 buffer->pitch = 0; 130 buffer->cpp = pDraw->bitsPerPixel / 8; 131 buffer->driverPrivate = private; 132 buffer->flags = 0; /* not tiled */ 133 buffer->format = pDraw->bitsPerPixel; 134 if (!private->pPixmap) { 135 private->dri2_depth = 0; 136 private->pPixmap = pPixmap; 137 pPixmap->refcnt++; 138 } 139 return TRUE; 140 case DRI2BufferStencil: 141 case DRI2BufferDepthStencil: 142 if (!pScrn->vtSema) 143 return FALSE; 144 145 depth = (format) ? vmwgfx_zs_format_to_depth(format) : 32; 146 147 /* 148 * The SVGA device uses the zs ordering. 149 */ 150 151 srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, 152 depth, xa_type_zs, xa_format_unknown, 153 XA_FLAG_SHARED ); 154 if (!srf) 155 return FALSE; 156 157 private->dri2_depth = depth; 158 159 break; 160 case DRI2BufferDepth: 161 if (!pScrn->vtSema) 162 return FALSE; 163 164 depth = (format) ? vmwgfx_z_format_to_depth(format) : 165 pDraw->bitsPerPixel; 166 167 if (depth == 24) 168 srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, 169 depth, xa_type_zs, xa_format_unknown, 170 XA_FLAG_SHARED ); 171 else 172 srf = xa_surface_create(ms->xat, pDraw->width, pDraw->height, 173 depth, 174 xa_type_z, xa_format_unknown, 175 XA_FLAG_SHARED); 176 if (!srf) 177 return FALSE; 178 179 private->dri2_depth = depth; 180 181 break; 182 } 183 184 if (!private->pPixmap) { 185 private->pPixmap = pPixmap; 186 pPixmap->refcnt++; 187 } 188 189 if (!srf) { 190 depth = (format) ? vmwgfx_color_format_to_depth(format) : 191 pDraw->depth; 192 193 if (!vmwgfx_hw_dri2_validate(pPixmap, depth)) 194 return FALSE; 195 196 srf = vpix->hw; 197 private->refcount++; 198 private->dri2_depth = depth; 199 200 /* 201 * Compiz workaround. See vmwgfx_dirty(); 202 */ 203 204 if (buffer->attachment == DRI2BufferFrontLeft || 205 buffer->attachment == DRI2BufferFakeFrontLeft) 206 vpix->hw_is_dri2_fronts++; 207 } 208 209 private->srf = srf; 210 if (_xa_surface_handle(srf, &buffer->name, &buffer->pitch) != 0) 211 return FALSE; 212 213 buffer->cpp = xa_format_depth(xa_surface_format(srf)) / 8; 214 buffer->driverPrivate = private; 215 buffer->flags = 0; /* not tiled */ 216 buffer->format = format; 217 private->refcount++; 218 219 return TRUE; 220} 221 222static void 223dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer) 224{ 225 BufferPrivatePtr private = buffer->driverPrivate; 226 struct xa_surface *srf = private->srf; 227 ScreenPtr pScreen = pDraw->pScreen; 228 struct vmwgfx_saa_pixmap *vpix = vmwgfx_saa_pixmap(private->pPixmap); 229 230 if (--private->refcount == 0 && srf) { 231 xa_surface_destroy(srf); 232 } 233 234 /* 235 * Compiz workaround. See vmwgfx_dirty(); 236 */ 237 238 if ((buffer->attachment == DRI2BufferFrontLeft || 239 buffer->attachment == DRI2BufferFakeFrontLeft) && 240 private->refcount == 1 && 241 --vpix->hw_is_dri2_fronts == 0) 242 WSBMLISTDELINIT(&vpix->sync_x_head); 243 244 private->srf = NULL; 245 pScreen->DestroyPixmap(private->pPixmap); 246} 247 248 249static DRI2Buffer2Ptr 250dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) 251{ 252 DRI2Buffer2Ptr buffer; 253 BufferPrivatePtr private; 254 255 buffer = calloc(1, sizeof *buffer); 256 if (!buffer) 257 return NULL; 258 259 private = calloc(1, sizeof *private); 260 if (!private) { 261 goto fail; 262 } 263 264 buffer->attachment = attachment; 265 buffer->driverPrivate = private; 266 267 if (dri2_do_create_buffer(pDraw, buffer, format)) 268 return buffer; 269 270 free(private); 271fail: 272 free(buffer); 273 return NULL; 274} 275 276static void 277dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer) 278{ 279 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ 280 dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer); 281 282 free(buffer->driverPrivate); 283 free(buffer); 284} 285 286static void 287dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 288 DRI2Buffer2Ptr pDestBuffer, DRI2Buffer2Ptr pSrcBuffer) 289{ 290 291 292 ScreenPtr pScreen = pDraw->pScreen; 293 BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate; 294 BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate; 295 DrawablePtr src_draw; 296 DrawablePtr dst_draw; 297 RegionPtr myClip; 298 GCPtr gc; 299 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 300 301 /* 302 * This is a fragile protection against HW operations when not master. 303 * Needs to be blocked higher up in the dri2 code. 304 */ 305 if (!pScrn->vtSema) 306 return; 307 308 /* 309 * In driCreateBuffers we dewrap windows into the 310 * backing pixmaps in order to get to the texture. 311 * We need to use the real drawable in CopyArea 312 * so that cliprects and offsets are correct. 313 */ 314 src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : 315 &src_priv->pPixmap->drawable; 316 dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : 317 &dst_priv->pPixmap->drawable; 318 319 /* 320 * The clients implements glXWaitX with a copy front to fake and then 321 * waiting on the server to signal its completion of it. While 322 * glXWaitGL is a client side flush and a copy from fake to front. 323 * This is how it is done in the DRI2 protocol, how ever depending 324 * which type of drawables the server does things a bit differently 325 * then what the protocol says as the fake and front are the same. 326 * 327 * for pixmaps glXWaitX is a server flush. 328 * for pixmaps glXWaitGL is a client flush. 329 * for windows glXWaitX is a copy from front to fake then a server flush. 330 * for windows glXWaitGL is a client flush then a copy from fake to front. 331 * 332 * XXX in the windows case this code always flushes but that isn't a 333 * must in the glXWaitGL case but we don't know if this is a glXWaitGL 334 * or a glFlush/glFinish call. 335 */ 336 if (dst_priv->pPixmap == src_priv->pPixmap) { 337 /* pixmap glXWaitX */ 338 if (pSrcBuffer->attachment == DRI2BufferFrontLeft && 339 pDestBuffer->attachment == DRI2BufferFakeFrontLeft) { 340 341 if (!vmwgfx_hw_dri2_validate(dst_priv->pPixmap, 342 dst_priv->dri2_depth)) 343 return; 344 } 345 /* pixmap glXWaitGL */ 346 if (pDestBuffer->attachment == DRI2BufferFrontLeft && 347 pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) { 348 return; 349 } else { 350 vmwgfx_flush_dri2(pScreen); 351 return; 352 } 353 } 354 355 gc = GetScratchGC(pDraw->depth, pScreen); 356 myClip = REGION_CREATE(pScreen, REGION_RECTS(pRegion), 357 REGION_NUM_RECTS(pRegion)); 358 (*gc->funcs->ChangeClip) (gc, CT_REGION, myClip, 0); 359 ValidateGC(dst_draw, gc); 360 361 /* 362 * Damage the src drawable in order for damageCopyArea to pick up 363 * that something changed. 364 */ 365 DamageRegionAppend(src_draw, pRegion); 366 if (pSrcBuffer->attachment != DRI2BufferFrontLeft) 367 saa_drawable_dirty(src_draw, TRUE, pRegion); 368 DamageRegionProcessPending(src_draw); 369 370 /* 371 * Call CopyArea. This usually means a call to damageCopyArea that 372 * is wrapping saa_copy_area. The damageCopyArea function will make 373 * sure the destination drawable is appropriately damaged. 374 */ 375 (*gc->ops->CopyArea)(src_draw, dst_draw, gc, 376 0, 0, pDraw->width, pDraw->height, 0, 0); 377 378 /* 379 * FreeScratchGC will free myClip as well. 380 */ 381 myClip = NULL; 382 FreeScratchGC(gc); 383} 384 385#if (DRI2INFOREC_VERSION >= 8 && DRI2INFOREC_VERSION < 10) 386static int vmw_dri_auth_magic2(ScreenPtr pScreen, uint32_t magic) 387{ 388 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 389 modesettingPtr ms = modesettingPTR(pScrn); 390 391 return vmwgfx_hosted_dri_auth(ms->hdriver, ms->hosted, NULL, magic); 392} 393#endif 394 395#if (DRI2INFOREC_VERSION >= 10) 396static int vmw_dri_auth_magic3(ClientPtr client, ScreenPtr pScreen, 397 uint32_t magic) 398{ 399 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 400 modesettingPtr ms = modesettingPTR(pScrn); 401 402 return vmwgfx_hosted_dri_auth(ms->hdriver, ms->hosted, client, magic); 403} 404#endif 405 406Bool 407xorg_dri2_init(ScreenPtr pScreen) 408{ 409 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 410 modesettingPtr ms = modesettingPTR(pScrn); 411 DRI2InfoRec dri2info; 412 int major, minor; 413 char fdPath[VMWGFX_FD_PATH_LEN]; 414 ssize_t numChar; 415 416 memset(&dri2info, 0, sizeof(dri2info)); 417 418 if (xf86LoaderCheckSymbol("DRI2Version")) { 419 DRI2Version(&major, &minor); 420 } else { 421 /* Assume version 1.0 */ 422 major = 1; 423 minor = 0; 424 } 425 426 dri2info.version = min(DRI2INFOREC_VERSION, 3); 427 dri2info.fd = ms->fd; 428 dri2info.driverName = "vmwgfx"; 429 430 /* 431 * This way of obtaining the DRM device name is a bit 432 * os-specific. It would be better to obtain it from 433 * drmOpen. Currently this works only for Linux. 434 */ 435 memset(fdPath, 0, VMWGFX_FD_PATH_LEN); 436 snprintf(fdPath, VMWGFX_FD_PATH_LEN - 1, "/proc/self/fd/%d", ms->fd); 437 numChar = readlink(fdPath, ms->dri2_device_name, VMWGFX_DRI_DEVICE_LEN); 438 if (numChar <= 0 || numChar >= VMWGFX_DRI_DEVICE_LEN) { 439 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 440 "Could not find the drm device name. Disabling dri2.\n"); 441 return FALSE; 442 } 443 ms->dri2_device_name[numChar] = 0; 444 dri2info.deviceName = ms->dri2_device_name; 445 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 446 "Path of drm device is \"%s\".\n", ms->dri2_device_name); 447 448 dri2info.CreateBuffer = dri2_create_buffer; 449 dri2info.DestroyBuffer = dri2_destroy_buffer; 450 451 dri2info.CopyRegion = dri2_copy_region; 452 dri2info.Wait = NULL; 453 454#if (DRI2INFOREC_VERSION >= 8 && DRI2INFOREC_VERSION < 10) 455 if (vmwgfx_is_hosted(ms->hdriver)) { 456 dri2info.version = 8; 457 dri2info.AuthMagic2 = vmw_dri_auth_magic2; 458 } 459#endif 460#if (DRI2INFOREC_VERSION >= 10) 461 if (vmwgfx_is_hosted(ms->hdriver)) { 462 dri2info.version = 10; 463 dri2info.AuthMagic3 = vmw_dri_auth_magic3; 464 } 465#endif 466 467 return DRI2ScreenInit(pScreen, &dri2info); 468} 469 470void 471xorg_dri2_close(ScreenPtr pScreen) 472{ 473 DRI2CloseScreen(pScreen); 474} 475 476/* vim: set sw=4 ts=8 sts=4: */ 477