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