xorg_dri2.c revision d28740c298968303500a8c43047ded2679e727ac
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_format.h" 44#include "util/u_rect.h" 45 46/* Make all the #if cases in the code esier to read */ 47/* XXX can it be set to 1? */ 48#ifndef DRI2INFOREC_VERSION 49#define DRI2INFOREC_VERSION 0 50#endif 51 52typedef struct { 53 PixmapPtr pPixmap; 54 struct pipe_texture *tex; 55 struct pipe_fence_handle *fence; 56} *BufferPrivatePtr; 57 58static Bool 59dri2_do_create_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer, unsigned int format) 60{ 61 struct pipe_texture *tex = NULL; 62 ScreenPtr pScreen = pDraw->pScreen; 63 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 64 modesettingPtr ms = modesettingPTR(pScrn); 65 struct exa_pixmap_priv *exa_priv; 66 BufferPrivatePtr private = buffer->driverPrivate; 67 PixmapPtr pPixmap; 68 unsigned stride, handle; 69 70 if (pDraw->type == DRAWABLE_PIXMAP) 71 pPixmap = (PixmapPtr) pDraw; 72 else 73 pPixmap = (*pScreen->GetWindowPixmap)((WindowPtr) pDraw); 74 exa_priv = exaGetPixmapDriverPrivate(pPixmap); 75 76 switch (buffer->attachment) { 77 default: 78 if (buffer->attachment != DRI2BufferFakeFrontLeft || 79 pDraw->type != DRAWABLE_PIXMAP) { 80 private->pPixmap = (*pScreen->CreatePixmap)(pScreen, pDraw->width, 81 pDraw->height, 82 pDraw->depth, 83 0); 84 } 85 break; 86 case DRI2BufferFrontLeft: 87 break; 88 case DRI2BufferStencil: 89#if DRI2INFOREC_VERSION >= 3 90 case DRI2BufferDepthStencil: 91#else 92 /* Works on old X servers because sanity checking is for the weak */ 93 case 9: 94#endif 95 if (exa_priv->depth_stencil_tex && 96 !util_format_is_depth_or_stencil(exa_priv->depth_stencil_tex->format)) 97 exa_priv->depth_stencil_tex = NULL; 98 /* Fall through */ 99 case DRI2BufferDepth: 100 if (exa_priv->depth_stencil_tex) 101 pipe_texture_reference(&tex, exa_priv->depth_stencil_tex); 102 else { 103 struct pipe_texture template; 104 memset(&template, 0, sizeof(template)); 105 template.target = PIPE_TEXTURE_2D; 106 if (buffer->attachment == DRI2BufferDepth) 107 template.format = ms->ds_depth_bits_last ? 108 PIPE_FORMAT_X8Z24_UNORM : PIPE_FORMAT_Z24X8_UNORM; 109 else 110 template.format = ms->ds_depth_bits_last ? 111 PIPE_FORMAT_S8Z24_UNORM : PIPE_FORMAT_Z24S8_UNORM; 112 pf_get_block(template.format, &template.block); 113 template.width0 = pDraw->width; 114 template.height0 = pDraw->height; 115 template.depth0 = 1; 116 template.last_level = 0; 117 template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL | 118 PIPE_TEXTURE_USAGE_DISPLAY_TARGET; 119 tex = ms->screen->texture_create(ms->screen, &template); 120 pipe_texture_reference(&exa_priv->depth_stencil_tex, tex); 121 } 122 break; 123 } 124 125 if (!private->pPixmap) { 126 private->pPixmap = pPixmap; 127 pPixmap->refcnt++; 128 } 129 130 if (!tex) { 131 /* First call to make sure we have a pixmap private */ 132 exaMoveInPixmap(private->pPixmap); 133 xorg_exa_set_shared_usage(private->pPixmap); 134 pScreen->ModifyPixmapHeader(private->pPixmap, 0, 0, 0, 0, 0, NULL); 135 /* Second call to make sure texture has valid contents */ 136 exaMoveInPixmap(private->pPixmap); 137 tex = xorg_exa_get_texture(private->pPixmap); 138 } 139 140 if (!tex) 141 FatalError("NO TEXTURE IN DRI2\n"); 142 143 ms->api->shared_handle_from_texture(ms->api, ms->screen, tex, &stride, &handle); 144 145 buffer->name = handle; 146 buffer->pitch = stride; 147 buffer->cpp = 4; 148 buffer->driverPrivate = private; 149 buffer->flags = 0; /* not tiled */ 150#if DRI2INFOREC_VERSION == 2 151 ((DRI2Buffer2Ptr)buffer)->format = 0; 152#elif DRI2INFOREC_VERSION >= 3 153 buffer->format = 0; 154#endif 155 private->tex = tex; 156 157 return TRUE; 158} 159 160static void 161dri2_do_destroy_buffer(DrawablePtr pDraw, DRI2BufferPtr buffer) 162{ 163 ScreenPtr pScreen = pDraw->pScreen; 164 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 165 modesettingPtr ms = modesettingPTR(pScrn); 166 BufferPrivatePtr private = buffer->driverPrivate; 167 struct exa_pixmap_priv *exa_priv = exaGetPixmapDriverPrivate(private->pPixmap); 168 169 pipe_texture_reference(&private->tex, NULL); 170 ms->screen->fence_reference(ms->screen, &private->fence, NULL); 171 pipe_texture_reference(&exa_priv->depth_stencil_tex, NULL); 172 (*pScreen->DestroyPixmap)(private->pPixmap); 173} 174 175#if DRI2INFOREC_VERSION >= 2 176 177static DRI2Buffer2Ptr 178dri2_create_buffer(DrawablePtr pDraw, unsigned int attachment, unsigned int format) 179{ 180 DRI2Buffer2Ptr buffer; 181 BufferPrivatePtr private; 182 183 buffer = xcalloc(1, sizeof *buffer); 184 if (!buffer) 185 return NULL; 186 187 private = xcalloc(1, sizeof *private); 188 if (!private) { 189 goto fail; 190 } 191 192 buffer->attachment = attachment; 193 buffer->driverPrivate = private; 194 195 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ 196 if (dri2_do_create_buffer(pDraw, (DRI2BufferPtr)buffer, format)) 197 return buffer; 198 199 xfree(private); 200fail: 201 xfree(buffer); 202 return NULL; 203} 204 205static void 206dri2_destroy_buffer(DrawablePtr pDraw, DRI2Buffer2Ptr buffer) 207{ 208 /* So far it is safe to downcast a DRI2Buffer2Ptr to DRI2BufferPtr */ 209 dri2_do_destroy_buffer(pDraw, (DRI2BufferPtr)buffer); 210 211 xfree(buffer->driverPrivate); 212 xfree(buffer); 213} 214 215#else /* DRI2INFOREC_VERSION < 2 */ 216 217static DRI2BufferPtr 218dri2_create_buffers(DrawablePtr pDraw, unsigned int *attachments, int count) 219{ 220 BufferPrivatePtr privates; 221 DRI2BufferPtr buffers; 222 int i; 223 224 buffers = xcalloc(count, sizeof *buffers); 225 if (!buffers) 226 goto fail_buffers; 227 228 privates = xcalloc(count, sizeof *privates); 229 if (!privates) 230 goto fail_privates; 231 232 for (i = 0; i < count; i++) { 233 buffers[i].attachment = attachments[i]; 234 buffers[i].driverPrivate = &privates[i]; 235 236 if (!dri2_do_create_buffer(pDraw, &buffers[i], 0)) 237 goto fail; 238 } 239 240 return buffers; 241 242fail: 243 xfree(privates); 244fail_privates: 245 xfree(buffers); 246fail_buffers: 247 return NULL; 248} 249 250static void 251dri2_destroy_buffers(DrawablePtr pDraw, DRI2BufferPtr buffers, int count) 252{ 253 int i; 254 255 for (i = 0; i < count; i++) { 256 dri2_do_destroy_buffer(pDraw, &buffers[i]); 257 } 258 259 if (buffers) { 260 xfree(buffers[0].driverPrivate); 261 xfree(buffers); 262 } 263} 264 265#endif /* DRI2INFOREC_VERSION >= 2 */ 266 267static void 268dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, 269 DRI2BufferPtr pDestBuffer, DRI2BufferPtr pSrcBuffer) 270{ 271 ScreenPtr pScreen = pDraw->pScreen; 272 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 273 modesettingPtr ms = modesettingPTR(pScrn); 274 BufferPrivatePtr dst_priv = pDestBuffer->driverPrivate; 275 BufferPrivatePtr src_priv = pSrcBuffer->driverPrivate; 276 DrawablePtr src_draw; 277 DrawablePtr dst_draw; 278 GCPtr gc; 279 RegionPtr copy_clip; 280 Bool save_accel; 281 282 /* 283 * In driCreateBuffers we dewrap windows into the 284 * backing pixmaps in order to get to the texture. 285 * We need to use the real drawable in CopyArea 286 * so that cliprects and offsets are correct. 287 */ 288 src_draw = (pSrcBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : 289 &src_priv->pPixmap->drawable; 290 dst_draw = (pDestBuffer->attachment == DRI2BufferFrontLeft) ? pDraw : 291 &dst_priv->pPixmap->drawable; 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_priv->pPixmap == src_priv->pPixmap) { 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_draw, 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 /* Try to make sure the blit will be accelerated */ 345 save_accel = ms->exa->accel; 346 ms->exa->accel = TRUE; 347 348 /* In case it won't be though, make sure the GPU copy contents of the 349 * source pixmap will be used for the software fallback - presumably the 350 * client modified them before calling in here. 351 */ 352 exaMoveInPixmap(src_priv->pPixmap); 353 DamageRegionAppend(src_draw, pRegion); 354 DamageRegionProcessPending(src_draw); 355 356 (*gc->ops->CopyArea)(src_draw, dst_draw, gc, 357 0, 0, pDraw->width, pDraw->height, 0, 0); 358 ms->exa->accel = save_accel; 359 360 FreeScratchGC(gc); 361 362 ms->ctx->flush(ms->ctx, PIPE_FLUSH_SWAPBUFFERS, 363 pDestBuffer->attachment == DRI2BufferFrontLeft ? 364 &dst_priv->fence : NULL); 365} 366 367Bool 368xorg_dri2_init(ScreenPtr pScreen) 369{ 370 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 371 modesettingPtr ms = modesettingPTR(pScrn); 372 DRI2InfoRec dri2info; 373 374#if DRI2INFOREC_VERSION >= 2 375 dri2info.version = DRI2INFOREC_VERSION; 376#else 377 dri2info.version = 1; 378#endif 379 dri2info.fd = ms->fd; 380 381 dri2info.driverName = pScrn->driverName; 382 dri2info.deviceName = "/dev/dri/card0"; /* FIXME */ 383 384#if DRI2INFOREC_VERSION >= 2 385 dri2info.CreateBuffer = dri2_create_buffer; 386 dri2info.DestroyBuffer = dri2_destroy_buffer; 387#else 388 dri2info.CreateBuffers = dri2_create_buffers; 389 dri2info.DestroyBuffers = dri2_destroy_buffers; 390#endif 391 dri2info.CopyRegion = dri2_copy_region; 392 dri2info.Wait = NULL; 393 394 ms->d_depth_bits_last = 395 ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_X8Z24_UNORM, 396 PIPE_TEXTURE_2D, 397 PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); 398 ms->ds_depth_bits_last = 399 ms->screen->is_format_supported(ms->screen, PIPE_FORMAT_S8Z24_UNORM, 400 PIPE_TEXTURE_2D, 401 PIPE_TEXTURE_USAGE_DEPTH_STENCIL, 0); 402 403 return DRI2ScreenInit(pScreen, &dri2info); 404} 405 406void 407xorg_dri2_close(ScreenPtr pScreen) 408{ 409 DRI2CloseScreen(pScreen); 410} 411 412/* vim: set sw=4 ts=8 sts=4: */ 413