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