amdgpu_glamor.c revision 46845023
1/* 2 * Copyright © 2011 Intel Corporation. 3 * 2012 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation 7 * files (the "Software"), to deal in the Software without 8 * restriction, including without limitation the rights to use, copy, 9 * modify, merge, publish, distribute, sublicense, and/or sell copies 10 * of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including 14 * the next paragraph) shall be included in all copies or substantial 15 * portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 24 * DEALINGS IN THE SOFTWARE. 25 */ 26 27#ifdef HAVE_CONFIG_H 28#include "config.h" 29#endif 30 31#ifdef USE_GLAMOR 32 33#include <xf86.h> 34 35#include "amdgpu_bo_helper.h" 36#include "amdgpu_pixmap.h" 37#include "amdgpu_glamor.h" 38 39#include <gbm.h> 40 41#ifndef HAVE_GLAMOR_FINISH 42#include <GL/gl.h> 43#endif 44 45DevPrivateKeyRec amdgpu_pixmap_index; 46 47void amdgpu_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst) 48{ 49 AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(dst->drawable.pScreen)); 50 51 if (!info->use_glamor) 52 return; 53 glamor_egl_exchange_buffers(src, dst); 54} 55 56Bool amdgpu_glamor_create_screen_resources(ScreenPtr screen) 57{ 58 PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen); 59 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 60 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 61 62 if (!info->use_glamor) 63 return TRUE; 64 65#ifdef HAVE_GLAMOR_GLYPHS_INIT 66 if (!glamor_glyphs_init(screen)) 67 return FALSE; 68#endif 69 70 return amdgpu_glamor_create_textured_pixmap(screen_pixmap, 71 info->front_buffer); 72} 73 74Bool amdgpu_glamor_pre_init(ScrnInfoPtr scrn) 75{ 76 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 77 pointer glamor_module; 78 CARD32 version; 79 80#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,20,99,0,0) 81 if (scrn->depth < 24) { 82#else 83 if (scrn->depth < 15) { 84#endif 85 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 86 "Depth %d not supported with glamor, disabling\n", 87 scrn->depth); 88 return FALSE; 89 } 90 91#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,15,0,0,0) 92 if (!xf86LoaderCheckSymbol("glamor_egl_init")) { 93 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 94 "glamor requires Load \"glamoregl\" in " 95 "Section \"Module\", disabling.\n"); 96 return FALSE; 97 } 98#endif 99 100 /* Load glamor module */ 101 if ((glamor_module = xf86LoadSubModule(scrn, GLAMOR_EGL_MODULE_NAME))) { 102 version = xf86GetModuleVersion(glamor_module); 103 if (version < MODULE_VERSION_NUMERIC(0, 3, 1)) { 104 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 105 "Incompatible glamor version, required >= 0.3.0.\n"); 106 return FALSE; 107 } else { 108 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 109 110 if (scrn->depth == 30 && 111 version < MODULE_VERSION_NUMERIC(1, 0, 1)) { 112 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 113 "Depth 30 requires glamor >= 1.0.1 (xserver 1.20)," 114 " can't enable glamor\n"); 115 return FALSE; 116 } 117 118 if (glamor_egl_init(scrn, pAMDGPUEnt->fd)) { 119 xf86DrvMsg(scrn->scrnIndex, X_INFO, 120 "glamor detected, initialising EGL layer.\n"); 121 } else { 122 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 123 "glamor detected, failed to initialize EGL.\n"); 124 return FALSE; 125 } 126 } 127 } else { 128 xf86DrvMsg(scrn->scrnIndex, X_ERROR, "glamor not available\n"); 129 return FALSE; 130 } 131 132 info->use_glamor = TRUE; 133 134 return TRUE; 135} 136 137Bool 138amdgpu_glamor_create_textured_pixmap(PixmapPtr pixmap, struct amdgpu_buffer *bo) 139{ 140 ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen); 141 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 142 143 if ((info->use_glamor) == 0) 144 return TRUE; 145 146 if (bo->flags & AMDGPU_BO_FLAGS_GBM) { 147 return glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, 148 bo->bo.gbm 149#if XORG_VERSION_CURRENT > XORG_VERSION_NUMERIC(1,19,99,903,0) 150 , FALSE 151#endif 152 ); 153 } else { 154 uint32_t bo_handle; 155 156 if (!amdgpu_bo_get_handle(bo, &bo_handle)) 157 return FALSE; 158 159 return glamor_egl_create_textured_pixmap(pixmap, bo_handle, 160 pixmap->devKind); 161 } 162} 163 164static Bool amdgpu_glamor_destroy_pixmap(PixmapPtr pixmap) 165{ 166#ifndef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP 167 ScreenPtr screen = pixmap->drawable.pScreen; 168 AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(screen)); 169 Bool ret; 170#endif 171 172 if (pixmap->refcnt == 1) { 173 if (pixmap->devPrivate.ptr) { 174 struct amdgpu_buffer *bo = amdgpu_get_pixmap_bo(pixmap); 175 176 if (bo) 177 amdgpu_bo_unmap(bo); 178 } 179 180#ifdef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP 181 glamor_egl_destroy_textured_pixmap(pixmap); 182#endif 183 amdgpu_set_pixmap_bo(pixmap, NULL); 184 } 185 186#ifdef HAVE_GLAMOR_EGL_DESTROY_TEXTURED_PIXMAP 187 fbDestroyPixmap(pixmap); 188 return TRUE; 189#else 190 screen->DestroyPixmap = info->glamor.SavedDestroyPixmap; 191 ret = screen->DestroyPixmap(pixmap); 192 info->glamor.SavedDestroyPixmap = screen->DestroyPixmap; 193 screen->DestroyPixmap = amdgpu_glamor_destroy_pixmap; 194 195 return ret; 196#endif 197} 198 199static PixmapPtr 200amdgpu_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, 201 unsigned usage) 202{ 203 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 204 PixmapFormatPtr format = xf86GetPixFormat(scrn, depth); 205 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 206 struct amdgpu_pixmap *priv; 207 PixmapPtr pixmap, new_pixmap = NULL; 208 209 if (!format) 210 return NULL; 211 212 if (!(usage & AMDGPU_CREATE_PIXMAP_SCANOUT) && 213 !AMDGPU_CREATE_PIXMAP_SHARED(usage)) { 214 if (info->shadow_primary) { 215 if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP) 216 return fbCreatePixmap(screen, w, h, depth, usage); 217 218 usage |= AMDGPU_CREATE_PIXMAP_LINEAR | 219 AMDGPU_CREATE_PIXMAP_GTT; 220 } else if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP) { 221 if (w < scrn->virtualX || w > scrn->displayWidth || 222 h != scrn->virtualY || 223 format->bitsPerPixel != scrn->bitsPerPixel) { 224 pixmap = glamor_create_pixmap(screen, w, h, depth, usage); 225 if (pixmap) 226 return pixmap; 227 } else { 228 usage |= AMDGPU_CREATE_PIXMAP_SCANOUT; 229 } 230 } 231 } 232 233 if (w > 32767 || h > 32767) 234 return NullPixmap; 235 236 if (depth == 1) 237 return fbCreatePixmap(screen, w, h, depth, usage); 238 239 if (usage == CREATE_PIXMAP_USAGE_GLYPH_PICTURE && w <= 32 && h <= 32) 240 return fbCreatePixmap(screen, w, h, depth, usage); 241 242 pixmap = fbCreatePixmap(screen, 0, 0, depth, usage); 243 if (pixmap == NullPixmap) 244 return pixmap; 245 246 if (w && h) { 247 int stride; 248 249 priv = calloc(1, sizeof(struct amdgpu_pixmap)); 250 if (!priv) 251 goto fallback_pixmap; 252 253 priv->bo = amdgpu_alloc_pixmap_bo(scrn, w, h, depth, usage, 254 pixmap->drawable.bitsPerPixel, 255 &stride); 256 if (!priv->bo) 257 goto fallback_priv; 258 259 amdgpu_set_pixmap_private(pixmap, priv); 260 261 screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL); 262 263 pixmap->devPrivate.ptr = NULL; 264 265 if (!amdgpu_glamor_create_textured_pixmap(pixmap, priv->bo)) 266 goto fallback_glamor; 267 } 268 269 return pixmap; 270 271fallback_glamor: 272 if (AMDGPU_CREATE_PIXMAP_SHARED(usage)) { 273 /* XXX need further work to handle the DRI2 failure case. 274 * Glamor don't know how to handle a BO only pixmap. Put 275 * a warning indicator here. 276 */ 277 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 278 "Failed to create textured DRI2/PRIME pixmap."); 279 280 amdgpu_glamor_destroy_pixmap(pixmap); 281 return NullPixmap; 282 } 283 /* Create textured pixmap failed means glamor failed to 284 * create a texture from current BO for some reasons. We turn 285 * to create a new glamor pixmap and clean up current one. 286 * One thing need to be noted, this new pixmap doesn't 287 * has a priv and bo attached to it. It's glamor's responsbility 288 * to take care of it. Glamor will mark this new pixmap as a 289 * texture only pixmap and will never fallback to DDX layer 290 * afterwards. 291 */ 292 new_pixmap = glamor_create_pixmap(screen, w, h, depth, usage); 293 amdgpu_bo_unref(&priv->bo); 294fallback_priv: 295 free(priv); 296fallback_pixmap: 297 fbDestroyPixmap(pixmap); 298 if (new_pixmap) 299 return new_pixmap; 300 else 301 return fbCreatePixmap(screen, w, h, depth, usage); 302} 303 304PixmapPtr 305amdgpu_glamor_set_pixmap_bo(DrawablePtr drawable, PixmapPtr pixmap) 306{ 307 PixmapPtr old = get_drawable_pixmap(drawable); 308 ScreenPtr screen = drawable->pScreen; 309 struct amdgpu_pixmap *priv = amdgpu_get_pixmap_private(pixmap); 310 GCPtr gc; 311 312 /* With a glamor pixmap, 2D pixmaps are created in texture 313 * and without a static BO attached to it. To support DRI, 314 * we need to create a new textured-drm pixmap and 315 * need to copy the original content to this new textured-drm 316 * pixmap, and then convert the old pixmap to a coherent 317 * textured-drm pixmap which has a valid BO attached to it 318 * and also has a valid texture, thus both glamor and DRI2 319 * can access it. 320 * 321 */ 322 323 /* Copy the current contents of the pixmap to the bo. */ 324 gc = GetScratchGC(drawable->depth, screen); 325 if (gc) { 326 ValidateGC(&pixmap->drawable, gc); 327 gc->ops->CopyArea(&old->drawable, &pixmap->drawable, 328 gc, 329 0, 0, 330 old->drawable.width, 331 old->drawable.height, 0, 0); 332 FreeScratchGC(gc); 333 } 334 335 /* And redirect the pixmap to the new bo (for 3D). */ 336 glamor_egl_exchange_buffers(old, pixmap); 337 amdgpu_set_pixmap_private(pixmap, amdgpu_get_pixmap_private(old)); 338 amdgpu_set_pixmap_private(old, priv); 339 340 screen->ModifyPixmapHeader(old, 341 old->drawable.width, 342 old->drawable.height, 343 0, 0, pixmap->devKind, NULL); 344 old->devPrivate.ptr = NULL; 345 346 screen->DestroyPixmap(pixmap); 347 348 return old; 349} 350 351 352static Bool 353amdgpu_glamor_share_pixmap_backing(PixmapPtr pixmap, ScreenPtr secondary, 354 void **handle_p) 355{ 356 ScreenPtr screen = pixmap->drawable.pScreen; 357 AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(screen)); 358 uint64_t tiling_info; 359 CARD16 stride; 360 CARD32 size; 361 Bool is_linear; 362 int fd; 363 364 tiling_info = amdgpu_pixmap_get_tiling_info(pixmap); 365 366 if (info->family >= AMDGPU_FAMILY_AI) 367 is_linear = AMDGPU_TILING_GET(tiling_info, SWIZZLE_MODE) == 0; 368 else 369 is_linear = AMDGPU_TILING_GET(tiling_info, ARRAY_MODE) == 1; 370 371 if (!is_linear) { 372 PixmapPtr linear; 373 374 /* We don't want to re-allocate the screen pixmap as 375 * linear, to avoid trouble with page flipping 376 */ 377 if (screen->GetScreenPixmap(screen) == pixmap) 378 return FALSE; 379 380 linear = screen->CreatePixmap(screen, pixmap->drawable.width, 381 pixmap->drawable.height, 382 pixmap->drawable.depth, 383 CREATE_PIXMAP_USAGE_SHARED); 384 if (!linear) 385 return FALSE; 386 387 amdgpu_glamor_set_pixmap_bo(&pixmap->drawable, linear); 388 } 389 390 fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size); 391 if (fd < 0) 392 return FALSE; 393 394 *handle_p = (void *)(long)fd; 395 return TRUE; 396} 397 398static Bool 399amdgpu_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle) 400{ 401 ScreenPtr screen = pixmap->drawable.pScreen; 402 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 403 int ihandle = (int)(long)handle; 404 struct amdgpu_pixmap *priv; 405 406 if (!amdgpu_set_shared_pixmap_backing(pixmap, handle)) 407 return FALSE; 408 409 priv = amdgpu_get_pixmap_private(pixmap); 410 411 if (ihandle != -1 && 412 !amdgpu_glamor_create_textured_pixmap(pixmap, priv->bo)) { 413 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 414 "Failed to get PRIME drawable for glamor pixmap.\n"); 415 return FALSE; 416 } 417 418 screen->ModifyPixmapHeader(pixmap, 419 pixmap->drawable.width, 420 pixmap->drawable.height, 421 0, 0, 0, NULL); 422 423 return TRUE; 424} 425 426 427Bool amdgpu_glamor_init(ScreenPtr screen) 428{ 429 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 430 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 431#ifdef RENDER 432#ifdef HAVE_FBGLYPHS 433 UnrealizeGlyphProcPtr SavedUnrealizeGlyph = NULL; 434#endif 435 PictureScreenPtr ps = NULL; 436 437 if (info->shadow_primary) { 438 ps = GetPictureScreenIfSet(screen); 439 440 if (ps) { 441#ifdef HAVE_FBGLYPHS 442 SavedUnrealizeGlyph = ps->UnrealizeGlyph; 443#endif 444 info->glamor.SavedGlyphs = ps->Glyphs; 445 info->glamor.SavedTriangles = ps->Triangles; 446 info->glamor.SavedTrapezoids = ps->Trapezoids; 447 } 448 } 449#endif /* RENDER */ 450 451 if (!glamor_init(screen, GLAMOR_USE_EGL_SCREEN | GLAMOR_USE_SCREEN | 452 GLAMOR_USE_PICTURE_SCREEN | GLAMOR_INVERTED_Y_AXIS | 453 GLAMOR_NO_DRI3)) { 454 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 455 "Failed to initialize glamor.\n"); 456 return FALSE; 457 } 458 459 if (!glamor_egl_init_textured_pixmap(screen)) { 460 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 461 "Failed to initialize textured pixmap of screen for glamor.\n"); 462 return FALSE; 463 } 464 if (!dixRegisterPrivateKey(&amdgpu_pixmap_index, PRIVATE_PIXMAP, 0)) 465 return FALSE; 466 467 if (info->shadow_primary) 468 amdgpu_glamor_screen_init(screen); 469 470#if defined(RENDER) && defined(HAVE_FBGLYPHS) 471 /* For ShadowPrimary, we need fbUnrealizeGlyph instead of 472 * glamor_unrealize_glyph 473 */ 474 if (ps) 475 ps->UnrealizeGlyph = SavedUnrealizeGlyph; 476#endif 477 478 info->glamor.SavedCreatePixmap = screen->CreatePixmap; 479 screen->CreatePixmap = amdgpu_glamor_create_pixmap; 480 info->glamor.SavedDestroyPixmap = screen->DestroyPixmap; 481 screen->DestroyPixmap = amdgpu_glamor_destroy_pixmap; 482 info->glamor.SavedSharePixmapBacking = screen->SharePixmapBacking; 483 screen->SharePixmapBacking = amdgpu_glamor_share_pixmap_backing; 484 info->glamor.SavedSetSharedPixmapBacking = screen->SetSharedPixmapBacking; 485 screen->SetSharedPixmapBacking = 486 amdgpu_glamor_set_shared_pixmap_backing; 487 488 xf86DrvMsg(scrn->scrnIndex, X_INFO, "Use GLAMOR acceleration.\n"); 489 return TRUE; 490} 491 492void amdgpu_glamor_flush(ScrnInfoPtr pScrn) 493{ 494 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 495 496 if (info->use_glamor) { 497 glamor_block_handler(pScrn->pScreen); 498 } 499 500 info->gpu_flushed++; 501} 502 503void amdgpu_glamor_finish(ScrnInfoPtr pScrn) 504{ 505 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 506 507 if (info->use_glamor) { 508#if HAVE_GLAMOR_FINISH 509 glamor_finish(pScrn->pScreen); 510 info->gpu_flushed++; 511#else 512 amdgpu_glamor_flush(pScrn); 513 glFinish(); 514#endif 515 } 516} 517 518void 519amdgpu_glamor_fini(ScreenPtr screen) 520{ 521 AMDGPUInfoPtr info = AMDGPUPTR(xf86ScreenToScrn(screen)); 522 523 if (!info->use_glamor) 524 return; 525 526 screen->CreatePixmap = info->glamor.SavedCreatePixmap; 527 screen->DestroyPixmap = info->glamor.SavedDestroyPixmap; 528 screen->SharePixmapBacking = info->glamor.SavedSharePixmapBacking; 529 screen->SetSharedPixmapBacking = info->glamor.SavedSetSharedPixmapBacking; 530} 531 532XF86VideoAdaptorPtr amdgpu_glamor_xv_init(ScreenPtr pScreen, int num_adapt) 533{ 534 return glamor_xv_init(pScreen, num_adapt); 535} 536 537#endif /* USE_GLAMOR */ 538