uxa.c revision 428d7b3d
1/* 2 * Copyright © 2001 Keith Packard 3 * 4 * Partly based on code that is Copyright © The XFree86 Project Inc. 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Keith Packard not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. Keith Packard makes no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25/** @file 26 * This file covers the initialization and teardown of UXA, and has various 27 * functions not responsible for performing rendering, pixmap migration, or 28 * memory management. 29 */ 30 31#ifdef HAVE_DIX_CONFIG_H 32#include <dix-config.h> 33#endif 34 35#include <stdlib.h> 36 37#include "uxa-priv.h" 38#include <X11/fonts/fontstruct.h> 39#include "dixfontstr.h" 40#include "uxa.h" 41 42#if HAS_DEVPRIVATEKEYREC 43DevPrivateKeyRec uxa_screen_index; 44#else 45int uxa_screen_index; 46#endif 47 48/** 49 * uxa_get_drawable_pixmap() returns a backing pixmap for a given drawable. 50 * 51 * @param pDrawable the drawable being requested. 52 * 53 * This function returns the backing pixmap for a drawable, whether it is a 54 * redirected window, unredirected window, or already a pixmap. Note that 55 * coordinate translation is needed when drawing to the backing pixmap of a 56 * redirected window, and the translation coordinates are provided by calling 57 * uxa_get_drawable_pixmap() on the drawable. 58 */ 59PixmapPtr uxa_get_drawable_pixmap(DrawablePtr pDrawable) 60{ 61 if (pDrawable->type == DRAWABLE_WINDOW) 62 return pDrawable->pScreen-> 63 GetWindowPixmap((WindowPtr) pDrawable); 64 else 65 return (PixmapPtr) pDrawable; 66} 67 68/** 69 * Sets the offsets to add to coordinates to make them address the same bits in 70 * the backing drawable. These coordinates are nonzero only for redirected 71 * windows. 72 */ 73void 74uxa_get_drawable_deltas(DrawablePtr pDrawable, PixmapPtr pPixmap, 75 int *xp, int *yp) 76{ 77#ifdef COMPOSITE 78 if (pDrawable->type == DRAWABLE_WINDOW) { 79 *xp = -pPixmap->screen_x; 80 *yp = -pPixmap->screen_y; 81 return; 82 } 83#endif 84 85 *xp = 0; 86 *yp = 0; 87} 88 89/** 90 * uxa_pixmap_is_offscreen() is used to determine if a pixmap is in offscreen 91 * memory, meaning that acceleration could probably be done to it, and that it 92 * will need to be wrapped by PrepareAccess()/FinishAccess() when accessing it 93 * with the CPU. 94 * 95 * Note that except for UploadToScreen()/DownloadFromScreen() (which explicitly 96 * deal with moving pixmaps in and out of system memory), UXA will give drivers 97 * pixmaps as arguments for which uxa_pixmap_is_offscreen() is TRUE. 98 * 99 * @return TRUE if the given drawable is in framebuffer memory. 100 */ 101Bool uxa_pixmap_is_offscreen(PixmapPtr p) 102{ 103 ScreenPtr pScreen = p->drawable.pScreen; 104 uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 105 106 if (uxa_screen->info->pixmap_is_offscreen) 107 return uxa_screen->info->pixmap_is_offscreen(p); 108 109 return FALSE; 110} 111 112/** 113 * uxa_drawable_is_offscreen() is a convenience wrapper for 114 * uxa_pixmap_is_offscreen(). 115 */ 116Bool uxa_drawable_is_offscreen(DrawablePtr pDrawable) 117{ 118 return uxa_pixmap_is_offscreen(uxa_get_drawable_pixmap(pDrawable)); 119} 120 121/** 122 * Returns the pixmap which backs a drawable, and the offsets to add to 123 * coordinates to make them address the same bits in the backing drawable. 124 */ 125PixmapPtr uxa_get_offscreen_pixmap(DrawablePtr drawable, int *xp, int *yp) 126{ 127 PixmapPtr pixmap = uxa_get_drawable_pixmap(drawable); 128 129 uxa_get_drawable_deltas(drawable, pixmap, xp, yp); 130 131 if (uxa_pixmap_is_offscreen(pixmap)) 132 return pixmap; 133 else 134 return NULL; 135} 136 137/** 138 * uxa_prepare_access() is UXA's wrapper for the driver's PrepareAccess() handler. 139 * 140 * It deals with waiting for synchronization with the card, determining if 141 * PrepareAccess() is necessary, and working around PrepareAccess() failure. 142 */ 143Bool uxa_prepare_access(DrawablePtr pDrawable, uxa_access_t access) 144{ 145 ScreenPtr pScreen = pDrawable->pScreen; 146 uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 147 PixmapPtr pPixmap = uxa_get_drawable_pixmap(pDrawable); 148 Bool offscreen = uxa_pixmap_is_offscreen(pPixmap); 149 150 if (!offscreen) 151 return TRUE; 152 153 if (uxa_screen->info->prepare_access) 154 return (*uxa_screen->info->prepare_access) (pPixmap, access); 155 return TRUE; 156} 157 158/** 159 * uxa_finish_access() is UXA's wrapper for the driver's finish_access() handler. 160 * 161 * It deals with calling the driver's finish_access() only if necessary. 162 */ 163void uxa_finish_access(DrawablePtr pDrawable, uxa_access_t access) 164{ 165 ScreenPtr pScreen = pDrawable->pScreen; 166 uxa_screen_t *uxa_screen = uxa_get_screen(pScreen); 167 PixmapPtr pPixmap; 168 169 if (uxa_screen->info->finish_access == NULL) 170 return; 171 172 pPixmap = uxa_get_drawable_pixmap(pDrawable); 173 if (!uxa_pixmap_is_offscreen(pPixmap)) 174 return; 175 176 (*uxa_screen->info->finish_access) (pPixmap, access); 177} 178 179/** 180 * uxa_validate_gc() sets the ops to UXA's implementations, which may be 181 * accelerated or may sync the card and fall back to fb. 182 */ 183static void 184uxa_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) 185{ 186 /* fbValidateGC will do direct access to pixmaps if the tiling has 187 * changed. 188 * Preempt fbValidateGC by doing its work and masking the change out, so 189 * that we can do the Prepare/finish_access. 190 */ 191 192#ifdef FB_24_32BIT 193 if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) { 194 (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC)); 195 fbGetRotatedPixmap(pGC) = 0; 196 } 197 198 if (pGC->fillStyle == FillTiled) { 199 PixmapPtr pOldTile, pNewTile; 200 201 pOldTile = pGC->tile.pixmap; 202 if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) { 203 pNewTile = fbGetRotatedPixmap(pGC); 204 if (!pNewTile || 205 pNewTile->drawable.bitsPerPixel != 206 pDrawable->bitsPerPixel) { 207 if (pNewTile) 208 (*pGC->pScreen-> 209 DestroyPixmap) (pNewTile); 210 /* fb24_32ReformatTile will do direct access 211 * of a newly-allocated pixmap. This isn't a 212 * problem yet, since we don't put pixmaps in 213 * FB until at least one accelerated UXA op. 214 */ 215 if (uxa_prepare_access 216 (&pOldTile->drawable, UXA_ACCESS_RO)) { 217 pNewTile = 218 fb24_32ReformatTile(pOldTile, 219 pDrawable-> 220 bitsPerPixel); 221 uxa_finish_access(&pOldTile->drawable, UXA_ACCESS_RO); 222 } 223 } 224 if (pNewTile) { 225 fbGetRotatedPixmap(pGC) = pOldTile; 226 pGC->tile.pixmap = pNewTile; 227 changes |= GCTile; 228 } 229 } 230 } 231#endif 232 if (changes & GCTile) { 233 if (!pGC->tileIsPixel 234 && FbEvenTile(pGC->tile.pixmap->drawable.width * 235 pDrawable->bitsPerPixel)) { 236 if (uxa_prepare_access 237 (&pGC->tile.pixmap->drawable, UXA_ACCESS_RW)) { 238 fbPadPixmap(pGC->tile.pixmap); 239 uxa_finish_access(&pGC->tile.pixmap->drawable, UXA_ACCESS_RW); 240 } 241 } 242 /* Mask out the GCTile change notification, now that we've 243 * done FB's job for it. 244 */ 245 changes &= ~GCTile; 246 } 247 248 if (changes & GCStipple && pGC->stipple) { 249 /* We can't inline stipple handling like we do for GCTile 250 * because it sets fbgc privates. 251 */ 252 if (uxa_prepare_access(&pGC->stipple->drawable, UXA_ACCESS_RW)) { 253 fbValidateGC(pGC, changes, pDrawable); 254 uxa_finish_access(&pGC->stipple->drawable, UXA_ACCESS_RW); 255 } 256 } else { 257 fbValidateGC(pGC, changes, pDrawable); 258 } 259 260 pGC->ops = (GCOps *) & uxa_ops; 261} 262 263static GCFuncs uxaGCFuncs = { 264 uxa_validate_gc, 265 miChangeGC, 266 miCopyGC, 267 miDestroyGC, 268 miChangeClip, 269 miDestroyClip, 270 miCopyClip 271}; 272 273/** 274 * uxa_create_gc makes a new GC and hooks up its funcs handler, so that 275 * uxa_validate_gc() will get called. 276 */ 277static int uxa_create_gc(GCPtr pGC) 278{ 279 if (!fbCreateGC(pGC)) 280 return FALSE; 281 282 pGC->funcs = &uxaGCFuncs; 283 284 return TRUE; 285} 286 287Bool uxa_prepare_access_window(WindowPtr pWin) 288{ 289 if (pWin->backgroundState == BackgroundPixmap) { 290 if (!uxa_prepare_access 291 (&pWin->background.pixmap->drawable, UXA_ACCESS_RO)) 292 return FALSE; 293 } 294 295 if (pWin->borderIsPixel == FALSE) { 296 if (!uxa_prepare_access 297 (&pWin->border.pixmap->drawable, UXA_ACCESS_RO)) { 298 if (pWin->backgroundState == BackgroundPixmap) 299 uxa_finish_access(&pWin->background.pixmap-> 300 drawable, UXA_ACCESS_RO); 301 return FALSE; 302 } 303 } 304 return TRUE; 305} 306 307void uxa_finish_access_window(WindowPtr pWin) 308{ 309 if (pWin->backgroundState == BackgroundPixmap) 310 uxa_finish_access(&pWin->background.pixmap->drawable, UXA_ACCESS_RO); 311 312 if (pWin->borderIsPixel == FALSE) 313 uxa_finish_access(&pWin->border.pixmap->drawable, UXA_ACCESS_RO); 314} 315 316static Bool uxa_change_window_attributes(WindowPtr pWin, unsigned long mask) 317{ 318 Bool ret; 319 320 if (!uxa_prepare_access_window(pWin)) 321 return FALSE; 322 ret = fbChangeWindowAttributes(pWin, mask); 323 uxa_finish_access_window(pWin); 324 return ret; 325} 326 327static RegionPtr uxa_bitmap_to_region(PixmapPtr pPix) 328{ 329 RegionPtr ret; 330 if (!uxa_prepare_access(&pPix->drawable, UXA_ACCESS_RO)) 331 return NULL; 332 ret = fbPixmapToRegion(pPix); 333 uxa_finish_access(&pPix->drawable, UXA_ACCESS_RO); 334 return ret; 335} 336 337void uxa_set_fallback_debug(ScreenPtr screen, Bool enable) 338{ 339 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 340 341 uxa_screen->fallback_debug = enable; 342} 343 344void uxa_set_force_fallback(ScreenPtr screen, Bool value) 345{ 346 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 347 348 uxa_screen->force_fallback = value; 349} 350 351/** 352 * uxa_close_screen() unwraps its wrapped screen functions and tears down UXA's 353 * screen private, before calling down to the next CloseSccreen. 354 */ 355static Bool uxa_close_screen(CLOSE_SCREEN_ARGS_DECL) 356{ 357 uxa_screen_t *uxa_screen = uxa_get_screen(screen); 358#ifdef RENDER 359 PictureScreenPtr ps = GetPictureScreenIfSet(screen); 360#endif 361 int n; 362 363 if (uxa_screen->solid_clear) 364 FreePicture(uxa_screen->solid_clear, 0); 365 if (uxa_screen->solid_black) 366 FreePicture(uxa_screen->solid_black, 0); 367 if (uxa_screen->solid_white) 368 FreePicture(uxa_screen->solid_white, 0); 369 for (n = 0; n < uxa_screen->solid_cache_size; n++) 370 FreePicture(uxa_screen->solid_cache[n].picture, 0); 371 372 uxa_glyphs_fini(screen); 373 374#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,15,99,903,0) 375 if (screen->devPrivate) { 376 /* Destroy the pixmap created by miScreenInit() *before* 377 * chaining up as we finalize ourselves here and so this 378 * is the last chance we have of releasing our resources 379 * associated with the Pixmap. So do it first. 380 */ 381 (void) (*screen->DestroyPixmap) (screen->devPrivate); 382 screen->devPrivate = NULL; 383 } 384#endif 385 386 screen->CreateGC = uxa_screen->SavedCreateGC; 387 screen->CloseScreen = uxa_screen->SavedCloseScreen; 388 screen->GetImage = uxa_screen->SavedGetImage; 389 screen->GetSpans = uxa_screen->SavedGetSpans; 390 screen->CreatePixmap = uxa_screen->SavedCreatePixmap; 391 screen->DestroyPixmap = uxa_screen->SavedDestroyPixmap; 392 screen->CopyWindow = uxa_screen->SavedCopyWindow; 393 screen->ChangeWindowAttributes = 394 uxa_screen->SavedChangeWindowAttributes; 395 screen->BitmapToRegion = uxa_screen->SavedBitmapToRegion; 396#ifdef RENDER 397 if (ps) { 398 ps->Composite = uxa_screen->SavedComposite; 399 ps->Glyphs = uxa_screen->SavedGlyphs; 400 ps->Trapezoids = uxa_screen->SavedTrapezoids; 401 ps->AddTraps = uxa_screen->SavedAddTraps; 402 ps->Triangles = uxa_screen->SavedTriangles; 403 404 ps->UnrealizeGlyph = uxa_screen->SavedUnrealizeGlyph; 405 } 406#endif 407 408 free(uxa_screen); 409 410 return (*screen->CloseScreen) (CLOSE_SCREEN_ARGS); 411} 412 413/** 414 * This function allocates a driver structure for UXA drivers to fill in. By 415 * having UXA allocate the structure, the driver structure can be extended 416 * without breaking ABI between UXA and the drivers. The driver's 417 * responsibility is to check beforehand that the UXA module has a matching 418 * major number and sufficient minor. Drivers are responsible for freeing the 419 * driver structure using free(). 420 * 421 * @return a newly allocated, zero-filled driver structure 422 */ 423uxa_driver_t *uxa_driver_alloc(void) 424{ 425 return calloc(1, sizeof(uxa_driver_t)); 426} 427 428/** 429 * @param screen screen being initialized 430 * @param pScreenInfo UXA driver record 431 * 432 * uxa_driver_init sets up UXA given a driver record filled in by the driver. 433 * pScreenInfo should have been allocated by uxa_driver_alloc(). See the 434 * comments in _UxaDriver for what must be filled in and what is optional. 435 * 436 * @return TRUE if UXA was successfully initialized. 437 */ 438Bool uxa_driver_init(ScreenPtr screen, uxa_driver_t * uxa_driver) 439{ 440 uxa_screen_t *uxa_screen; 441 442 if (!uxa_driver) 443 return FALSE; 444 445 if (uxa_driver->uxa_major != UXA_VERSION_MAJOR || 446 uxa_driver->uxa_minor > UXA_VERSION_MINOR) { 447 LogMessage(X_ERROR, 448 "UXA(%d): driver's UXA version requirements " 449 "(%d.%d) are incompatible with UXA version (%d.%d)\n", 450 screen->myNum, uxa_driver->uxa_major, 451 uxa_driver->uxa_minor, UXA_VERSION_MAJOR, 452 UXA_VERSION_MINOR); 453 return FALSE; 454 } 455 456 if (!uxa_driver->prepare_solid) { 457 LogMessage(X_ERROR, 458 "UXA(%d): uxa_driver_t::prepare_solid must be " 459 "non-NULL\n", screen->myNum); 460 return FALSE; 461 } 462 463 if (!uxa_driver->prepare_copy) { 464 LogMessage(X_ERROR, 465 "UXA(%d): uxa_driver_t::prepare_copy must be " 466 "non-NULL\n", screen->myNum); 467 return FALSE; 468 } 469#if HAS_DIXREGISTERPRIVATEKEY 470 if (!dixRegisterPrivateKey(&uxa_screen_index, PRIVATE_SCREEN, 0)) 471 return FALSE; 472#endif 473 uxa_screen = calloc(sizeof(uxa_screen_t), 1); 474 475 if (!uxa_screen) { 476 LogMessage(X_WARNING, 477 "UXA(%d): Failed to allocate screen private\n", 478 screen->myNum); 479 return FALSE; 480 } 481 482 uxa_screen->info = uxa_driver; 483 484 dixSetPrivate(&screen->devPrivates, &uxa_screen_index, uxa_screen); 485 486 uxa_screen->force_fallback = FALSE; 487 488 uxa_screen->solid_cache_size = 0; 489 uxa_screen->solid_clear = 0; 490 uxa_screen->solid_black = 0; 491 uxa_screen->solid_white = 0; 492 493// exaDDXDriverInit(screen); 494 495 /* 496 * Replace various fb screen functions 497 */ 498 uxa_screen->SavedCloseScreen = screen->CloseScreen; 499 screen->CloseScreen = uxa_close_screen; 500 501 uxa_screen->SavedCreateGC = screen->CreateGC; 502 screen->CreateGC = uxa_create_gc; 503 504 uxa_screen->SavedGetImage = screen->GetImage; 505 screen->GetImage = uxa_get_image; 506 507 uxa_screen->SavedGetSpans = screen->GetSpans; 508 screen->GetSpans = uxa_get_spans; 509 510 uxa_screen->SavedCopyWindow = screen->CopyWindow; 511 screen->CopyWindow = uxa_copy_window; 512 513 uxa_screen->SavedChangeWindowAttributes = 514 screen->ChangeWindowAttributes; 515 screen->ChangeWindowAttributes = uxa_change_window_attributes; 516 517 uxa_screen->SavedBitmapToRegion = screen->BitmapToRegion; 518 screen->BitmapToRegion = uxa_bitmap_to_region; 519 520#ifdef RENDER 521 { 522 PictureScreenPtr ps = GetPictureScreenIfSet(screen); 523 if (ps) { 524 uxa_screen->SavedComposite = ps->Composite; 525 ps->Composite = uxa_composite; 526 527 uxa_screen->SavedGlyphs = ps->Glyphs; 528 ps->Glyphs = uxa_glyphs; 529 530 uxa_screen->SavedUnrealizeGlyph = ps->UnrealizeGlyph; 531 ps->UnrealizeGlyph = uxa_glyph_unrealize; 532 533 uxa_screen->SavedTriangles = ps->Triangles; 534 ps->Triangles = uxa_triangles; 535 536 uxa_screen->SavedTrapezoids = ps->Trapezoids; 537 ps->Trapezoids = uxa_trapezoids; 538 539 uxa_screen->SavedAddTraps = ps->AddTraps; 540 ps->AddTraps = uxa_add_traps; 541 } 542 } 543#endif 544 545 LogMessage(X_INFO, 546 "UXA(%d): Driver registered support for the following" 547 " operations:\n", screen->myNum); 548 assert(uxa_driver->prepare_solid != NULL); 549 LogMessage(X_INFO, " solid\n"); 550 assert(uxa_driver->prepare_copy != NULL); 551 LogMessage(X_INFO, " copy\n"); 552 if (uxa_driver->prepare_composite != NULL) { 553 LogMessage(X_INFO, " composite (RENDER acceleration)\n"); 554 } 555 if (uxa_driver->put_image != NULL) { 556 LogMessage(X_INFO, " put_image\n"); 557 } 558 if (uxa_driver->get_image != NULL) { 559 LogMessage(X_INFO, " get_image\n"); 560 } 561 562 return TRUE; 563} 564 565Bool uxa_resources_init(ScreenPtr screen) 566{ 567 if (!uxa_glyphs_init(screen)) 568 return FALSE; 569 570 return TRUE; 571} 572 573/** 574 * uxa_driver_fini tears down UXA on a given screen. 575 * 576 * @param pScreen screen being torn down. 577 */ 578void uxa_driver_fini(ScreenPtr pScreen) 579{ 580 /*right now does nothing */ 581} 582