xorg_dri2.c revision d509f84543d0979e9bb53c20c195f378dd61e728
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 "pipe/p_inlines.h" 42 43#include "util/u_rect.h" 44 45typedef struct { 46 PixmapPtr pPixmap; 47 struct pipe_texture *tex; 48 struct pipe_fence_handle *fence; 49} *BufferPrivatePtr; 50 51static Bool 52driDoCreateBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer, unsigned int format) 53{ 54 struct pipe_texture *tex = NULL; 55 ScreenPtr pScreen = pDraw->pScreen; 56 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 57 modesettingPtr ms = modesettingPTR(pScrn); 58 struct exa_pixmap_priv *exa_priv; 59 BufferPrivatePtr private = buffer->driverPrivate; 60 PixmapPtr pPixmap; 61 unsigned stride, handle; 62 63 if (pDraw->type == DRAWABLE_PIXMAP) 64 pPixmap = (PixmapPtr) pDraw; 65 else 66 pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw); 67 exa_priv = exaGetPixmapDriverPrivate(pPixmap); 68 69 switch (buffer->attachment) { 70 default: 71 if (buffer->attachment != DRI2BufferFakeFrontLeft || 72 pDraw->type != DRAWABLE_PIXMAP) { 73 private->pPixmap = (*pScreen->CreatePixmap)(pScreen, pDraw->width, 74 pDraw->height, 75 pDraw->depth, 76 0); 77 } 78 break; 79 case DRI2BufferFrontLeft: 80 break; 81 case DRI2BufferStencil: 82#if defined(DRI2INFOREC_VERSION) && DRI2INFOREC_VERSION > 2 83 case DRI2BufferDepthStencil: 84#else 85 /* Works on old X servers because sanity checking is for the weak */ 86 case 9: 87#endif 88 if (exa_priv->depth_stencil_tex && 89 !pf_is_depth_stencil(exa_priv->depth_stencil_tex->format)) 90 exa_priv->depth_stencil_tex = NULL; 91 /* Fall through */ 92 case DRI2BufferDepth: 93 if (exa_priv->depth_stencil_tex) 94 pipe_texture_reference(&tex, exa_priv->depth_stencil_tex); 95 else { 96 struct pipe_texture template; 97 memset(&template, 0, sizeof(template)); 98 template.target = PIPE_TEXTURE_2D; 99 if (buffer->attachment == DRI2BufferDepth) 100 template.format = ms->ds_depth_bits_last ? 101 PIPE_FORMAT_X8Z24_UNORM : PIPE_FORMAT_Z24X8_UNORM; 102 else 103 template.format = ms->ds_depth_bits_last ? 104 PIPE_FORMAT_S8Z24_UNORM : PIPE_FORMAT_Z24S8_UNORM; 105 pf_get_block(template.format, &template.block); 106 template.width0 = pDraw->width; 107 template.height0 = pDraw->height; 108 template.depth0 = 1; 109 template.last_level = 0; 110 template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL | 111 PIPE_TEXTURE_USAGE_DISPLAY_TARGET; 112 tex = ms->screen->texture_create(ms->screen, &template); 113 pipe_texture_reference(&exa_priv->depth_stencil_tex, tex); 114 } 115 break; 116 } 117 118 if (!private->pPixmap) { 119 private->pPixmap = pPixmap; 120 pPixmap->refcnt++; 121 } 122 123 if (!tex) { 124 exaMoveInPixmap(private->pPixmap); 125 xorg_exa_set_shared_usage(private->pPixmap); 126 pScreen->ModifyPixmapHeader(private->pPixmap, 0, 0, 0, 0, 0, NULL); 127 tex = xorg_exa_get_texture(private->pPixmap); 128 } 129 130 if (!tex) 131 FatalError("NO TEXTURE IN DRI2\n"); 132 133 ms->api->shared_handle_from_texture(ms->api, ms->screen, tex, &stride, &handle); 134 135 buffer->name = handle; 136 buffer->pitch = stride; 137 buffer->cpp = 4; 138 buffer->driverPrivate = private; 139 buffer->flags = 0; /* not tiled */ 140 private->tex = tex; 141 142 return TRUE; 143} 144 145static void 146driDoDestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer) 147{ 148 ScreenPtr pScreen = pDraw->pScreen; 149 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 150 modesettingPtr ms = modesettingPTR(pScrn); 151 BufferPrivatePtr private = buffer->driverPrivate; 152 struct exa_pixmap_priv *exa_priv = exaGetPixmapDriverPrivate(private->pPixmap); 153 154 pipe_texture_reference(&private->tex, NULL); 155 ms->screen->fence_reference(ms->screen, &private->fence, NULL); 156 pipe_texture_reference(&exa_priv->depth_stencil_tex, NULL); 157 (*pScreen->DestroyPixmap)(private->pPixmap); 158} 159 160#if defined(DRI2INFOREC_VERSION) && DRI2INFOREC_VERSION > 2 161 162static DRI2BufferPtr 163driCreateBuffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) 164{ 165 DRI2BufferPtr buffer; 166 BufferPrivatePtr private; 167 168 buffer = xcalloc(1, sizeof *buffer); 169 if (!buffer) 170 return NULL; 171 172 private = xcalloc(1, sizeof *private); 173 if (!private) { 174 goto fail; 175 } 176 177 buffer->attachment = attachment; 178 buffer->driverPrivate = private; 179 180 if (driDoCreateBuffer(pDraw, buffer, format)) 181 return buffer; 182 183 xfree(private); 184fail: 185 xfree(buffer); 186 return NULL; 187} 188 189static void 190driDestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer) 191{ 192 driDoDestroyBuffer(pDraw, buffer); 193 194 xfree(buffer->driverPrivate); 195 xfree(buffer); 196} 197 198#else /* DRI2INFOREC_VERSION <= 2 */ 199 200static DRI2BufferPtr 201driCreateBuffers(DrawablePtr pDraw, unsigned int *attachments, int count) 202{ 203 BufferPrivatePtr privates; 204 DRI2BufferPtr buffers; 205 int i; 206 207 buffers = xcalloc(count, sizeof *buffers); 208 if (!buffers) 209 goto fail_buffers; 210 211 privates = xcalloc(count, sizeof *privates); 212 if (!privates) 213 goto fail_privates; 214 215 for (i = 0; i < count; i++) { 216 buffers[i].attachment = attachments[i]; 217 buffers[i].driverPrivate = &privates[i]; 218 219 if (!driDoCreateBuffer(pDraw, &buffers[i], 0)) 220 goto fail; 221 } 222 223 return buffers; 224 225fail: 226 xfree(privates); 227fail_privates: 228 xfree(buffers); 229fail_buffers: 230 return NULL; 231} 232 233static void 234driDestroyBuffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count) 235{ 236 int i; 237 238 for (i = 0; i < count; i++) { 239 driDoDestroyBuffer(pDraw, &buffers[i]); 240 } 241 242 if (buffers) { 243 xfree(buffers[0].driverPrivate); 244 xfree(buffers); 245 } 246} 247 248#endif /* DRI2INFOREC_VERSION */ 249 250static void 251driCopyRegion(DrawablePtr pDraw, RegionPtr pRegion, 252 DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer) 253{ 254 ScreenPtr pScreen = pDraw->pScreen; 255 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 256 modesettingPtr ms = modesettingPTR(pScrn); 257 BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate; 258 BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate; 259 PixmapPtr src_pixmap; 260 PixmapPtr dst_pixmap; 261 GCPtr gc; 262 RegionPtr copy_clip; 263 264 /* 265 * In driCreateBuffers we dewrap windows into the 266 * backing pixmaps in order to get to the texture. 267 * We need to use the real drawable in CopyArea 268 * so that cliprects and offsets are correct. 269 */ 270 src_pixmap = src_priv->pPixmap; 271 dst_pixmap = dst_priv->pPixmap; 272 if (pSrcBuffer->attachment == DRI2BufferFrontLeft) 273 src_pixmap = (PixmapPtr)pDraw; 274 if (pDestBuffer->attachment == DRI2BufferFrontLeft) 275 dst_pixmap = (PixmapPtr)pDraw; 276 277 /* 278 * The clients implements glXWaitX with a copy front to fake and then 279 * waiting on the server to signal its completion of it. While 280 * glXWaitGL is a client side flush and a copy from fake to front. 281 * This is how it is done in the DRI2 protocol, how ever depending 282 * which type of drawables the server does things a bit differently 283 * then what the protocol says as the fake and front are the same. 284 * 285 * for pixmaps glXWaitX is a server flush. 286 * for pixmaps glXWaitGL is a client flush. 287 * for windows glXWaitX is a copy from front to fake then a server flush. 288 * for windows glXWaitGL is a client flush then a copy from fake to front. 289 * 290 * XXX in the windows case this code always flushes but that isn't a 291 * must in the glXWaitGL case but we don't know if this is a glXWaitGL 292 * or a glFlush/glFinish call. 293 */ 294 if (dst_pixmap == src_pixmap) { 295 /* pixmap glXWaitX */ 296 if (pSrcBuffer->attachment == DRI2BufferFrontLeft && 297 pDestBuffer->attachment == DRI2BufferFakeFrontLeft) { 298 ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, NULL); 299 return; 300 } 301 /* pixmap glXWaitGL */ 302 if (pDestBuffer->attachment == DRI2BufferFrontLeft && 303 pSrcBuffer->attachment == DRI2BufferFakeFrontLeft) { 304 return; 305 } else { 306 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 307 "copying between the same pixmap\n"); 308 } 309 } 310 311 gc = GetScratchGC(pDraw->depth, pScreen); 312 copy_clip = REGION_CREATE(pScreen, NULL, 0); 313 REGION_COPY(pScreen, copy_clip, pRegion); 314 (*gc->funcs->ChangeClip) (gc, CT_REGION, copy_clip, 0); 315 ValidateGC(&dst_pixmap->drawable, gc); 316 317 /* If this is a full buffer swap, throttle on the previous one */ 318 if (dst_priv->fence && REGION_NUM_RECTS(pRegion) == 1) { 319 BoxPtr extents = REGION_EXTENTS(pScreen, pRegion); 320 321 if (extents->x1 == 0 && extents->y1 == 0 && 322 extents->x2 == pDraw->width && extents->y2 == pDraw->height) { 323 ms->screen->fence_finish(ms->screen, dst_priv->fence, 0); 324 ms->screen->fence_reference(ms->screen, &dst_priv->fence, NULL); 325 } 326 } 327 328 (*gc->ops->CopyArea)(&src_pixmap->drawable, &dst_pixmap->drawable, gc, 329 0, 0, pDraw->width, pDraw->height, 0, 0); 330 331 FreeScratchGC(gc); 332 333 ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, 334 pDestBuffer->attachment == DRI2BufferFrontLeft ? 335 &dst_priv->fence : NULL); 336} 337 338Bool 339driScreenInit(ScreenPtr pScreen) 340{ 341 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 342 modesettingPtr ms = modesettingPTR(pScrn); 343 DRI2InfoRec dri2info; 344 345#if defined(DRI2INFOREC_VERSION) 346 dri2info.version = DRI2INFOREC_VERSION; 347#else 348 dri2info.version = 1; 349#endif 350 dri2info.fd = ms->fd; 351 352 dri2info.driverName = pScrn->driverName; 353 dri2info.deviceName = "/dev/dri/card0"; /* FIXME */ 354 355#if defined(DRI2INFOREC_VERSION) && DRI2INFOREC_VERSION > 2 356 dri2info.CreateBuffer = driCreateBuffer; 357 dri2info.DestroyBuffer = driDestroyBuffer; 358#else 359 dri2info.CreateBuffers = driCreateBuffers; 360 dri2info.DestroyBuffers = driDestroyBuffers; 361#endif 362 dri2info.CopyRegion = driCopyRegion; 363 dri2info.Wait = NULL; 364 365 ms->d_depth_bits_last = 366 ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_X8Z24_UNORM, 367 PIPE_TEXTURE_2D, 368 PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); 369 ms->ds_depth_bits_last = 370 ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_S8Z24_UNORM, 371 PIPE_TEXTURE_2D, 372 PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); 373 374 return DRI2ScreenInit(pScreen, &dri2info); 375} 376 377void 378driCloseScreen(ScreenPtr pScreen) 379{ 380 DRI2CloseScreen(pScreen); 381} 382 383/* vim: set sw=4 ts=8 sts=4: */ 384