xorg_exa.c revision 05aa56a8275cc6f78e85b1fdf731500d1a5e5b08
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_exa.h" 32#include "xorg_tracker.h" 33#include "xorg_composite.h" 34 35#include <xorg-server.h> 36#include <xf86.h> 37#include <picturestr.h> 38#include <picture.h> 39 40#include "pipe/p_format.h" 41#include "pipe/p_context.h" 42#include "pipe/p_state.h" 43#include "pipe/p_inlines.h" 44 45#include "cso_cache/cso_context.h" 46 47#include "util/u_rect.h" 48 49/* 50 * Helper functions 51 */ 52 53static void 54exa_get_pipe_format(int depth, enum pipe_format *format, int *bbp) 55{ 56 switch (depth) { 57 case 32: 58 *format = PIPE_FORMAT_A8R8G8B8_UNORM; 59 assert(*bbp == 32); 60 break; 61 case 24: 62 *format = PIPE_FORMAT_X8R8G8B8_UNORM; 63 assert(*bbp == 32); 64 break; 65 case 16: 66 *format = PIPE_FORMAT_R5G6B5_UNORM; 67 assert(*bbp == 16); 68 break; 69 case 15: 70 *format = PIPE_FORMAT_A1R5G5B5_UNORM; 71 assert(*bbp == 16); 72 break; 73 case 8: 74 case 4: 75 case 1: 76 *format = PIPE_FORMAT_A8R8G8B8_UNORM; /* bad bad bad */ 77 break; 78 default: 79 assert(0); 80 break; 81 } 82} 83 84/* 85 * Static exported EXA functions 86 */ 87 88static void 89ExaWaitMarker(ScreenPtr pScreen, int marker) 90{ 91} 92 93static int 94ExaMarkSync(ScreenPtr pScreen) 95{ 96 return 1; 97} 98 99static Bool 100ExaPrepareAccess(PixmapPtr pPix, int index) 101{ 102 ScreenPtr pScreen = pPix->drawable.pScreen; 103 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 104 modesettingPtr ms = modesettingPTR(pScrn); 105 struct exa_context *exa = ms->exa; 106 struct exa_pixmap_priv *priv; 107 108 priv = exaGetPixmapDriverPrivate(pPix); 109 110 if (!priv) 111 return FALSE; 112 113 if (!priv->tex) 114 return FALSE; 115 116 if (priv->map_count++ == 0) 117 { 118 if (exa->ctx->is_texture_referenced(exa->ctx, priv->tex, 0, 0) & 119 PIPE_REFERENCED_FOR_WRITE) 120 exa->ctx->flush(exa->ctx, 0, NULL); 121 122 priv->map_transfer = 123 exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0, 124 PIPE_TRANSFER_READ_WRITE, 125 0, 0, priv->tex->width[0], priv->tex->height[0]); 126 127 pPix->devPrivate.ptr = 128 exa->scrn->transfer_map(exa->scrn, priv->map_transfer); 129 pPix->devKind = priv->map_transfer->stride; 130 } 131 132 return TRUE; 133} 134 135static void 136ExaFinishAccess(PixmapPtr pPix, int index) 137{ 138 ScreenPtr pScreen = pPix->drawable.pScreen; 139 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 140 modesettingPtr ms = modesettingPTR(pScrn); 141 struct exa_context *exa = ms->exa; 142 struct exa_pixmap_priv *priv; 143 priv = exaGetPixmapDriverPrivate(pPix); 144 145 if (!priv) 146 return; 147 148 if (!priv->map_transfer) 149 return; 150 151 if (--priv->map_count == 0) { 152 assert(priv->map_transfer); 153 exa->scrn->transfer_unmap(exa->scrn, priv->map_transfer); 154 exa->scrn->tex_transfer_destroy(priv->map_transfer); 155 priv->map_transfer = NULL; 156 } 157} 158 159static void 160ExaDone(PixmapPtr pPixmap) 161{ 162 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; 163 modesettingPtr ms = modesettingPTR(pScrn); 164 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); 165 struct exa_context *exa = ms->exa; 166 167 if (!priv) 168 return; 169 170 if (priv->src_surf) 171 exa->scrn->tex_surface_destroy(priv->src_surf); 172 priv->src_surf = NULL; 173} 174 175static void 176ExaDoneComposite(PixmapPtr pPixmap) 177{ 178 179} 180 181static Bool 182ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg) 183{ 184 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; 185 modesettingPtr ms = modesettingPTR(pScrn); 186 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); 187 struct exa_context *exa = ms->exa; 188 189 if (1) 190 return FALSE; 191 192 if (pPixmap->drawable.depth < 15) 193 return FALSE; 194 195 if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask)) 196 return FALSE; 197 198 if (!priv || !priv->tex) 199 return FALSE; 200 201 if (alu != GXcopy) 202 return FALSE; 203 204 if (!exa->ctx || !exa->ctx->surface_fill) 205 return FALSE; 206 207 priv->color = fg; 208 209 return TRUE; 210} 211 212static void 213ExaSolid(PixmapPtr pPixmap, int x0, int y0, int x1, int y1) 214{ 215 ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum]; 216 modesettingPtr ms = modesettingPTR(pScrn); 217 struct exa_context *exa = ms->exa; 218 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); 219 struct pipe_surface *surf = 220 exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0, 221 PIPE_BUFFER_USAGE_GPU_READ | 222 PIPE_BUFFER_USAGE_GPU_WRITE); 223 224 exa->ctx->surface_fill(exa->ctx, surf, x0, y0, x1 - x0, y1 - y0, 225 priv->color); 226 227 exa->scrn->tex_surface_destroy(surf); 228} 229 230static Bool 231ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir, 232 int ydir, int alu, Pixel planeMask) 233{ 234 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; 235 modesettingPtr ms = modesettingPTR(pScrn); 236 struct exa_context *exa = ms->exa; 237 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); 238 struct exa_pixmap_priv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap); 239 240 if (1) 241 return FALSE; 242 243 if (alu != GXcopy) 244 return FALSE; 245 246 if (pSrcPixmap->drawable.depth < 15 || pDstPixmap->drawable.depth < 15) 247 return FALSE; 248 249 if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask)) 250 return FALSE; 251 252 if (!priv || !src_priv) 253 return FALSE; 254 255 if (!priv->tex || !src_priv->tex) 256 return FALSE; 257 258 if (!exa->ctx || !exa->ctx->surface_copy) 259 return FALSE; 260 261 priv->src_surf = 262 exa->scrn->get_tex_surface(exa->scrn, src_priv->tex, 0, 0, 0, 263 PIPE_BUFFER_USAGE_GPU_READ | 264 PIPE_BUFFER_USAGE_GPU_WRITE); 265 266 return TRUE; 267} 268 269static void 270ExaCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, 271 int width, int height) 272{ 273 ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum]; 274 modesettingPtr ms = modesettingPTR(pScrn); 275 struct exa_context *exa = ms->exa; 276 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDstPixmap); 277 struct pipe_surface *surf = 278 exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0, 279 PIPE_BUFFER_USAGE_GPU_READ | 280 PIPE_BUFFER_USAGE_GPU_WRITE); 281 282 exa->ctx->surface_copy(exa->ctx, surf, dstX, dstY, priv->src_surf, 283 srcX, srcY, width, height); 284 exa->scrn->tex_surface_destroy(surf); 285} 286 287static Bool 288ExaPrepareComposite(int op, PicturePtr pSrcPicture, 289 PicturePtr pMaskPicture, PicturePtr pDstPicture, 290 PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) 291{ 292 ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; 293 modesettingPtr ms = modesettingPTR(pScrn); 294 struct exa_context *exa = ms->exa; 295 296 return xorg_composite_bind_state(exa, op, pSrcPicture, pMaskPicture, 297 pDstPicture); 298} 299 300static void 301ExaComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY, 302 int dstX, int dstY, int width, int height) 303{ 304 ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum]; 305 modesettingPtr ms = modesettingPTR(pScrn); 306 struct exa_context *exa = ms->exa; 307 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pDst); 308 309 xorg_composite(exa, priv, srcX, srcY, maskX, maskY, 310 dstX, dstY, width, height); 311} 312 313static Bool 314ExaCheckComposite(int op, 315 PicturePtr pSrcPicture, PicturePtr pMaskPicture, 316 PicturePtr pDstPicture) 317{ 318 return xorg_composite_accelerated(op, 319 pSrcPicture, 320 pMaskPicture, 321 pDstPicture); 322} 323 324static void * 325ExaCreatePixmap(ScreenPtr pScreen, int size, int align) 326{ 327 struct exa_pixmap_priv *priv; 328 329 priv = xcalloc(1, sizeof(struct exa_pixmap_priv)); 330 if (!priv) 331 return NULL; 332 333 return priv; 334} 335 336static void 337ExaDestroyPixmap(ScreenPtr pScreen, void *dPriv) 338{ 339 struct exa_pixmap_priv *priv = (struct exa_pixmap_priv *)dPriv; 340 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 341 modesettingPtr ms = modesettingPTR(pScrn); 342 343 if (!priv) 344 return; 345 346 if (priv->tex) 347 ms->screen->texture_destroy(priv->tex); 348 349 xfree(priv); 350} 351 352static Bool 353ExaPixmapIsOffscreen(PixmapPtr pPixmap) 354{ 355 struct exa_pixmap_priv *priv; 356 357 priv = exaGetPixmapDriverPrivate(pPixmap); 358 359 if (!priv) 360 return FALSE; 361 362 if (priv->tex) 363 return TRUE; 364 365 return FALSE; 366} 367 368int 369xorg_exa_set_displayed_usage(PixmapPtr pPixmap) 370{ 371 struct exa_pixmap_priv *priv; 372 priv = exaGetPixmapDriverPrivate(pPixmap); 373 374 if (!priv) { 375 FatalError("NO PIXMAP PRIVATE\n"); 376 return 0; 377 } 378 379 if (priv->flags & ~PIPE_TEXTURE_USAGE_PRIMARY) { 380 FatalError("BAD FLAGS\n"); 381 return 0; 382 } 383 priv->flags = PIPE_TEXTURE_USAGE_PRIMARY; 384 385 return 0; 386} 387 388int 389xorg_exa_set_shared_usage(PixmapPtr pPixmap) 390{ 391 struct exa_pixmap_priv *priv; 392 priv = exaGetPixmapDriverPrivate(pPixmap); 393 394 if (!priv) { 395 FatalError("NO PIXMAP PRIVATE\n"); 396 return 0; 397 } 398 399 if (priv->flags & ~PIPE_TEXTURE_USAGE_DISPLAY_TARGET) { 400 FatalError("BAD FLAGS\n"); 401 return 0; 402 } 403 priv->flags = PIPE_TEXTURE_USAGE_DISPLAY_TARGET; 404 405 return 0; 406} 407 408unsigned 409xorg_exa_get_pixmap_handle(PixmapPtr pPixmap, unsigned *stride_out) 410{ 411 ScreenPtr pScreen = pPixmap->drawable.pScreen; 412 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 413 modesettingPtr ms = modesettingPTR(pScrn); 414 struct exa_pixmap_priv *priv; 415 struct pipe_buffer *buffer = NULL; 416 unsigned handle; 417 unsigned stride; 418 419 if (!ms->exa) { 420 FatalError("NO MS->EXA\n"); 421 return 0; 422 } 423 424 priv = exaGetPixmapDriverPrivate(pPixmap); 425 426 if (!priv) { 427 FatalError("NO PIXMAP PRIVATE\n"); 428 return 0; 429 } 430 431 ms->api->buffer_from_texture(ms->api, priv->tex, &buffer, &stride); 432 ms->api->handle_from_buffer(ms->api, ms->screen, buffer, &handle); 433 pipe_buffer_reference(&buffer, NULL); 434 if (stride_out) 435 *stride_out = stride; 436 437 return handle; 438} 439 440static Bool 441ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height, 442 int depth, int bitsPerPixel, int devKind, 443 pointer pPixData) 444{ 445 ScreenPtr pScreen = pPixmap->drawable.pScreen; 446 ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; 447 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); 448 modesettingPtr ms = modesettingPTR(pScrn); 449 struct exa_context *exa = ms->exa; 450 451 if (!priv) 452 return FALSE; 453 454 if (depth <= 0) 455 depth = pPixmap->drawable.depth; 456 457 if (bitsPerPixel <= 0) 458 bitsPerPixel = pPixmap->drawable.bitsPerPixel; 459 460 if (width <= 0) 461 width = pPixmap->drawable.width; 462 463 if (height <= 0) 464 height = pPixmap->drawable.height; 465 466 if (width <= 0 || height <= 0 || depth <= 0) 467 return FALSE; 468 469 miModifyPixmapHeader(pPixmap, width, height, depth, 470 bitsPerPixel, devKind, NULL); 471 472 /* Deal with screen resize */ 473 if (priv->tex && (priv->tex->width[0] != width || 474 priv->tex->height[0] != height || 475 priv->tex_flags != priv->flags)) { 476 pipe_texture_reference(&priv->tex, NULL); 477 } 478 479 if (!priv->tex 480#ifdef DRM_MODE_FEATURE_DIRTYFB 481 && priv->flags 482#endif 483 ) { 484 struct pipe_texture template; 485 486 memset(&template, 0, sizeof(template)); 487 template.target = PIPE_TEXTURE_2D; 488 exa_get_pipe_format(depth, &template.format, &bitsPerPixel); 489 pf_get_block(template.format, &template.block); 490 template.width[0] = width; 491 template.height[0] = height; 492 template.depth[0] = 1; 493 template.last_level = 0; 494 template.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET | priv->flags; 495 priv->tex_flags = priv->flags; 496 priv->tex = exa->scrn->texture_create(exa->scrn, &template); 497 } 498 499#ifdef DRM_MODE_FEATURE_DIRTYFB 500 if (!priv->tex) { 501 if (pPixData) 502 pPixmap->devPrivate.ptr = pPixData; 503 else 504 pPixmap->devPrivate.ptr = xalloc(pPixmap->drawable.height * pPixmap->devKind); 505 } else 506#endif 507 if (pPixData) { 508 struct pipe_transfer *transfer = 509 exa->scrn->get_tex_transfer(exa->scrn, priv->tex, 0, 0, 0, 510 PIPE_TRANSFER_WRITE, 511 0, 0, width, height); 512 util_copy_rect(exa->scrn->transfer_map(exa->scrn, transfer), 513 &priv->tex->block, transfer->stride, 0, 0, 514 width, height, pPixData, pPixmap->devKind, 0, 0); 515 exa->scrn->transfer_unmap(exa->scrn, transfer); 516 exa->scrn->tex_transfer_destroy(transfer); 517 } 518 519 return TRUE; 520} 521 522struct pipe_texture * 523xorg_exa_get_texture(PixmapPtr pPixmap) 524{ 525 struct exa_pixmap_priv *priv = exaGetPixmapDriverPrivate(pPixmap); 526 struct pipe_texture *tex = NULL; 527 pipe_texture_reference(&tex, priv->tex); 528 return tex; 529} 530 531void 532xorg_exa_close(ScrnInfoPtr pScrn) 533{ 534 modesettingPtr ms = modesettingPTR(pScrn); 535 struct exa_context *exa = ms->exa; 536 537 if (exa->cso) { 538 cso_release_all(exa->cso); 539 cso_destroy_context(exa->cso); 540 } 541 542 if (exa->ctx) 543 exa->ctx->destroy(exa->ctx); 544 545 exaDriverFini(pScrn->pScreen); 546 xfree(exa); 547 ms->exa = NULL; 548} 549 550void * 551xorg_exa_init(ScrnInfoPtr pScrn) 552{ 553 modesettingPtr ms = modesettingPTR(pScrn); 554 struct exa_context *exa; 555 ExaDriverPtr pExa; 556 557 exa = xcalloc(1, sizeof(struct exa_context)); 558 if (!exa) 559 return NULL; 560 561 pExa = exaDriverAlloc(); 562 if (!pExa) { 563 goto out_err; 564 } 565 566 memset(pExa, 0, sizeof(*pExa)); 567 568 pExa->exa_major = 2; 569 pExa->exa_minor = 2; 570 pExa->memoryBase = 0; 571 pExa->memorySize = 0; 572 pExa->offScreenBase = 0; 573 pExa->pixmapOffsetAlign = 0; 574 pExa->pixmapPitchAlign = 1; 575 pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS; 576 pExa->maxX = 8191; /* FIXME */ 577 pExa->maxY = 8191; /* FIXME */ 578 579 pExa->WaitMarker = ExaWaitMarker; 580 pExa->MarkSync = ExaMarkSync; 581 pExa->PrepareSolid = ExaPrepareSolid; 582 pExa->Solid = ExaSolid; 583 pExa->DoneSolid = ExaDone; 584 pExa->PrepareCopy = ExaPrepareCopy; 585 pExa->Copy = ExaCopy; 586 pExa->DoneCopy = ExaDone; 587 pExa->CheckComposite = ExaCheckComposite; 588 pExa->PrepareComposite = ExaPrepareComposite; 589 pExa->Composite = ExaComposite; 590 pExa->DoneComposite = ExaDoneComposite; 591 pExa->PixmapIsOffscreen = ExaPixmapIsOffscreen; 592 pExa->PrepareAccess = ExaPrepareAccess; 593 pExa->FinishAccess = ExaFinishAccess; 594 pExa->CreatePixmap = ExaCreatePixmap; 595 pExa->DestroyPixmap = ExaDestroyPixmap; 596 pExa->ModifyPixmapHeader = ExaModifyPixmapHeader; 597 598 if (!exaDriverInit(pScrn->pScreen, pExa)) { 599 goto out_err; 600 } 601 602 exa->scrn = ms->screen; 603 exa->ctx = ms->api->create_context(ms->api, exa->scrn); 604 /* Share context with DRI */ 605 ms->ctx = exa->ctx; 606 607 exa->cso = cso_create_context(exa->ctx); 608 609 return (void *)exa; 610 611 out_err: 612 xorg_exa_close(pScrn); 613 614 return NULL; 615} 616 617/* vim: set sw=4 ts=8 sts=4: */ 618