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