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