xorg_dri2.c revision b0ba8d6f807543d461272833a76059fed8a4d6e9
1/* 2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the 14 * next paragraph) shall be included in all copies or substantial portions 15 * of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 20 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR 21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 * 25 * 26 * Author: Alan Hourihane <alanh@tungstengraphics.com> 27 * Author: Jakob Bornecrantz <wallbraker@gmail.com> 28 * 29 */ 30 31#include "xorg-server.h" 32#include "xf86.h" 33#include "xf86_OSproc.h" 34 35#include "xorg_tracker.h" 36#include "xorg_exa.h" 37 38#include "dri2.h" 39 40#include "pipe/p_state.h" 41#include "util/u_inlines.h" 42 43#include "util/u_format.h" 44 45/* Make all the #if cases in the code esier to read */ 46#ifndef DRI2INFOREC_VERSION 47#define DRI2INFOREC_VERSION 1 48#endif 49 50#if DRI2INFOREC_VERSION == 2 51static Bool set_format_in_do_create_buffer; 52#endif 53 54typedef struct { 55 PixmapPtr pPixmap; 56 struct pipe_resource *tex; 57 struct pipe_fence_handle *fence; 58} *BufferPrivatePtr; 59 60static Bool 61dri2_do_create_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, unsigned int format) 62{ 63 struct pipe_resource *tex = NULL; 64 ScreenPtr pScreen = pDraw->pScreen; 65 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 66 modesettingPtr ms = modesettingPTR(pScrn); 67 struct exa_pixmap_priv *exa_priv; 68 BufferPrivatePtr private = buffer->driverPrivate; 69 PixmapPtr pPixmap; 70 struct winsys_handle whandle; 71 72 if (pDraw->type == DRAWABLE_PIXMAP) 73 pPixmap = (PixmapPtr) pDraw; 74 else 75 pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw); 76 exa_priv = exaGetPixmapDriverPrivate(pPixmap); 77 78 79 switch (buffer->attachment) { 80 default: 81 if (buffer->attachment != DRI2BufferFakeFrontLeft || 82 pDraw->type != DRAWABLE_PIXMAP) { 83 private->pPixmap = (*pScreen->CreatePixmap)(pScreen, pDraw->width, 84 pDraw->height, 85 pDraw->depth, 86 0); 87 } 88 break; 89 case DRI2BufferFrontLeft: 90 break; 91 case DRI2BufferStencil: 92#if DRI2INFOREC_VERSION >= 3 93 case DRI2BufferDepthStencil: 94#else 95 /* Works on old X servers because sanity checking is for the weak */ 96 case 9: 97#endif 98 if (exa_priv->depth_stencil_tex && 99 !util_format_is_depth_or_stencil(exa_priv->depth_stencil_tex->format)) 100 exa_priv->depth_stencil_tex = NULL; 101 /* Fall through */ 102 case DRI2BufferDepth: 103 if (exa_priv->depth_stencil_tex) 104 pipe_resource_reference(&tex, exa_priv->depth_stencil_tex); 105 else { 106 struct pipe_resource template; 107 unsigned depthBits = (format != 0) ? format : pDraw->depth; 108 memset(&template, 0, sizeof(template)); 109 template.target = PIPE_TEXTURE_2D; 110 if (buffer->attachment == DRI2BufferDepth) { 111 switch(depthBits) { 112 case 16: 113 template.format = PIPE_FORMAT_Z16_UNORM; 114 break; 115 case 32: 116 template.format = PIPE_FORMAT_Z32_UNORM; 117 break; 118 default: 119 template.format = ms->ds_depth_bits_last ? 120 PIPE_FORMAT_Z24X8_UNORM : PIPE_FORMAT_X8Z24_UNORM; 121 break; 122 } 123 } else { 124 template.format = ms->ds_depth_bits_last ? 125 PIPE_FORMAT_Z24_UNORM_S8_USCALED : PIPE_FORMAT_S8_USCALED_Z24_UNORM; 126 } 127 template.width0 = pDraw->width; 128 template.height0 = pDraw->height; 129 template.depth0 = 1; 130 template.last_level = 0; 131 template.bind = PIPE_BIND_DEPTH_STENCIL | 132 PIPE_BIND_SHARED; 133 tex = ms->screen->resource_create(ms->screen, &template); 134 pipe_resource_reference(&exa_priv->depth_stencil_tex, tex); 135 } 136 break; 137 } 138 139 if (!private->pPixmap) { 140 private->pPixmap = pPixmap; 141 pPixmap->refcnt++; 142 } 143 144 if (!tex) { 145 /* First call to make sure we have a pixmap private */ 146 exaMoveInPixmap(private->pPixmap); 147 xorg_exa_set_shared_usage(private->pPixmap); 148 pScreen->ModifyPixmapHeader(private->pPixmap, 0, 0, 0, 0, 0, NULL); 149 /* Second call to make sure texture has valid contents */ 150 exaMoveInPixmap(private->pPixmap); 151 tex = xorg_exa_get_texture(private->pPixmap); 152 } 153 154 if (!tex) 155 FatalError("NO TEXTURE IN DRI2\n"); 156 157 memset(&whandle, 0, sizeof(whandle)); 158 whandle.type = DRM_API_HANDLE_TYPE_SHARED; 159 160 ms->screen->resource_get_handle(ms->screen, tex, &whandle); 161 162 buffer->name = whandle.handle; 163 buffer->pitch = whandle.stride; 164 buffer->cpp = 4; 165 buffer->driverPrivate = private; 166 buffer->flags = 0; /* not tiled */ 167#if DRI2INFOREC_VERSION == 2 168 /* ABI forwards/backwards compatibility */ 169 if (set_format_in_do_create_buffer) 170 ((DRI2Buffer2Ptr)buffer)->format = 0; 171#elif DRI2INFOREC_VERSION >= 3 172 buffer->format = 0; 173#endif 174 private->tex = tex; 175 176 return TRUE; 177} 178 179static void 180dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer) 181{ 182 ScreenPtr pScreen = pDraw->pScreen; 183 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 184 modesettingPtr ms = modesettingPTR(pScrn); 185 BufferPrivatePtr private = buffer->driverPrivate; 186 struct exa_pixmap_priv *exa_priv = exaGetPixmapDriverPrivate(private->pPixmap); 187 188 pipe_resource_reference(&private->tex, NULL); 189 ms->screen->fence_reference(ms->screen, &private->fence, NULL); 190 pipe_resource_reference(&exa_priv->depth_stencil_tex, NULL); 191 (*pScreen->DestroyPixmap)(private->pPixmap); 192} 193 194#if DRI2INFOREC_VERSION >= 2 195 196static DRI2Buffer2Ptr 197dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) 198{ 199 DRI2Buffer2Ptr buffer; 200 BufferPrivatePtr private; 201 202 buffer = xcalloc(1, sizeof *buffer); 203 if (!buffer) 204 return NULL; 205 206 private = xcalloc(1, sizeof *private); 207 if (!private) { 208 goto fail; 209 } 210 211 buffer->attachment = attachment; 212 buffer->driverPrivate = private; 213 214 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ 215 if (dri2_do_create_buffer(pDraw, (DRI2BufferPtr)buffer, format)) 216 return buffer; 217 218 xfree(private); 219fail: 220 xfree(buffer); 221 return NULL; 222} 223 224static void 225dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer) 226{ 227 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ 228 dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer); 229 230 xfree(buffer->driverPrivate); 231 xfree(buffer); 232} 233 234#endif /* DRI2INFOREC_VERSION >= 2 */ 235 236#if DRI2INFOREC_VERSION <= 2 237 238static DRI2BufferPtr 239dri2_create_buffers(DrawablePtr pDraw, unsigned int *attachments, int count) 240{ 241 BufferPrivatePtr privates; 242 DRI2BufferPtr buffers; 243 int i; 244 245 buffers = xcalloc(count, sizeof *buffers); 246 if (!buffers) 247 goto fail_buffers; 248 249 privates = xcalloc(count, sizeof *privates); 250 if (!privates) 251 goto fail_privates; 252 253 for (i = 0; i < count; i++) { 254 buffers[i].attachment = attachments[i]; 255 buffers[i].driverPrivate = &privates[i]; 256 257 if (!dri2_do_create_buffer(pDraw, &buffers[i], 0)) 258 goto fail; 259 } 260 261 return buffers; 262 263fail: 264 xfree(privates); 265fail_privates: 266 xfree(buffers); 267fail_buffers: 268 return NULL; 269} 270 271static void 272dri2_destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count) 273{ 274 int i; 275 276 for (i = 0; i < count; i++) { 277 dri2_do_destroy_buffer(pDraw, &buffers[i]); 278 } 279 280 if (buffers) { 281 xfree(buffers[0].driverPrivate); 282 xfree(buffers); 283 } 284} 285 286#endif /* DRI2INFOREC_VERSION <= 2 */ 287 288static void 289dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 290 DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer) 291{ 292 ScreenPtr pScreen = pDraw->pScreen; 293 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 294 modesettingPtr ms = modesettingPTR(pScrn); 295 BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate; 296 BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate; 297 DrawablePtr src_draw; 298 DrawablePtr dst_draw; 299 GCPtr gc; 300 RegionPtr copy_clip; 301 Bool save_accel; 302 303 /* 304 * In driCreateBuffers we dewrap windows into the 305 * backing pixmaps in order to get to the texture. 306 * We need to use the real drawable in CopyArea 307 * so that cliprects and offsets are correct. 308 */ 309 src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : 310 &src_priv->pPixmap->drawable; 311 dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : 312 &dst_priv->pPixmap->drawable; 313 314 /* 315 * The clients implements glXWaitX with a copy front to fake and then 316 * waiting on the server to signal its completion of it. While 317 * glXWaitGL is a client side flush and a copy from fake to front. 318 * This is how it is done in the DRI2 protocol, how ever depending 319 * which type of drawables the server does things a bit differently 320 * then what the protocol says as the fake and front are the same. 321 * 322 * for pixmaps glXWaitX is a server flush. 323 * for pixmaps glXWaitGL is a client flush. 324 * for windows glXWaitX is a copy from front to fake then a server flush. 325 * for windows glXWaitGL is a client flush then a copy from fake to front. 326 * 327 * XXX in the windows case this code always flushes but that isn't a 328 * must in the glXWaitGL case but we don't know if this is a glXWaitGL 329 * or a glFlush/glFinish call. 330 */ 331 if (dst_priv->pPixmap == src_priv->pPixmap) { 332 /* pixmap glXWaitX */ 333 if (pSrcBuffer->attachment == DRI2BufferFrontLeft && 334 pDestBuffer->attachment == DRI2BufferFakeFrontLeft) { 335 ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, NULL); 336 return; 337 } 338 /* pixmap glXWaitGL */ 339 if (pDestBuffer->attachment == DRI2BufferFrontLeft && 340 pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) { 341 return; 342 } else { 343 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 344 "copying between the same pixmap\n"); 345 } 346 } 347 348 gc = GetScratchGC(pDraw->depth, pScreen); 349 copy_clip = REGION_CREATE(pScreen, NULL, 0); 350 REGION_COPY(pScreen, copy_clip, pRegion); 351 (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 352 ValidateGC(dst_draw, gc); 353 354 /* If this is a full buffer swap, throttle on the previous one */ 355 if (dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) { 356 BoxPtr extents = REGION_EXTENTS(pScreen, pRegion); 357 358 if (extents->x1 == 0 && extents->y1 == 0 && 359 extents->x2 == pDraw->width && extents->y2 == pDraw->height) { 360 ms->screen->fence_finish(ms->screen, dst_priv->fence, 0); 361 ms->screen->fence_reference(ms->screen, &dst_priv->fence, NULL); 362 } 363 } 364 365 /* Try to make sure the blit will be accelerated */ 366 save_accel = ms->exa->accel; 367 ms->exa->accel = TRUE; 368 369 /* In case it won't be though, make sure the GPU copy contents of the 370 * source pixmap will be used for the software fallback - presumably the 371 * client modified them before calling in here. 372 */ 373 exaMoveInPixmap(src_priv->pPixmap); 374 DamageRegionAppend(src_draw, pRegion); 375 DamageRegionProcessPending(src_draw); 376 377 (*gc->ops->CopyArea)(src_draw, dst_draw, gc, 378 0, 0, pDraw->width, pDraw->height, 0, 0); 379 ms->exa->accel = save_accel; 380 381 FreeScratchGC(gc); 382 383 ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, 384 pDestBuffer->attachment == DRI2BufferFrontLeft ? 385 &dst_priv->fence : NULL); 386} 387 388Bool 389xorg_dri2_init(ScreenPtr pScreen) 390{ 391 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 392 modesettingPtr ms = modesettingPTR(pScrn); 393 DRI2InfoRec dri2info; 394#if DRI2INFOREC_VERSION >= 2 395 int major, minor; 396 397 if (xf86LoaderCheckSymbol("DRI2Version")) { 398 DRI2Version(&major, &minor); 399 } else { 400 /* Assume version 1.0 */ 401 major = 1; 402 minor = 0; 403 } 404#endif 405 406 dri2info.version = min(DRI2INFOREC_VERSION, 3); 407 dri2info.fd = ms->fd; 408 409 dri2info.driverName = pScrn->driverName; 410 dri2info.deviceName = "/dev/dri/card0"; /* FIXME */ 411 412#if DRI2INFOREC_VERSION >= 2 413 dri2info.CreateBuffer = dri2_create_buffer; 414 dri2info.DestroyBuffer = dri2_destroy_buffer; 415#endif 416 417 /* For X servers in the 1.6.x series there where two DRI2 version. 418 * This allows us to build one binary that works on both servers. 419 */ 420#if DRI2INFOREC_VERSION == 2 421 if (minor == 0) { 422 set_format_in_do_create_buffer = FALSE; 423 dri2info.CreateBuffers = dri2_create_buffers; 424 dri2info.DestroyBuffers = dri2_destroy_buffers; 425 } else 426 set_format_in_do_create_buffer = FALSE; 427#endif 428 429 /* For version 1 set these unconditionaly. */ 430#if DRI2INFOREC_VERSION == 1 431 dri2info.CreateBuffers = dri2_create_buffers; 432 dri2info.DestroyBuffers = dri2_destroy_buffers; 433#endif 434 dri2info.CopyRegion = dri2_copy_region; 435 dri2info.Wait = NULL; 436 437 ms->d_depth_bits_last = 438 ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24X8_UNORM, 439 PIPE_TEXTURE_2D, 440 PIPE_BIND_DEPTH_STENCIL, 0); 441 ms->ds_depth_bits_last = 442 ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_Z24_UNORM_S8_USCALED, 443 PIPE_TEXTURE_2D, 444 PIPE_BIND_DEPTH_STENCIL, 0); 445 446 return DRI2ScreenInit(pScreen, &dri2info); 447} 448 449void 450xorg_dri2_close(ScreenPtr pScreen) 451{ 452 DRI2CloseScreen(pScreen); 453} 454 455/* vim: set sw=4 ts=8 sts=4: */ 456