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