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