drmmode_display.c revision 90f2b693
1/* 2 * Copyright © 2007 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Dave Airlie <airlied@redhat.com> 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <errno.h> 33#include <sys/ioctl.h> 34#include <time.h> 35#include "cursorstr.h" 36#include "damagestr.h" 37#include "inputstr.h" 38#include "list.h" 39#include "micmap.h" 40#include "mipointrst.h" 41#include "xf86cmap.h" 42#include "xf86Priv.h" 43#include "sarea.h" 44 45#include "drmmode_display.h" 46#include "amdgpu_bo_helper.h" 47#include "amdgpu_glamor.h" 48#include "amdgpu_pixmap.h" 49 50#include <dri.h> 51 52/* DPMS */ 53#ifdef HAVE_XEXTPROTO_71 54#include <X11/extensions/dpmsconst.h> 55#else 56#define DPMS_SERVER 57#include <X11/extensions/dpms.h> 58#endif 59 60#include <gbm.h> 61 62#define DEFAULT_NOMINAL_FRAME_RATE 60 63 64static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 65 66static Bool 67AMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 68{ 69 int i = 0; 70 char s1[20]; 71 72 do { 73 switch (*s) { 74 case ',': 75 s1[i] = '\0'; 76 i = 0; 77 if (strcmp(s1, output_name) == 0) 78 return TRUE; 79 break; 80 case ' ': 81 case '\t': 82 case '\n': 83 case '\r': 84 break; 85 default: 86 s1[i] = *s; 87 i++; 88 break; 89 } 90 } while (*s++); 91 92 s1[i] = '\0'; 93 if (strcmp(s1, output_name) == 0) 94 return TRUE; 95 96 return FALSE; 97} 98 99 100static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 101 int width, int height, 102 int depth, int bpp, 103 int pitch, 104 struct amdgpu_buffer *bo) 105{ 106 ScreenPtr pScreen = pScrn->pScreen; 107 PixmapPtr pixmap; 108 109 pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 110 AMDGPU_CREATE_PIXMAP_SCANOUT); 111 if (!pixmap) 112 return NULL; 113 114 if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height, 115 depth, bpp, pitch, NULL)) 116 goto fail; 117 118 if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo)) 119 goto fail; 120 121 if (amdgpu_set_pixmap_bo(pixmap, bo)) 122 return pixmap; 123 124fail: 125 pScreen->DestroyPixmap(pixmap); 126 return NULL; 127} 128 129static void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 130{ 131 ScreenPtr pScreen = pixmap->drawable.pScreen; 132 133 (*pScreen->DestroyPixmap) (pixmap); 134} 135 136static void 137drmmode_ConvertFromKMode(ScrnInfoPtr scrn, 138 drmModeModeInfo * kmode, DisplayModePtr mode) 139{ 140 memset(mode, 0, sizeof(DisplayModeRec)); 141 mode->status = MODE_OK; 142 143 mode->Clock = kmode->clock; 144 145 mode->HDisplay = kmode->hdisplay; 146 mode->HSyncStart = kmode->hsync_start; 147 mode->HSyncEnd = kmode->hsync_end; 148 mode->HTotal = kmode->htotal; 149 mode->HSkew = kmode->hskew; 150 151 mode->VDisplay = kmode->vdisplay; 152 mode->VSyncStart = kmode->vsync_start; 153 mode->VSyncEnd = kmode->vsync_end; 154 mode->VTotal = kmode->vtotal; 155 mode->VScan = kmode->vscan; 156 157 mode->Flags = kmode->flags; //& FLAG_BITS; 158 mode->name = strdup(kmode->name); 159 160 if (kmode->type & DRM_MODE_TYPE_DRIVER) 161 mode->type = M_T_DRIVER; 162 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 163 mode->type |= M_T_PREFERRED; 164 xf86SetModeCrtc(mode, scrn->adjustFlags); 165} 166 167static void 168drmmode_ConvertToKMode(ScrnInfoPtr scrn, 169 drmModeModeInfo * kmode, DisplayModePtr mode) 170{ 171 memset(kmode, 0, sizeof(*kmode)); 172 173 kmode->clock = mode->Clock; 174 kmode->hdisplay = mode->HDisplay; 175 kmode->hsync_start = mode->HSyncStart; 176 kmode->hsync_end = mode->HSyncEnd; 177 kmode->htotal = mode->HTotal; 178 kmode->hskew = mode->HSkew; 179 180 kmode->vdisplay = mode->VDisplay; 181 kmode->vsync_start = mode->VSyncStart; 182 kmode->vsync_end = mode->VSyncEnd; 183 kmode->vtotal = mode->VTotal; 184 kmode->vscan = mode->VScan; 185 186 kmode->flags = mode->Flags; //& FLAG_BITS; 187 if (mode->name) 188 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 189 kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0; 190 191} 192 193/* 194 * Utility helper for drmWaitVBlank 195 */ 196Bool 197drmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 198 uint32_t target_seq, unsigned long signal, uint64_t *ust, 199 uint32_t *result_seq) 200{ 201 int crtc_id = drmmode_get_crtc_id(crtc); 202 ScrnInfoPtr scrn = crtc->scrn; 203 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 204 drmVBlank vbl; 205 206 if (crtc_id == 1) 207 type |= DRM_VBLANK_SECONDARY; 208 else if (crtc_id > 1) 209 type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 210 DRM_VBLANK_HIGH_CRTC_MASK; 211 212 vbl.request.type = type; 213 vbl.request.sequence = target_seq; 214 vbl.request.signal = signal; 215 216 if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0) 217 return FALSE; 218 219 if (ust) 220 *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 221 vbl.reply.tval_usec; 222 if (result_seq) 223 *result_seq = vbl.reply.sequence; 224 225 return TRUE; 226} 227 228/* 229 * Retrieves present time in microseconds that is compatible 230 * with units used by vblank timestamps. Depending on the kernel 231 * version and DRM kernel module configuration, the vblank 232 * timestamp can either be in real time or monotonic time 233 */ 234int drmmode_get_current_ust(int drm_fd, CARD64 * ust) 235{ 236 uint64_t cap_value; 237 int ret; 238 struct timespec now; 239 240 ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 241 if (ret || !cap_value) 242 /* old kernel or drm_timestamp_monotonic turned off */ 243 ret = clock_gettime(CLOCK_REALTIME, &now); 244 else 245 ret = clock_gettime(CLOCK_MONOTONIC, &now); 246 if (ret) 247 return ret; 248 *ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000); 249 return 0; 250} 251 252/* 253 * Get current frame count and frame count timestamp of the crtc. 254 */ 255int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 256{ 257 ScrnInfoPtr scrn = crtc->scrn; 258 uint32_t seq; 259 260 if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 261 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 262 "get vblank counter failed: %s\n", strerror(errno)); 263 return -1; 264 } 265 266 *msc = seq; 267 268 return Success; 269} 270 271static uint32_t 272drmmode_crtc_get_prop_id(uint32_t drm_fd, 273 drmModeObjectPropertiesPtr props, 274 char const* name) 275{ 276 uint32_t i, prop_id = 0; 277 278 for (i = 0; !prop_id && i < props->count_props; ++i) { 279 drmModePropertyPtr drm_prop = 280 drmModeGetProperty(drm_fd, props->props[i]); 281 282 if (!drm_prop) 283 continue; 284 285 if (strcmp(drm_prop->name, name) == 0) 286 prop_id = drm_prop->prop_id; 287 288 drmModeFreeProperty(drm_prop); 289 } 290 291 return prop_id; 292} 293 294static void drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc) 295{ 296 drmModeObjectPropertiesPtr drm_props; 297 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 298 drmmode_ptr drmmode = drmmode_crtc->drmmode; 299 300 if (drmmode->vrr_prop_id) 301 return; 302 303 drm_props = drmModeObjectGetProperties(drm_fd, 304 drmmode_crtc->mode_crtc->crtc_id, 305 DRM_MODE_OBJECT_CRTC); 306 307 if (!drm_props) 308 return; 309 310 drmmode->vrr_prop_id = drmmode_crtc_get_prop_id(drm_fd, 311 drm_props, 312 "VRR_ENABLED"); 313 314 drmModeFreeObjectProperties(drm_props); 315} 316 317void drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled) 318{ 319 ScrnInfoPtr pScrn = crtc->scrn; 320 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 321 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 322 drmmode_ptr drmmode = drmmode_crtc->drmmode; 323 324 if (drmmode->vrr_prop_id && 325 drmmode_crtc->vrr_enabled != enabled && 326 drmModeObjectSetProperty(pAMDGPUEnt->fd, 327 drmmode_crtc->mode_crtc->crtc_id, 328 DRM_MODE_OBJECT_CRTC, 329 drmmode->vrr_prop_id, 330 enabled) == 0) 331 drmmode_crtc->vrr_enabled = enabled; 332} 333 334static void 335drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 336{ 337 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 338 ScrnInfoPtr scrn = crtc->scrn; 339 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 340 CARD64 ust; 341 int ret; 342 343 if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 344 uint32_t seq; 345 346 amdgpu_drm_wait_pending_flip(crtc); 347 348 /* 349 * On->Off transition: record the last vblank time, 350 * sequence number and frame period. 351 */ 352 if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 353 &seq)) 354 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 355 "%s cannot get last vblank counter\n", 356 __func__); 357 else { 358 CARD64 nominal_frame_rate, pix_in_frame; 359 360 drmmode_crtc->dpms_last_ust = ust; 361 drmmode_crtc->dpms_last_seq = seq; 362 nominal_frame_rate = crtc->mode.Clock; 363 nominal_frame_rate *= 1000; 364 pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 365 if (nominal_frame_rate == 0 || pix_in_frame == 0) 366 nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 367 else 368 nominal_frame_rate /= pix_in_frame; 369 drmmode_crtc->dpms_last_fps = nominal_frame_rate; 370 } 371 372 drmmode_crtc->dpms_mode = mode; 373 amdgpu_drm_queue_handle_deferred(crtc); 374 } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 375 /* 376 * Off->On transition: calculate and accumulate the 377 * number of interpolated vblanks while we were in Off state 378 */ 379 ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust); 380 if (ret) 381 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 382 "%s cannot get current time\n", __func__); 383 else if (drmmode_crtc->dpms_last_ust) { 384 CARD64 time_elapsed, delta_seq; 385 time_elapsed = ust - drmmode_crtc->dpms_last_ust; 386 delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 387 delta_seq /= 1000000; 388 drmmode_crtc->interpolated_vblanks += delta_seq; 389 390 } 391 392 drmmode_crtc->dpms_mode = DPMSModeOn; 393 } 394} 395 396static void 397drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 398{ 399 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 400 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 401 402 /* Disable unused CRTCs and enable/disable active CRTCs */ 403 if (!crtc->enabled || mode != DPMSModeOn) { 404 drmmode_do_crtc_dpms(crtc, DPMSModeOff); 405 drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 406 0, 0, 0, NULL, 0, NULL); 407 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 408 } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 409 crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 410 crtc->x, crtc->y); 411} 412 413#ifdef USE_GLAMOR 414 415static PixmapPtr 416create_pixmap_for_fbcon(drmmode_ptr drmmode, 417 ScrnInfoPtr pScrn, int fbcon_id) 418{ 419 ScreenPtr pScreen = pScrn->pScreen; 420 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 421 PixmapPtr pixmap = NULL; 422 drmModeFBPtr fbcon; 423 424 fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id); 425 if (!fbcon) 426 return NULL; 427 428 if (fbcon->depth != pScrn->depth || 429 fbcon->width != pScrn->virtualX || 430 fbcon->height != pScrn->virtualY) 431 goto out_free_fb; 432 433 pixmap = fbCreatePixmap(pScreen, 0, 0, fbcon->depth, 0); 434 if (!pixmap) 435 goto out_free_fb; 436 437 pScreen->ModifyPixmapHeader(pixmap, fbcon->width, fbcon->height, 0, 0, 438 fbcon->pitch, NULL); 439 pixmap->devPrivate.ptr = NULL; 440 441 if (!glamor_egl_create_textured_pixmap(pixmap, fbcon->handle, 442 pixmap->devKind)) { 443 pScreen->DestroyPixmap(pixmap); 444 pixmap = NULL; 445 } 446 447out_free_fb: 448 drmModeFreeFB(fbcon); 449 return pixmap; 450} 451 452#endif /* USE_GLAMOR */ 453 454void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 455{ 456#ifdef USE_GLAMOR 457 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 458 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 459 ScreenPtr pScreen = pScrn->pScreen; 460 PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 461 struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst); 462 int fbcon_id = 0; 463 GCPtr gc; 464 int i; 465 466 if (!info->use_glamor) 467 return; 468 469 for (i = 0; i < xf86_config->num_crtc; i++) { 470 drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 471 472 if (drmmode_crtc->mode_crtc->buffer_id) 473 fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 474 } 475 476 if (!fbcon_id) 477 return; 478 479 if (fbcon_id == fb->handle) { 480 /* in some rare case there might be no fbcon and we might already 481 * be the one with the current fb to avoid a false deadlck in 482 * kernel ttm code just do nothing as anyway there is nothing 483 * to do 484 */ 485 return; 486 } 487 488 src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 489 if (!src) 490 return; 491 492 gc = GetScratchGC(pScrn->depth, pScreen); 493 ValidateGC(&dst->drawable, gc); 494 495 (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 496 pScrn->virtualX, pScrn->virtualY, 0, 0); 497 498 FreeScratchGC(gc); 499 500 pScreen->canDoBGNoneRoot = TRUE; 501 pScreen->DestroyPixmap(src); 502#endif 503 504 return; 505} 506 507void 508drmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 509 struct drmmode_scanout *scanout) 510{ 511 512 if (scanout->pixmap) { 513 drmmode_destroy_bo_pixmap(scanout->pixmap); 514 scanout->pixmap = NULL; 515 } 516 517 if (scanout->bo) { 518 amdgpu_bo_unref(&scanout->bo); 519 scanout->bo = NULL; 520 } 521} 522 523void 524drmmode_crtc_scanout_free(xf86CrtcPtr crtc) 525{ 526 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 527 528 if (drmmode_crtc->scanout_update_pending) { 529 amdgpu_drm_wait_pending_flip(crtc); 530 amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 531 drmmode_crtc->scanout_update_pending = 0; 532 amdgpu_drm_queue_handle_deferred(crtc); 533 } 534 535 drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 536 &drmmode_crtc->scanout[0]); 537 drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 538 &drmmode_crtc->scanout[1]); 539 540 if (drmmode_crtc->scanout_damage) 541 DamageDestroy(drmmode_crtc->scanout_damage); 542} 543 544PixmapPtr 545drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, 546 int width, int height) 547{ 548 ScrnInfoPtr pScrn = crtc->scrn; 549 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 550 drmmode_ptr drmmode = drmmode_crtc->drmmode; 551 int pitch; 552 553 if (scanout->pixmap) { 554 if (scanout->width == width && scanout->height == height) 555 return scanout->pixmap; 556 557 drmmode_crtc_scanout_destroy(drmmode, scanout); 558 } 559 560 scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height, 561 pScrn->depth, 0, 562 pScrn->bitsPerPixel, &pitch); 563 if (!scanout->bo) { 564 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 565 "Failed to allocate scanout buffer memory\n"); 566 return NULL; 567 } 568 569 scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 570 width, height, 571 pScrn->depth, 572 pScrn->bitsPerPixel, 573 pitch, scanout->bo); 574 if (!scanout->pixmap) { 575 ErrorF("failed to create CRTC scanout pixmap\n"); 576 goto error; 577 } 578 579 if (amdgpu_pixmap_get_fb(scanout->pixmap)) { 580 scanout->width = width; 581 scanout->height = height; 582 } else { 583 ErrorF("failed to create CRTC scanout FB\n"); 584error: 585 drmmode_crtc_scanout_destroy(drmmode, scanout); 586 } 587 588 return scanout->pixmap; 589} 590 591static void 592amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 593{ 594 drmmode_crtc_private_ptr drmmode_crtc = closure; 595 596 if (drmmode_crtc->ignore_damage) { 597 RegionEmpty(&damage->damage); 598 drmmode_crtc->ignore_damage = FALSE; 599 return; 600 } 601 602 /* Only keep track of the extents */ 603 RegionUninit(&damage->damage); 604 damage->damage.data = NULL; 605} 606 607static void 608drmmode_screen_damage_destroy(DamagePtr damage, void *closure) 609{ 610 drmmode_crtc_private_ptr drmmode_crtc = closure; 611 612 drmmode_crtc->scanout_damage = NULL; 613 RegionUninit(&drmmode_crtc->scanout_last_region); 614} 615 616static Bool 617drmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 618{ 619 AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 620 621 /* Check for Option "SWcursor" */ 622 if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 623 return FALSE; 624 625 /* Fall back to SW cursor if the CRTC is transformed */ 626 if (crtc->transformPresent) 627 return FALSE; 628 629#if XF86_CRTC_VERSION < 7 630 /* Xorg doesn't correctly handle cursor position transform in the 631 * rotation case 632 */ 633 if (crtc->driverIsPerformingTransform && 634 (crtc->rotation & 0xf) != RR_Rotate_0) 635 return FALSE; 636#endif 637 638 /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 639 if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 640 !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 641 return FALSE; 642 643 return TRUE; 644} 645 646static void 647drmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 648{ 649 AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 650 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 651 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 652 int i; 653 654 drmmode_crtc->tear_free = FALSE; 655 656 for (i = 0; i < xf86_config->num_output; i++) { 657 xf86OutputPtr output = xf86_config->output[i]; 658 drmmode_output_private_ptr drmmode_output = output->driver_private; 659 660 if (output->crtc != crtc) 661 continue; 662 663 if (drmmode_output->tear_free == 1 || 664 (drmmode_output->tear_free == 2 && 665 (crtc->scrn->pScreen->isGPU || 666 info->shadow_primary || 667 crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 668 drmmode_crtc->tear_free = TRUE; 669 return; 670 } 671 } 672} 673 674#if XF86_CRTC_VERSION < 7 675#define XF86DriverTransformOutput TRUE 676#define XF86DriverTransformNone FALSE 677#endif 678 679static Bool 680drmmode_handle_transform(xf86CrtcPtr crtc) 681{ 682 Bool ret; 683 684#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 685 crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 686#else 687 crtc->driverIsPerformingTransform = !crtc->transformPresent && 688 (crtc->rotation & 0xf) == RR_Rotate_0; 689#endif 690 691 ret = xf86CrtcRotate(crtc); 692 693 crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 694 695 return ret; 696} 697 698 699static void 700drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 701 unsigned scanout_id, struct drmmode_fb **fb, 702 int *x, int *y) 703{ 704 ScrnInfoPtr scrn = crtc->scrn; 705 ScreenPtr screen = scrn->pScreen; 706 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 707 708 if (drmmode_crtc->tear_free && 709 !drmmode_crtc->scanout[1].pixmap) { 710 RegionPtr region; 711 BoxPtr box; 712 713 drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 714 mode->HDisplay, 715 mode->VDisplay); 716 region = &drmmode_crtc->scanout_last_region; 717 RegionUninit(region); 718 region->data = NULL; 719 box = RegionExtents(region); 720 box->x1 = crtc->x; 721 box->y1 = crtc->y; 722 box->x2 = crtc->x + mode->HDisplay; 723 box->y2 = crtc->y + mode->VDisplay; 724 } 725 726 if (scanout_id != drmmode_crtc->scanout_id) { 727 PixmapDirtyUpdatePtr dirty = NULL; 728 729 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 730 ent) { 731 if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 732 dirty->slave_dst = 733 drmmode_crtc->scanout[scanout_id].pixmap; 734 break; 735 } 736 } 737 738 if (!drmmode_crtc->tear_free) { 739 GCPtr gc = GetScratchGC(scrn->depth, screen); 740 741 ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc); 742 gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable, 743 &drmmode_crtc->scanout[0].pixmap->drawable, 744 gc, 0, 0, mode->HDisplay, mode->VDisplay, 745 0, 0); 746 FreeScratchGC(gc); 747 amdgpu_glamor_finish(scrn); 748 } 749 } 750 751 *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 752 *x = *y = 0; 753 drmmode_crtc->scanout_id = scanout_id; 754} 755 756 757static void 758drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 759 unsigned scanout_id, struct drmmode_fb **fb, int *x, 760 int *y) 761{ 762 ScrnInfoPtr scrn = crtc->scrn; 763 ScreenPtr screen = scrn->pScreen; 764 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 765 766 drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 767 mode->HDisplay, mode->VDisplay); 768 if (drmmode_crtc->tear_free) { 769 drmmode_crtc_scanout_create(crtc, 770 &drmmode_crtc->scanout[scanout_id ^ 1], 771 mode->HDisplay, mode->VDisplay); 772 } 773 774 if (drmmode_crtc->scanout[scanout_id].pixmap && 775 (!drmmode_crtc->tear_free || 776 drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) { 777 BoxRec extents = { .x1 = 0, .y1 = 0, 778 .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 779 780 if (!drmmode_crtc->scanout_damage) { 781 drmmode_crtc->scanout_damage = 782 DamageCreate(amdgpu_screen_damage_report, 783 drmmode_screen_damage_destroy, 784 DamageReportRawRegion, 785 TRUE, screen, drmmode_crtc); 786 DamageRegister(&screen->root->drawable, 787 drmmode_crtc->scanout_damage); 788 } 789 790 *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap); 791 *x = *y = 0; 792 793 if (amdgpu_scanout_do_update(crtc, scanout_id, 794 screen->GetWindowPixmap(screen->root), 795 extents)) { 796 RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 797 amdgpu_glamor_finish(scrn); 798 799 if (!drmmode_crtc->flip_pending) { 800 amdgpu_drm_abort_entry(drmmode_crtc-> 801 scanout_update_pending); 802 } 803 } 804 } 805} 806 807static char *cm_prop_names[] = { 808 "DEGAMMA_LUT", 809 "CTM", 810 "GAMMA_LUT", 811 "DEGAMMA_LUT_SIZE", 812 "GAMMA_LUT_SIZE", 813}; 814 815/** 816 * Return the enum of the color management property with the given name. 817 */ 818static enum drmmode_cm_prop get_cm_enum_from_str(const char *prop_name) 819{ 820 enum drmmode_cm_prop ret; 821 822 for (ret = 0; ret < CM_NUM_PROPS; ret++) { 823 if (!strcmp(prop_name, cm_prop_names[ret])) 824 return ret; 825 } 826 return CM_INVALID_PROP; 827} 828 829/** 830 * If legacy LUT is a, and non-legacy LUT is b, then the result of b(a(x)) is 831 * returned in out_lut. out_lut's length is expected to be the same as the 832 * non-legacy LUT b. 833 * 834 * @a_(red|green|blue): The red, green, and blue components of the legacy LUT. 835 * @b_lut: The non-legacy LUT, in DRM's color LUT format. 836 * @out_lut: The composed LUT, in DRM's color LUT format. 837 * @len_a: Length of legacy lut. 838 * @len_b: Length of non-legacy lut. 839 */ 840static void drmmode_lut_compose(uint16_t *a_red, 841 uint16_t *a_green, 842 uint16_t *a_blue, 843 struct drm_color_lut *b_lut, 844 struct drm_color_lut *out_lut, 845 uint32_t len_a, uint32_t len_b) 846{ 847 uint32_t i_l, i_r, i; 848 uint32_t i_amax, i_bmax; 849 uint32_t coeff_ibmax; 850 uint32_t j; 851 uint64_t a_out_ibmax; 852 int color; 853 size_t struct_size = sizeof(struct drm_color_lut); 854 855 uint32_t max_lut = (1 << 16) - 1; 856 857 i_amax = len_a - 1; 858 i_bmax = len_b - 1; 859 860 /* A linear interpolation is done on the legacy LUT before it is 861 * composed, to bring it up-to-size with the non-legacy LUT. The 862 * interpolation uses integers by keeping things multiplied until the 863 * last moment. 864 */ 865 for (color = 0; color < 3; color++) { 866 uint16_t *a, *b, *out; 867 868 /* Set the initial pointers to the right color components. The 869 * inner for-loop will then maintain the correct offset from 870 * the initial element. 871 */ 872 if (color == 0) { 873 a = a_red; 874 b = &b_lut[0].red; 875 out = &out_lut[0].red; 876 } else if (color == 1) { 877 a = a_green; 878 b = &b_lut[0].green; 879 out = &out_lut[0].green; 880 } else { 881 a = a_blue; 882 b = &b_lut[0].blue; 883 out = &out_lut[0].blue; 884 } 885 886 for (i = 0; i < len_b; i++) { 887 /* i_l and i_r tracks the left and right elements in 888 * a_lut, to the sample point i. Also handle last 889 * element edge case, when i_l = i_amax. 890 */ 891 i_l = i * i_amax / i_bmax; 892 i_r = i_l + !!(i_amax - i_l); 893 894 /* coeff is intended to be in [0, 1), depending on 895 * where sample i is between i_l and i_r. We keep it 896 * multiplied with i_bmax throughout to maintain 897 * precision */ 898 coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 899 a_out_ibmax = i_bmax * a[i_l] + 900 coeff_ibmax * (a[i_r] - a[i_l]); 901 902 /* j = floor((a_out/max_lut)*i_bmax). 903 * i.e. the element in LUT b that a_out maps to. We 904 * have to divide by max_lut to normalize a_out, since 905 * values in the LUTs are [0, 1<<16) 906 */ 907 j = a_out_ibmax / max_lut; 908 *(uint16_t*)((void*)out + (i*struct_size)) = 909 *(uint16_t*)((void*)b + (j*struct_size)); 910 } 911 } 912 913 for (i = 0; i < len_b; i++) 914 out_lut[i].reserved = 0; 915} 916 917/** 918 * Resize a LUT, using linear interpolation. 919 * 920 * @in_(red|green|blue): Legacy LUT components 921 * @out_lut: The resized LUT is returned here, in DRM color LUT format. 922 * @len_in: Length of legacy LUT. 923 * @len_out: Length of out_lut, i.e. the target size. 924 */ 925static void drmmode_lut_interpolate(uint16_t *in_red, 926 uint16_t *in_green, 927 uint16_t *in_blue, 928 struct drm_color_lut *out_lut, 929 uint32_t len_in, uint32_t len_out) 930{ 931 uint32_t i_l, i_r, i; 932 uint32_t i_amax, i_bmax; 933 uint32_t coeff_ibmax; 934 uint64_t out_ibmax; 935 int color; 936 size_t struct_size = sizeof(struct drm_color_lut); 937 938 i_amax = len_in - 1; 939 i_bmax = len_out - 1; 940 941 /* See @drmmode_lut_compose for details */ 942 for (color = 0; color < 3; color++) { 943 uint16_t *in, *out; 944 945 if (color == 0) { 946 in = in_red; 947 out = &out_lut[0].red; 948 } else if (color == 1) { 949 in = in_green; 950 out = &out_lut[0].green; 951 } else { 952 in = in_blue; 953 out = &out_lut[0].blue; 954 } 955 956 for (i = 0; i < len_out; i++) { 957 i_l = i * i_amax / i_bmax; 958 i_r = i_l + !!(i_amax - i_l); 959 960 coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 961 out_ibmax = i_bmax * in[i_l] + 962 coeff_ibmax * (in[i_r] - in[i_l]); 963 964 *(uint16_t*)((void*)out + (i*struct_size)) = 965 out_ibmax / i_bmax; 966 } 967 } 968 969 for (i = 0; i < len_out; i++) 970 out_lut[i].reserved = 0; 971} 972 973/** 974 * Configure and change a color property on a CRTC, through RandR. Only the 975 * specified output will be affected, even if the CRTC is attached to multiple 976 * outputs. Note that changes will be non-pending: the changes won't be pushed 977 * to kernel driver. 978 * 979 * @output: RandR output to set the property on. 980 * @crtc: The driver-private CRTC object containing the color properties. 981 * If this is NULL, "disabled" values of 0 will be used. 982 * @cm_prop_index: Color management property to configure and change. 983 * 984 * Return 0 on success, X-defined error code otherwise. 985 */ 986static int rr_configure_and_change_cm_property(xf86OutputPtr output, 987 drmmode_crtc_private_ptr crtc, 988 enum drmmode_cm_prop cm_prop_index) 989{ 990 drmmode_output_private_ptr drmmode_output = output->driver_private; 991 drmmode_ptr drmmode = drmmode_output->drmmode; 992 Bool need_configure = TRUE; 993 unsigned long length = 0; 994 void *data = NULL; 995 int format = 0; 996 uint32_t zero = 0; 997 INT32 range[2]; 998 Atom atom; 999 int err; 1000 1001 if (cm_prop_index == CM_INVALID_PROP) 1002 return BadName; 1003 1004 switch(cm_prop_index) { 1005 case CM_GAMMA_LUT_SIZE: 1006 format = 32; 1007 length = 1; 1008 data = &drmmode->gamma_lut_size; 1009 range[0] = 0; 1010 range[1] = -1; 1011 break; 1012 case CM_DEGAMMA_LUT_SIZE: 1013 format = 32; 1014 length = 1; 1015 data = &drmmode->degamma_lut_size; 1016 range[0] = 0; 1017 range[1] = -1; 1018 break; 1019 case CM_GAMMA_LUT: 1020 format = 16; 1021 range[0] = 0; 1022 range[1] = (1 << 16) - 1; // Max 16 bit unsigned int. 1023 if (crtc && crtc->gamma_lut) { 1024 /* Convert from 8bit size to 16bit size */ 1025 length = sizeof(*crtc->gamma_lut) >> 1; 1026 length *= drmmode->gamma_lut_size; 1027 data = crtc->gamma_lut; 1028 } else { 1029 length = 1; 1030 data = &zero; 1031 } 1032 break; 1033 case CM_DEGAMMA_LUT: 1034 format = 16; 1035 range[0] = 0; 1036 range[1] = (1 << 16) - 1; 1037 if (crtc && crtc->degamma_lut) { 1038 length = sizeof(*crtc->degamma_lut) >> 1; 1039 length *= drmmode->degamma_lut_size; 1040 data = crtc->degamma_lut; 1041 } else { 1042 length = 1; 1043 data = &zero; 1044 } 1045 break; 1046 case CM_CTM: 1047 /* CTM is fixed-point S31.32 format. */ 1048 format = 32; 1049 need_configure = FALSE; 1050 if (crtc && crtc->ctm) { 1051 /* Convert from 8bit size to 32bit size */ 1052 length = sizeof(*crtc->ctm) >> 2; 1053 data = crtc->ctm; 1054 } else { 1055 length = 1; 1056 data = &zero; 1057 } 1058 break; 1059 default: 1060 return BadName; 1061 } 1062 1063 atom = MakeAtom(cm_prop_names[cm_prop_index], 1064 strlen(cm_prop_names[cm_prop_index]), 1065 TRUE); 1066 if (!atom) 1067 return BadAlloc; 1068 1069 if (need_configure) { 1070 err = RRConfigureOutputProperty(output->randr_output, atom, 1071 FALSE, TRUE, FALSE, 2, range); 1072 if (err) { 1073 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1074 "Configuring color management property %s failed with %d\n", 1075 cm_prop_names[cm_prop_index], err); 1076 return err; 1077 } 1078 } 1079 1080 /* Always issue a non-pending change. We'll push cm properties 1081 * ourselves. 1082 */ 1083 err = RRChangeOutputProperty(output->randr_output, atom, 1084 XA_INTEGER, format, 1085 PropModeReplace, 1086 length, data, FALSE, FALSE); 1087 if (err) 1088 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1089 "Changing color management property %s failed with %d\n", 1090 cm_prop_names[cm_prop_index], err); 1091 return err; 1092} 1093 1094/** 1095* Stage a color management property. This parses the property value, according 1096* to the cm property type, then stores it within the driver-private CRTC 1097* object. 1098* 1099* @crtc: The CRTC to stage the new color management properties in 1100* @cm_prop_index: The color property to stage 1101* @value: The RandR property value to stage 1102* 1103* Return 0 on success, X-defined error code on failure. 1104*/ 1105static int drmmode_crtc_stage_cm_prop(xf86CrtcPtr crtc, 1106 enum drmmode_cm_prop cm_prop_index, 1107 RRPropertyValuePtr value) 1108{ 1109 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1110 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1111 size_t expected_bytes = 0; 1112 void **blob_data = NULL; 1113 Bool use_default = FALSE; 1114 1115 /* Update properties on the driver-private CRTC */ 1116 switch (cm_prop_index) { 1117 case CM_GAMMA_LUT: 1118 /* Calculate the expected size of value in bytes */ 1119 expected_bytes = sizeof(struct drm_color_lut) * 1120 drmmode->gamma_lut_size; 1121 1122 /* For gamma and degamma, we allow a default SRGB curve to be 1123 * set via setting a single element 1124 * 1125 * Otherwise, value size is in terms of the value format. 1126 * Ensure it's also in bytes (<< 1) before comparing with the 1127 * expected bytes. 1128 */ 1129 if (value->size == 1) 1130 use_default = TRUE; 1131 else if (value->type != XA_INTEGER || value->format != 16 || 1132 (size_t)(value->size << 1) != expected_bytes) 1133 return BadLength; 1134 1135 blob_data = (void**)&drmmode_crtc->gamma_lut; 1136 break; 1137 case CM_DEGAMMA_LUT: 1138 expected_bytes = sizeof(struct drm_color_lut) * 1139 drmmode->degamma_lut_size; 1140 1141 if (value->size == 1) 1142 use_default = TRUE; 1143 else if (value->type != XA_INTEGER || value->format != 16 || 1144 (size_t)(value->size << 1) != expected_bytes) 1145 return BadLength; 1146 1147 blob_data = (void**)&drmmode_crtc->degamma_lut; 1148 break; 1149 case CM_CTM: 1150 expected_bytes = sizeof(struct drm_color_ctm); 1151 1152 if (value->size == 1) 1153 use_default = TRUE; 1154 if (value->type != XA_INTEGER || value->format != 32 || 1155 (size_t)(value->size << 2) != expected_bytes) 1156 return BadLength; 1157 1158 blob_data = (void**)&drmmode_crtc->ctm; 1159 break; 1160 default: 1161 return BadName; 1162 } 1163 1164 free(*blob_data); 1165 if (!use_default) { 1166 *blob_data = malloc(expected_bytes); 1167 if (!*blob_data) 1168 return BadAlloc; 1169 memcpy(*blob_data, value->data, expected_bytes); 1170 } else 1171 *blob_data = NULL; 1172 1173 return Success; 1174} 1175 1176/** 1177 * Push staged color management properties on the CRTC to DRM. 1178 * 1179 * @crtc: The CRTC containing staged properties 1180 * @cm_prop_index: The color property to push 1181 * 1182 * Return 0 on success, X-defined error codes on failure. 1183 */ 1184static int drmmode_crtc_push_cm_prop(xf86CrtcPtr crtc, 1185 enum drmmode_cm_prop cm_prop_index) 1186{ 1187 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1188 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1189 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1190 Bool free_blob_data = FALSE; 1191 uint32_t created_blob_id = 0; 1192 uint32_t drm_prop_id; 1193 size_t expected_bytes = 0; 1194 void *blob_data = NULL; 1195 int ret; 1196 1197 switch (cm_prop_index) { 1198 case CM_GAMMA_LUT: 1199 /* Calculate the expected size of value in bytes */ 1200 expected_bytes = sizeof(struct drm_color_lut) * 1201 drmmode->gamma_lut_size; 1202 1203 /* Legacy gamma LUT is disabled on deep 30bpp color. In which 1204 * case, directly use non-legacy LUT. 1205 */ 1206 if (!crtc->funcs->gamma_set) { 1207 blob_data = drmmode_crtc->gamma_lut; 1208 goto do_push; 1209 } 1210 1211 blob_data = malloc(expected_bytes); 1212 if (!blob_data) 1213 return BadAlloc; 1214 1215 free_blob_data = TRUE; 1216 /* 1217 * Compose legacy and non-legacy LUT if non-legacy was set. 1218 * Otherwise, interpolate legacy LUT to non-legacy size. 1219 */ 1220 if (drmmode_crtc->gamma_lut) { 1221 drmmode_lut_compose(crtc->gamma_red, 1222 crtc->gamma_green, 1223 crtc->gamma_blue, 1224 drmmode_crtc->gamma_lut, 1225 blob_data, crtc->gamma_size, 1226 drmmode->gamma_lut_size); 1227 } else { 1228 drmmode_lut_interpolate(crtc->gamma_red, 1229 crtc->gamma_green, 1230 crtc->gamma_blue, 1231 blob_data, 1232 crtc->gamma_size, 1233 drmmode->gamma_lut_size); 1234 } 1235 break; 1236 case CM_DEGAMMA_LUT: 1237 expected_bytes = sizeof(struct drm_color_lut) * 1238 drmmode->degamma_lut_size; 1239 blob_data = drmmode_crtc->degamma_lut; 1240 break; 1241 case CM_CTM: 1242 expected_bytes = sizeof(struct drm_color_ctm); 1243 blob_data = drmmode_crtc->ctm; 1244 break; 1245 default: 1246 return BadName; 1247 } 1248 1249do_push: 1250 if (blob_data) { 1251 ret = drmModeCreatePropertyBlob(pAMDGPUEnt->fd, 1252 blob_data, expected_bytes, 1253 &created_blob_id); 1254 if (ret) { 1255 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1256 "Creating DRM blob failed with errno %d\n", 1257 ret); 1258 if (free_blob_data) 1259 free(blob_data); 1260 return BadRequest; 1261 } 1262 } 1263 1264 drm_prop_id = drmmode_crtc->drmmode->cm_prop_ids[cm_prop_index]; 1265 ret = drmModeObjectSetProperty(pAMDGPUEnt->fd, 1266 drmmode_crtc->mode_crtc->crtc_id, 1267 DRM_MODE_OBJECT_CRTC, 1268 drm_prop_id, 1269 (uint64_t)created_blob_id); 1270 1271 /* If successful, kernel will have a reference already. Safe to destroy 1272 * the blob either way. 1273 */ 1274 if (blob_data) 1275 drmModeDestroyPropertyBlob(pAMDGPUEnt->fd, created_blob_id); 1276 1277 if (ret) { 1278 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1279 "Setting DRM property blob failed with errno %d\n", 1280 ret); 1281 if (free_blob_data) 1282 free(blob_data); 1283 return BadRequest; 1284 } 1285 1286 if (free_blob_data) 1287 free(blob_data); 1288 1289 return Success; 1290} 1291 1292static void 1293drmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 1294 uint16_t *blue, int size) 1295{ 1296 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1297 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1298 int ret; 1299 1300 /* Use legacy if no support for non-legacy gamma */ 1301 if (!drmmode_cm_enabled(drmmode_crtc->drmmode)) { 1302 drmModeCrtcSetGamma(pAMDGPUEnt->fd, 1303 drmmode_crtc->mode_crtc->crtc_id, 1304 size, red, green, blue); 1305 return; 1306 } 1307 1308 ret = drmmode_crtc_push_cm_prop(crtc, CM_GAMMA_LUT); 1309 if (ret) 1310 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1311 "Setting Gamma LUT failed with errno %d\n", 1312 ret); 1313} 1314 1315Bool 1316drmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 1317 int x, int y) 1318{ 1319 ScrnInfoPtr scrn = crtc->scrn; 1320 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 1321 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1322 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1323 uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 1324 int output_count = 0; 1325 drmModeModeInfo kmode; 1326 Bool ret; 1327 int i; 1328 1329 if (!output_ids) 1330 return FALSE; 1331 1332 for (i = 0; i < xf86_config->num_output; i++) { 1333 xf86OutputPtr output = xf86_config->output[i]; 1334 drmmode_output_private_ptr drmmode_output = output->driver_private; 1335 1336 if (output->crtc != crtc) 1337 continue; 1338 1339 output_ids[output_count] = drmmode_output->mode_output->connector_id; 1340 output_count++; 1341 } 1342 1343 drmmode_ConvertToKMode(scrn, &kmode, mode); 1344 1345 ret = drmModeSetCrtc(pAMDGPUEnt->fd, 1346 drmmode_crtc->mode_crtc->crtc_id, 1347 fb->handle, x, y, output_ids, 1348 output_count, &kmode) == 0; 1349 1350 if (ret) { 1351 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb); 1352 } else { 1353 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1354 "failed to set mode: %s\n", strerror(errno)); 1355 } 1356 1357 free(output_ids); 1358 return ret; 1359} 1360 1361static Bool 1362drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 1363 Rotation rotation, int x, int y) 1364{ 1365 ScrnInfoPtr pScrn = crtc->scrn; 1366 ScreenPtr pScreen = pScrn->pScreen; 1367 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1368 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1369 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1370 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1371 Bool handle_deferred = FALSE; 1372 unsigned scanout_id = 0; 1373 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1374 int saved_x, saved_y; 1375 Rotation saved_rotation; 1376 DisplayModeRec saved_mode; 1377 Bool ret = FALSE; 1378 int i; 1379 struct drmmode_fb *fb = NULL; 1380 1381 /* The root window contents may be undefined before the WindowExposures 1382 * hook is called for it, so bail if we get here before that 1383 */ 1384 if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot) 1385 return FALSE; 1386 1387 saved_mode = crtc->mode; 1388 saved_x = crtc->x; 1389 saved_y = crtc->y; 1390 saved_rotation = crtc->rotation; 1391 1392 if (mode) { 1393 crtc->mode = *mode; 1394 crtc->x = x; 1395 crtc->y = y; 1396 crtc->rotation = rotation; 1397 1398 if (!drmmode_handle_transform(crtc)) 1399 goto done; 1400 1401 drmmode_crtc_update_tear_free(crtc); 1402 if (drmmode_crtc->tear_free) 1403 scanout_id = drmmode_crtc->scanout_id; 1404 else 1405 drmmode_crtc->scanout_id = 0; 1406 1407 if (drmmode_crtc->prime_scanout_pixmap) { 1408 drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 1409 &fb, &x, &y); 1410 } else if (drmmode_crtc->rotate.pixmap) { 1411 fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate.pixmap); 1412 x = y = 0; 1413 1414 } else if (!pScreen->isGPU && 1415 (drmmode_crtc->tear_free || 1416 crtc->driverIsPerformingTransform || 1417 info->shadow_primary)) { 1418 drmmode_crtc_scanout_update(crtc, mode, scanout_id, 1419 &fb, &x, &y); 1420 } 1421 1422 if (!fb) 1423 fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 1424 if (!fb) { 1425 union gbm_bo_handle bo_handle; 1426 1427 bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm); 1428 fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd, 1429 pScrn->virtualX, pScrn->virtualY, 1430 pScrn->displayWidth * info->pixel_bytes, 1431 bo_handle.u32); 1432 /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 1433 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 1434 drmmode_crtc->fb = fb; 1435 } 1436 if (!fb) { 1437 ErrorF("failed to add FB for modeset\n"); 1438 goto done; 1439 } 1440 1441 amdgpu_drm_wait_pending_flip(crtc); 1442 handle_deferred = TRUE; 1443 1444 if (!drmmode_set_mode(crtc, fb, mode, x, y)) 1445 goto done; 1446 1447 ret = TRUE; 1448 1449 if (pScreen) 1450 xf86CrtcSetScreenSubpixelOrder(pScreen); 1451 1452 drmmode_crtc->need_modeset = FALSE; 1453 1454 /* go through all the outputs and force DPMS them back on? */ 1455 for (i = 0; i < xf86_config->num_output; i++) { 1456 xf86OutputPtr output = xf86_config->output[i]; 1457 1458 if (output->crtc != crtc) 1459 continue; 1460 1461 output->funcs->dpms(output, DPMSModeOn); 1462 } 1463 } 1464 1465 /* Compute index of this CRTC into xf86_config->crtc */ 1466 for (i = 0; i < xf86_config->num_crtc; i++) { 1467 if (xf86_config->crtc[i] != crtc) 1468 continue; 1469 1470 if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 1471 info->hwcursor_disabled &= ~(1 << i); 1472 else 1473 info->hwcursor_disabled |= 1 << i; 1474 1475 break; 1476 } 1477 1478#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 1479 if (!info->hwcursor_disabled) 1480 xf86_reload_cursors(pScreen); 1481#endif 1482 1483done: 1484 if (!ret) { 1485 crtc->x = saved_x; 1486 crtc->y = saved_y; 1487 crtc->rotation = saved_rotation; 1488 crtc->mode = saved_mode; 1489 } else { 1490 crtc->active = TRUE; 1491 1492 if (drmmode_crtc->scanout[scanout_id].pixmap && 1493 fb != amdgpu_pixmap_get_fb(drmmode_crtc-> 1494 scanout[scanout_id].pixmap)) { 1495 drmmode_crtc_scanout_free(crtc); 1496 } else if (!drmmode_crtc->tear_free) { 1497 drmmode_crtc_scanout_destroy(drmmode, 1498 &drmmode_crtc->scanout[1]); 1499 } 1500 } 1501 1502 if (handle_deferred) 1503 amdgpu_drm_queue_handle_deferred(crtc); 1504 1505 return ret; 1506} 1507 1508static void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 1509{ 1510 1511} 1512 1513static void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 1514{ 1515 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1516 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1517 1518#if XF86_CRTC_VERSION < 7 1519 if (crtc->driverIsPerformingTransform) { 1520 x += crtc->x; 1521 y += crtc->y; 1522 xf86CrtcTransformCursorPos(crtc, &x, &y); 1523 } 1524#endif 1525 1526 drmmode_crtc->cursor_x = x; 1527 drmmode_crtc->cursor_y = y; 1528 1529 drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1530} 1531 1532#if XF86_CRTC_VERSION < 7 1533 1534static int 1535drmmode_cursor_src_offset(Rotation rotation, int width, int height, 1536 int x_dst, int y_dst) 1537{ 1538 int t; 1539 1540 switch (rotation & 0xf) { 1541 case RR_Rotate_90: 1542 t = x_dst; 1543 x_dst = height - y_dst - 1; 1544 y_dst = t; 1545 break; 1546 case RR_Rotate_180: 1547 x_dst = width - x_dst - 1; 1548 y_dst = height - y_dst - 1; 1549 break; 1550 case RR_Rotate_270: 1551 t = x_dst; 1552 x_dst = y_dst; 1553 y_dst = width - t - 1; 1554 break; 1555 } 1556 1557 if (rotation & RR_Reflect_X) 1558 x_dst = width - x_dst - 1; 1559 if (rotation & RR_Reflect_Y) 1560 y_dst = height - y_dst - 1; 1561 1562 return y_dst * height + x_dst; 1563} 1564 1565#endif 1566 1567static Bool 1568drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied, 1569 Bool *apply_gamma) 1570{ 1571 uint32_t alpha = *argb >> 24; 1572 uint32_t rgb[3]; 1573 int i; 1574 1575 if (premultiplied) { 1576#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0) 1577 if (alpha == 0 && (*argb & 0xffffff) != 0) { 1578 /* Doesn't look like premultiplied alpha */ 1579 *premultiplied = FALSE; 1580 return FALSE; 1581 } 1582#endif 1583 1584 if (!(*apply_gamma)) 1585 return TRUE; 1586 1587 if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) { 1588 /* Un-premultiplied R/G/B would overflow gamma LUT, 1589 * don't apply gamma correction 1590 */ 1591 *apply_gamma = FALSE; 1592 return FALSE; 1593 } 1594 } 1595 1596 if (!alpha) { 1597 *argb = 0; 1598 return TRUE; 1599 } 1600 1601 /* Extract RGB */ 1602 for (i = 0; i < 3; i++) 1603 rgb[i] = (*argb >> (i * 8)) & 0xff; 1604 1605 if (premultiplied) { 1606 /* Un-premultiply alpha */ 1607 for (i = 0; i < 3; i++) 1608 rgb[i] = rgb[i] * 0xff / alpha; 1609 } 1610 1611 if (*apply_gamma) { 1612 rgb[0] = crtc->gamma_blue[rgb[0]] >> 8; 1613 rgb[1] = crtc->gamma_green[rgb[1]] >> 8; 1614 rgb[2] = crtc->gamma_red[rgb[2]] >> 8; 1615 } 1616 1617 /* Premultiply alpha */ 1618 for (i = 0; i < 3; i++) 1619 rgb[i] = rgb[i] * alpha / 0xff; 1620 1621 *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 1622 return TRUE; 1623} 1624 1625static void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 1626{ 1627 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1628 ScrnInfoPtr pScrn = crtc->scrn; 1629 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1630 unsigned id = drmmode_crtc->cursor_id; 1631 Bool premultiplied = TRUE; 1632 Bool apply_gamma = TRUE; 1633 uint32_t argb; 1634 uint32_t *ptr; 1635 1636 if ((crtc->scrn->depth != 24 && crtc->scrn->depth != 32) || 1637 drmmode_cm_enabled(&info->drmmode)) 1638 apply_gamma = FALSE; 1639 1640 if (drmmode_crtc->cursor && 1641 XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor) 1642 id ^= 1; 1643 1644 ptr = (uint32_t *) (drmmode_crtc->cursor_buffer[id]->cpu_ptr); 1645 1646#if XF86_CRTC_VERSION < 7 1647 if (crtc->driverIsPerformingTransform) { 1648 uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 1649 int dstx, dsty; 1650 int srcoffset; 1651 1652retry_transform: 1653 for (dsty = 0; dsty < cursor_h; dsty++) { 1654 for (dstx = 0; dstx < cursor_w; dstx++) { 1655 srcoffset = drmmode_cursor_src_offset(crtc->rotation, 1656 cursor_w, 1657 cursor_h, 1658 dstx, dsty); 1659 argb = image[srcoffset]; 1660 if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1661 &apply_gamma)) 1662 goto retry_transform; 1663 1664 ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb); 1665 } 1666 } 1667 } else 1668#endif 1669 { 1670 uint32_t cursor_size = info->cursor_w * info->cursor_h; 1671 int i; 1672 1673retry: 1674 for (i = 0; i < cursor_size; i++) { 1675 argb = image[i]; 1676 if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1677 &apply_gamma)) 1678 goto retry; 1679 1680 ptr[i] = cpu_to_le32(argb); 1681 } 1682 } 1683 1684 if (id != drmmode_crtc->cursor_id) { 1685 drmmode_crtc->cursor_id = id; 1686 crtc->funcs->show_cursor(crtc); 1687 } 1688} 1689 1690#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1691 1692static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 1693{ 1694 if (!drmmode_can_use_hw_cursor(crtc)) 1695 return FALSE; 1696 1697 drmmode_load_cursor_argb(crtc, image); 1698 return TRUE; 1699} 1700 1701#endif 1702 1703static void drmmode_hide_cursor(xf86CrtcPtr crtc) 1704{ 1705 ScrnInfoPtr pScrn = crtc->scrn; 1706 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1707 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1708 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1709 1710 drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 1711 info->cursor_w, info->cursor_h); 1712 drmmode_crtc->cursor = NULL; 1713} 1714 1715static void drmmode_show_cursor(xf86CrtcPtr crtc) 1716{ 1717 ScrnInfoPtr pScrn = crtc->scrn; 1718 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1719 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1720 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1721 struct amdgpu_buffer *cursor_buffer = 1722 drmmode_crtc->cursor_buffer[drmmode_crtc->cursor_id]; 1723 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1724 CursorPtr cursor = xf86_config->cursor; 1725 int xhot = cursor->bits->xhot; 1726 int yhot = cursor->bits->yhot; 1727 static Bool use_set_cursor2 = TRUE; 1728 struct drm_mode_cursor2 arg; 1729 1730 drmmode_crtc->cursor = xf86_config->cursor; 1731 1732 memset(&arg, 0, sizeof(arg)); 1733 1734 if (!amdgpu_bo_get_handle(cursor_buffer, &arg.handle)) { 1735 ErrorF("failed to get BO handle for cursor\n"); 1736 return; 1737 } 1738 1739 arg.flags = DRM_MODE_CURSOR_BO; 1740 arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id; 1741 arg.width = info->cursor_w; 1742 arg.height = info->cursor_h; 1743 1744 if (crtc->rotation != RR_Rotate_0 && 1745 crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1746 RR_Reflect_Y)) { 1747 int t; 1748 1749 /* Reflect & rotate hotspot position */ 1750 if (crtc->rotation & RR_Reflect_X) 1751 xhot = info->cursor_w - xhot - 1; 1752 if (crtc->rotation & RR_Reflect_Y) 1753 yhot = info->cursor_h - yhot - 1; 1754 1755 switch (crtc->rotation & 0xf) { 1756 case RR_Rotate_90: 1757 t = xhot; 1758 xhot = yhot; 1759 yhot = info->cursor_w - t - 1; 1760 break; 1761 case RR_Rotate_180: 1762 xhot = info->cursor_w - xhot - 1; 1763 yhot = info->cursor_h - yhot - 1; 1764 break; 1765 case RR_Rotate_270: 1766 t = xhot; 1767 xhot = info->cursor_h - yhot - 1; 1768 yhot = t; 1769 } 1770 } 1771 1772 if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) { 1773 arg.flags |= DRM_MODE_CURSOR_MOVE; 1774 arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot; 1775 arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot; 1776 drmmode_crtc->cursor_xhot = xhot; 1777 drmmode_crtc->cursor_yhot = yhot; 1778 } 1779 1780 if (use_set_cursor2) { 1781 int ret; 1782 1783 arg.hot_x = xhot; 1784 arg.hot_y = yhot; 1785 1786 ret = drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg); 1787 if (ret == -EINVAL) 1788 use_set_cursor2 = FALSE; 1789 else 1790 return; 1791 } 1792 1793 drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg); 1794} 1795 1796/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 1797 * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 1798 * anything else. 1799 */ 1800static void * 1801drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1802{ 1803 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1804 1805 if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 1806 height)) 1807 return NULL; 1808 1809 return (void*)~0UL; 1810} 1811 1812static PixmapPtr 1813drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1814{ 1815 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1816 1817 if (!data) { 1818 drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 1819 height); 1820 } 1821 1822 return drmmode_crtc->rotate.pixmap; 1823} 1824 1825static void 1826drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, 1827 void *data) 1828{ 1829 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1830 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1831 1832 drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 1833} 1834 1835static void 1836drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, 1837 uint16_t * blue, int size) 1838{ 1839 ScrnInfoPtr scrn = crtc->scrn; 1840 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1841 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 1842 int i; 1843 1844 drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 1845 1846 /* Compute index of this CRTC into xf86_config->crtc */ 1847 for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 1848 1849 if (info->hwcursor_disabled & (1 << i)) 1850 return; 1851 1852#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 1853 xf86CursorResetCursor(scrn->pScreen); 1854#else 1855 xf86_reload_cursors(scrn->pScreen); 1856#endif 1857} 1858 1859static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 1860{ 1861 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1862 unsigned scanout_id = drmmode_crtc->scanout_id; 1863 ScreenPtr screen = crtc->scrn->pScreen; 1864 PixmapDirtyUpdatePtr dirty; 1865 1866 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 1867 if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 1868 PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 1869 break; 1870 } 1871 } 1872 1873 drmmode_crtc_scanout_free(crtc); 1874 drmmode_crtc->prime_scanout_pixmap = NULL; 1875 1876 if (!ppix) 1877 return TRUE; 1878 1879 if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 1880 ppix->drawable.width, 1881 ppix->drawable.height)) 1882 return FALSE; 1883 1884 if (drmmode_crtc->tear_free && 1885 !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 1886 ppix->drawable.width, 1887 ppix->drawable.height)) { 1888 drmmode_crtc_scanout_free(crtc); 1889 return FALSE; 1890 } 1891 1892 drmmode_crtc->prime_scanout_pixmap = ppix; 1893 1894#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 1895 PixmapStartDirtyTracking(&ppix->drawable, 1896 drmmode_crtc->scanout[scanout_id].pixmap, 1897 0, 0, 0, 0, RR_Rotate_0); 1898#elif defined(HAS_DIRTYTRACKING_ROTATION) 1899 PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1900 0, 0, 0, 0, RR_Rotate_0); 1901#elif defined(HAS_DIRTYTRACKING2) 1902 PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 1903 0, 0, 0, 0); 1904#else 1905 PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0); 1906#endif 1907 return TRUE; 1908} 1909 1910static void drmmode_crtc_destroy(xf86CrtcPtr crtc) 1911{ 1912 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1913 1914 drmModeFreeCrtc(drmmode_crtc->mode_crtc); 1915 1916 /* Free LUTs and CTM */ 1917 free(drmmode_crtc->gamma_lut); 1918 free(drmmode_crtc->degamma_lut); 1919 free(drmmode_crtc->ctm); 1920 1921 free(drmmode_crtc); 1922 crtc->driver_private = NULL; 1923} 1924 1925 1926static xf86CrtcFuncsRec drmmode_crtc_funcs = { 1927 .dpms = drmmode_crtc_dpms, 1928 .set_mode_major = drmmode_set_mode_major, 1929 .set_cursor_colors = drmmode_set_cursor_colors, 1930 .set_cursor_position = drmmode_set_cursor_position, 1931 .show_cursor = drmmode_show_cursor, 1932 .hide_cursor = drmmode_hide_cursor, 1933 .load_cursor_argb = drmmode_load_cursor_argb, 1934#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1935 .load_cursor_argb_check = drmmode_load_cursor_argb_check, 1936#endif 1937 1938 .gamma_set = drmmode_crtc_gamma_set, 1939 .shadow_create = drmmode_crtc_shadow_create, 1940 .shadow_allocate = drmmode_crtc_shadow_allocate, 1941 .shadow_destroy = drmmode_crtc_shadow_destroy, 1942 .destroy = drmmode_crtc_destroy, 1943 .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1944}; 1945 1946int drmmode_get_crtc_id(xf86CrtcPtr crtc) 1947{ 1948 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1949 return drmmode_crtc->hw_id; 1950} 1951 1952void drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1953{ 1954 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1955 ScrnInfoPtr pScrn = crtc->scrn; 1956 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1957 int r; 1958 1959 r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev, 1960 drmmode_crtc->mode_crtc->crtc_id, 1961 &drmmode_crtc->hw_id); 1962 if (r) 1963 drmmode_crtc->hw_id = -1; 1964} 1965 1966/** 1967 * Initialize color management properties for the given CRTC by programming 1968 * the default gamma/degamma LUTs and CTM. 1969 * 1970 * If the CRTC does not support color management, or if errors occur during 1971 * initialization, all color properties on the driver-private CRTC will left 1972 * as NULL. 1973 * 1974 * @drm_fd: DRM file descriptor 1975 * @crtc: CRTC to initialize color management on. 1976 */ 1977static void drmmode_crtc_cm_init(int drm_fd, xf86CrtcPtr crtc) 1978{ 1979 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1980 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1981 int i; 1982 1983 if (!drmmode_cm_enabled(drmmode)) 1984 return; 1985 1986 /* Init CTM to identity. Values are in S31.32 fixed-point format */ 1987 drmmode_crtc->ctm = calloc(1, sizeof(*drmmode_crtc->ctm)); 1988 if (!drmmode_crtc->ctm) { 1989 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1990 "Memory error initializing CTM for CRTC%d", 1991 drmmode_get_crtc_id(crtc)); 1992 return; 1993 } 1994 1995 drmmode_crtc->ctm->matrix[0] = drmmode_crtc->ctm->matrix[4] = 1996 drmmode_crtc->ctm->matrix[8] = (uint64_t)1 << 32; 1997 1998 /* Push properties to reset properties currently in hardware */ 1999 for (i = 0; i < CM_GAMMA_LUT; i++) { 2000 if (drmmode_crtc_push_cm_prop(crtc, i)) 2001 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 2002 "Failed to initialize color management " 2003 "property %s on CRTC%d. Property value may " 2004 "not reflect actual hardware state.\n", 2005 cm_prop_names[i], 2006 drmmode_get_crtc_id(crtc)); 2007 } 2008} 2009 2010static unsigned int 2011drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 2012{ 2013 xf86CrtcPtr crtc; 2014 drmmode_crtc_private_ptr drmmode_crtc; 2015 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2016 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2017 2018 crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 2019 if (!crtc) 2020 return 0; 2021 2022 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 2023 drmmode_crtc->mode_crtc = 2024 drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); 2025 drmmode_crtc->drmmode = drmmode; 2026 drmmode_crtc->dpms_mode = DPMSModeOff; 2027 crtc->driver_private = drmmode_crtc; 2028 drmmode_crtc_hw_id(crtc); 2029 2030 drmmode_crtc_cm_init(pAMDGPUEnt->fd, crtc); 2031 drmmode_crtc_vrr_init(pAMDGPUEnt->fd, crtc); 2032 2033 /* Mark num'th crtc as in use on this device. */ 2034 pAMDGPUEnt->assigned_crtcs |= (1 << num); 2035 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2036 "Allocated crtc nr. %d to this screen.\n", num); 2037 2038 return 1; 2039} 2040 2041/* 2042 * Update all of the property values for an output 2043 */ 2044static void 2045drmmode_output_update_properties(xf86OutputPtr output) 2046{ 2047 drmmode_output_private_ptr drmmode_output = output->driver_private; 2048 int i, j, k; 2049 int err; 2050 drmModeConnectorPtr koutput; 2051 2052 /* Use the most recently fetched values from the kernel */ 2053 koutput = drmmode_output->mode_output; 2054 2055 if (!koutput) 2056 return; 2057 2058 for (i = 0; i < drmmode_output->num_props; i++) { 2059 drmmode_prop_ptr p = &drmmode_output->props[i]; 2060 2061 for (j = 0; j < koutput->count_props; j++) { 2062 if (koutput->props[j] != p->mode_prop->prop_id) 2063 continue; 2064 2065 /* Check to see if the property value has changed */ 2066 if (koutput->prop_values[j] == p->value) 2067 break; 2068 2069 p->value = koutput->prop_values[j]; 2070 2071 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 2072 INT32 value = p->value; 2073 2074 err = RRChangeOutputProperty(output->randr_output, 2075 p->atoms[0], XA_INTEGER, 2076 32, PropModeReplace, 1, 2077 &value, FALSE, TRUE); 2078 if (err != 0) { 2079 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2080 "RRChangeOutputProperty error, %d\n", 2081 err); 2082 } 2083 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2084 for (k = 0; k < p->mode_prop->count_enums; k++) { 2085 if (p->mode_prop->enums[k].value == p->value) 2086 break; 2087 } 2088 if (k < p->mode_prop->count_enums) { 2089 err = RRChangeOutputProperty(output->randr_output, 2090 p->atoms[0], XA_ATOM, 2091 32, PropModeReplace, 1, 2092 &p->atoms[k + 1], FALSE, 2093 TRUE); 2094 if (err != 0) { 2095 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2096 "RRChangeOutputProperty error, %d\n", 2097 err); 2098 } 2099 } 2100 } 2101 2102 break; 2103 } 2104 } 2105} 2106 2107static xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) 2108{ 2109 /* go to the hw and retrieve a new output struct */ 2110 drmmode_output_private_ptr drmmode_output = output->driver_private; 2111 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2112 xf86OutputStatus status; 2113 drmModeFreeConnector(drmmode_output->mode_output); 2114 2115 drmmode_output->mode_output = 2116 drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id); 2117 if (!drmmode_output->mode_output) { 2118 drmmode_output->output_id = -1; 2119 return XF86OutputStatusDisconnected; 2120 } 2121 2122 drmmode_output_update_properties(output); 2123 2124 switch (drmmode_output->mode_output->connection) { 2125 case DRM_MODE_CONNECTED: 2126 status = XF86OutputStatusConnected; 2127 break; 2128 case DRM_MODE_DISCONNECTED: 2129 status = XF86OutputStatusDisconnected; 2130 break; 2131 default: 2132 case DRM_MODE_UNKNOWNCONNECTION: 2133 status = XF86OutputStatusUnknown; 2134 break; 2135 } 2136 return status; 2137} 2138 2139static Bool 2140drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 2141{ 2142 return MODE_OK; 2143} 2144 2145static int 2146koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 2147 int type, const char *name) 2148{ 2149 int idx = -1; 2150 2151 for (int i = 0; i < koutput->count_props; i++) { 2152 drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 2153 2154 if (!prop) 2155 continue; 2156 2157 if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 2158 idx = i; 2159 2160 drmModeFreeProperty(prop); 2161 2162 if (idx > -1) 2163 break; 2164 } 2165 2166 return idx; 2167} 2168 2169static int 2170koutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 2171 int type, const char *name) 2172{ 2173 int idx = koutput_get_prop_idx(fd, koutput, type, name); 2174 2175 return (idx > -1) ? koutput->props[idx] : -1; 2176} 2177 2178static drmModePropertyBlobPtr 2179koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 2180{ 2181 drmModePropertyBlobPtr blob = NULL; 2182 int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 2183 2184 if (idx > -1) 2185 blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 2186 2187 return blob; 2188} 2189 2190static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 2191{ 2192 drmmode_output_private_ptr drmmode_output = output->driver_private; 2193 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2194 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2195 int i; 2196 DisplayModePtr Modes = NULL, Mode; 2197 xf86MonPtr mon = NULL; 2198 2199 if (!koutput) 2200 return NULL; 2201 2202 drmModeFreePropertyBlob(drmmode_output->edid_blob); 2203 2204 /* look for an EDID property */ 2205 drmmode_output->edid_blob = 2206 koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID"); 2207 2208 if (drmmode_output->edid_blob) { 2209 mon = xf86InterpretEDID(output->scrn->scrnIndex, 2210 drmmode_output->edid_blob->data); 2211 if (mon && drmmode_output->edid_blob->length > 128) 2212 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 2213 } 2214 xf86OutputSetEDID(output, mon); 2215 2216 /* modes should already be available */ 2217 for (i = 0; i < koutput->count_modes; i++) { 2218 Mode = xnfalloc(sizeof(DisplayModeRec)); 2219 2220 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 2221 Mode); 2222 Modes = xf86ModesAdd(Modes, Mode); 2223 2224 } 2225 return Modes; 2226} 2227 2228static void drmmode_output_destroy(xf86OutputPtr output) 2229{ 2230 drmmode_output_private_ptr drmmode_output = output->driver_private; 2231 int i; 2232 2233 if (drmmode_output->edid_blob) 2234 drmModeFreePropertyBlob(drmmode_output->edid_blob); 2235 for (i = 0; i < drmmode_output->num_props; i++) { 2236 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 2237 free(drmmode_output->props[i].atoms); 2238 } 2239 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 2240 drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 2241 } 2242 free(drmmode_output->mode_encoders); 2243 free(drmmode_output->props); 2244 drmModeFreeConnector(drmmode_output->mode_output); 2245 free(drmmode_output); 2246 output->driver_private = NULL; 2247} 2248 2249static void drmmode_output_dpms(xf86OutputPtr output, int mode) 2250{ 2251 drmmode_output_private_ptr drmmode_output = output->driver_private; 2252 xf86CrtcPtr crtc = output->crtc; 2253 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2254 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2255 2256 if (!koutput) 2257 return; 2258 2259 if (mode != DPMSModeOn && crtc) 2260 drmmode_do_crtc_dpms(crtc, mode); 2261 2262 drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 2263 drmmode_output->dpms_enum_id, mode); 2264 2265 if (mode == DPMSModeOn && crtc) { 2266 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2267 2268 if (drmmode_crtc->need_modeset) 2269 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2270 crtc->x, crtc->y); 2271 else 2272 drmmode_do_crtc_dpms(output->crtc, mode); 2273 } 2274} 2275 2276static Bool drmmode_property_ignore(drmModePropertyPtr prop) 2277{ 2278 if (!prop) 2279 return TRUE; 2280 /* ignore blob prop */ 2281 if (prop->flags & DRM_MODE_PROP_BLOB) 2282 return TRUE; 2283 /* ignore standard property */ 2284 if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 2285 return TRUE; 2286 2287 return FALSE; 2288} 2289 2290static void drmmode_output_create_resources(xf86OutputPtr output) 2291{ 2292 AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); 2293 drmmode_output_private_ptr drmmode_output = output->driver_private; 2294 drmmode_crtc_private_ptr drmmode_crtc; 2295 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 2296 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2297 drmModePropertyPtr drmmode_prop, tearfree_prop; 2298 int i, j, err; 2299 Atom name; 2300 2301 /* Create CONNECTOR_ID property */ 2302 name = MakeAtom("CONNECTOR_ID", 12, TRUE); 2303 if (name != BAD_RESOURCE) { 2304 INT32 value = mode_output->connector_id; 2305 2306 err = RRConfigureOutputProperty(output->randr_output, name, 2307 FALSE, FALSE, TRUE, 1, &value); 2308 if (err != Success) { 2309 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2310 "RRConfigureOutputProperty error, %d\n", err); 2311 } 2312 2313 err = RRChangeOutputProperty(output->randr_output, name, 2314 XA_INTEGER, 32, PropModeReplace, 1, 2315 &value, FALSE, FALSE); 2316 if (err != Success) { 2317 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2318 "RRChangeOutputProperty error, %d\n", err); 2319 } 2320 } 2321 2322 drmmode_output->props = 2323 calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 2324 if (!drmmode_output->props) 2325 return; 2326 2327 drmmode_output->num_props = 0; 2328 for (i = 0, j = 0; i < mode_output->count_props; i++) { 2329 drmmode_prop = 2330 drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 2331 if (drmmode_property_ignore(drmmode_prop)) { 2332 drmModeFreeProperty(drmmode_prop); 2333 continue; 2334 } 2335 drmmode_output->props[j].mode_prop = drmmode_prop; 2336 drmmode_output->props[j].value = mode_output->prop_values[i]; 2337 drmmode_output->num_props++; 2338 j++; 2339 } 2340 2341 /* Userspace-only property for TearFree */ 2342 tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 2343 tearfree_prop->flags = DRM_MODE_PROP_ENUM; 2344 strcpy(tearfree_prop->name, "TearFree"); 2345 tearfree_prop->count_enums = 3; 2346 tearfree_prop->enums = calloc(tearfree_prop->count_enums, 2347 sizeof(*tearfree_prop->enums)); 2348 strcpy(tearfree_prop->enums[0].name, "off"); 2349 strcpy(tearfree_prop->enums[1].name, "on"); 2350 tearfree_prop->enums[1].value = 1; 2351 strcpy(tearfree_prop->enums[2].name, "auto"); 2352 tearfree_prop->enums[2].value = 2; 2353 drmmode_output->props[j].mode_prop = tearfree_prop; 2354 drmmode_output->props[j].value = info->tear_free; 2355 drmmode_output->tear_free = info->tear_free; 2356 drmmode_output->num_props++; 2357 2358 for (i = 0; i < drmmode_output->num_props; i++) { 2359 drmmode_prop_ptr p = &drmmode_output->props[i]; 2360 drmmode_prop = p->mode_prop; 2361 2362 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 2363 INT32 range[2]; 2364 INT32 value = p->value; 2365 2366 p->num_atoms = 1; 2367 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2368 if (!p->atoms) 2369 continue; 2370 p->atoms[0] = 2371 MakeAtom(drmmode_prop->name, 2372 strlen(drmmode_prop->name), TRUE); 2373 range[0] = drmmode_prop->values[0]; 2374 range[1] = drmmode_prop->values[1]; 2375 err = 2376 RRConfigureOutputProperty(output->randr_output, 2377 p->atoms[0], FALSE, TRUE, 2378 drmmode_prop->flags & 2379 DRM_MODE_PROP_IMMUTABLE ? 2380 TRUE : FALSE, 2, range); 2381 if (err != 0) { 2382 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2383 "RRConfigureOutputProperty error, %d\n", 2384 err); 2385 } 2386 err = 2387 RRChangeOutputProperty(output->randr_output, 2388 p->atoms[0], XA_INTEGER, 32, 2389 PropModeReplace, 1, &value, 2390 FALSE, TRUE); 2391 if (err != 0) { 2392 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2393 "RRChangeOutputProperty error, %d\n", 2394 err); 2395 } 2396 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 2397 p->num_atoms = drmmode_prop->count_enums + 1; 2398 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2399 if (!p->atoms) 2400 continue; 2401 p->atoms[0] = 2402 MakeAtom(drmmode_prop->name, 2403 strlen(drmmode_prop->name), TRUE); 2404 for (j = 1; j <= drmmode_prop->count_enums; j++) { 2405 struct drm_mode_property_enum *e = 2406 &drmmode_prop->enums[j - 1]; 2407 p->atoms[j] = 2408 MakeAtom(e->name, strlen(e->name), TRUE); 2409 } 2410 err = 2411 RRConfigureOutputProperty(output->randr_output, 2412 p->atoms[0], FALSE, FALSE, 2413 drmmode_prop->flags & 2414 DRM_MODE_PROP_IMMUTABLE ? 2415 TRUE : FALSE, 2416 p->num_atoms - 1, 2417 (INT32 *) & p->atoms[1]); 2418 if (err != 0) { 2419 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2420 "RRConfigureOutputProperty error, %d\n", 2421 err); 2422 } 2423 for (j = 0; j < drmmode_prop->count_enums; j++) 2424 if (drmmode_prop->enums[j].value == p->value) 2425 break; 2426 /* there's always a matching value */ 2427 err = 2428 RRChangeOutputProperty(output->randr_output, 2429 p->atoms[0], XA_ATOM, 32, 2430 PropModeReplace, 1, 2431 &p->atoms[j + 1], FALSE, 2432 TRUE); 2433 if (err != 0) { 2434 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2435 "RRChangeOutputProperty error, %d\n", 2436 err); 2437 } 2438 } 2439 } 2440 2441 /* Do not configure cm properties on output if there's no support. */ 2442 if (!drmmode_cm_enabled(drmmode_output->drmmode)) 2443 return; 2444 2445 drmmode_crtc = output->crtc ? output->crtc->driver_private : NULL; 2446 2447 for (i = 0; i < CM_NUM_PROPS; i++) 2448 rr_configure_and_change_cm_property(output, drmmode_crtc, i); 2449} 2450 2451static void 2452drmmode_output_set_tear_free(AMDGPUEntPtr pAMDGPUEnt, 2453 drmmode_output_private_ptr drmmode_output, 2454 xf86CrtcPtr crtc, int tear_free) 2455{ 2456 if (drmmode_output->tear_free == tear_free) 2457 return; 2458 2459 drmmode_output->tear_free = tear_free; 2460 2461 if (crtc) { 2462 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2463 crtc->x, crtc->y); 2464 } 2465} 2466 2467static Bool 2468drmmode_output_set_property(xf86OutputPtr output, Atom property, 2469 RRPropertyValuePtr value) 2470{ 2471 drmmode_output_private_ptr drmmode_output = output->driver_private; 2472 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2473 enum drmmode_cm_prop cm_prop_index; 2474 int i; 2475 2476 cm_prop_index = get_cm_enum_from_str(NameForAtom(property)); 2477 if (cm_prop_index >= 0 && cm_prop_index < CM_DEGAMMA_LUT_SIZE) { 2478 if (!output->crtc) 2479 return FALSE; 2480 if (drmmode_crtc_stage_cm_prop(output->crtc, cm_prop_index, 2481 value)) 2482 return FALSE; 2483 if (drmmode_crtc_push_cm_prop(output->crtc, cm_prop_index)) 2484 return FALSE; 2485 return TRUE; 2486 } 2487 2488 for (i = 0; i < drmmode_output->num_props; i++) { 2489 drmmode_prop_ptr p = &drmmode_output->props[i]; 2490 2491 if (p->atoms[0] != property) 2492 continue; 2493 2494 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 2495 uint32_t val; 2496 2497 if (value->type != XA_INTEGER || value->format != 32 || 2498 value->size != 1) 2499 return FALSE; 2500 val = *(uint32_t *) value->data; 2501 2502 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2503 drmmode_output->output_id, 2504 p->mode_prop->prop_id, 2505 (uint64_t) val); 2506 return TRUE; 2507 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2508 Atom atom; 2509 const char *name; 2510 int j; 2511 2512 if (value->type != XA_ATOM || value->format != 32 2513 || value->size != 1) 2514 return FALSE; 2515 memcpy(&atom, value->data, 4); 2516 if (!(name = NameForAtom(atom))) 2517 return FALSE; 2518 2519 /* search for matching name string, then set its value down */ 2520 for (j = 0; j < p->mode_prop->count_enums; j++) { 2521 if (!strcmp(p->mode_prop->enums[j].name, name)) { 2522 if (i == (drmmode_output->num_props - 1)) { 2523 drmmode_output_set_tear_free(pAMDGPUEnt, 2524 drmmode_output, 2525 output->crtc, j); 2526 } else { 2527 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2528 drmmode_output->output_id, 2529 p->mode_prop->prop_id, 2530 p->mode_prop->enums[j].value); 2531 } 2532 2533 return TRUE; 2534 } 2535 } 2536 } 2537 } 2538 2539 return TRUE; 2540} 2541 2542static Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 2543{ 2544 drmmode_crtc_private_ptr drmmode_crtc; 2545 enum drmmode_cm_prop cm_prop_id; 2546 int ret; 2547 2548 /* First, see if it's a cm property */ 2549 cm_prop_id = get_cm_enum_from_str(NameForAtom(property)); 2550 if (output->crtc && cm_prop_id != CM_INVALID_PROP) { 2551 drmmode_crtc = output->crtc->driver_private; 2552 2553 ret = rr_configure_and_change_cm_property(output, drmmode_crtc, 2554 cm_prop_id); 2555 if (ret) { 2556 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2557 "Error getting color property: %d\n", 2558 ret); 2559 return FALSE; 2560 } 2561 return TRUE; 2562 } 2563 2564 /* Otherwise, must be an output property. */ 2565 return TRUE; 2566} 2567 2568static const xf86OutputFuncsRec drmmode_output_funcs = { 2569 .dpms = drmmode_output_dpms, 2570 .create_resources = drmmode_output_create_resources, 2571 .set_property = drmmode_output_set_property, 2572 .get_property = drmmode_output_get_property, 2573 .detect = drmmode_output_detect, 2574 .mode_valid = drmmode_output_mode_valid, 2575 2576 .get_modes = drmmode_output_get_modes, 2577 .destroy = drmmode_output_destroy 2578}; 2579 2580static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2581 SubPixelHorizontalRGB, 2582 SubPixelHorizontalBGR, 2583 SubPixelVerticalRGB, 2584 SubPixelVerticalBGR, 2585 SubPixelNone 2586}; 2587 2588const char *output_names[] = { "None", 2589 "VGA", 2590 "DVI-I", 2591 "DVI-D", 2592 "DVI-A", 2593 "Composite", 2594 "S-video", 2595 "LVDS", 2596 "CTV", 2597 "DIN", 2598 "DisplayPort", 2599 "HDMI-A", 2600 "HDMI-B", 2601 "TV", 2602 "eDP", 2603 "Virtual", 2604 "DSI", 2605}; 2606 2607#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 2608 2609static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 2610{ 2611 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2612 int i; 2613 for (i = 0; i < xf86_config->num_output; i++) { 2614 xf86OutputPtr output = xf86_config->output[i]; 2615 drmmode_output_private_ptr drmmode_output; 2616 drmmode_output = output->driver_private; 2617 if (drmmode_output->output_id == id) 2618 return output; 2619 } 2620 return NULL; 2621} 2622 2623static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 2624{ 2625 char *conn; 2626 char conn_id[5]; 2627 int id, len; 2628 char *blob_data; 2629 2630 if (!path_blob) 2631 return -1; 2632 2633 blob_data = path_blob->data; 2634 /* we only handle MST paths for now */ 2635 if (strncmp(blob_data, "mst:", 4)) 2636 return -1; 2637 2638 conn = strchr(blob_data + 4, '-'); 2639 if (!conn) 2640 return -1; 2641 len = conn - (blob_data + 4); 2642 if (len + 1 > 5) 2643 return -1; 2644 memcpy(conn_id, blob_data + 4, len); 2645 conn_id[len] = '\0'; 2646 id = strtoul(conn_id, NULL, 10); 2647 2648 *conn_base_id = id; 2649 2650 *path = conn + 1; 2651 return 0; 2652} 2653 2654static void 2655drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 2656 drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 2657{ 2658 xf86OutputPtr output; 2659 int conn_id; 2660 char *extra_path; 2661 2662 output = NULL; 2663 if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 2664 output = find_output(pScrn, conn_id); 2665 if (output) { 2666 snprintf(name, 32, "%s-%s", output->name, extra_path); 2667 } else { 2668 if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 2669 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 2670 } else if (pScrn->is_gpu) { 2671 snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 2672 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 2673 } else { 2674 /* need to do smart conversion here for compat with non-kms ATI driver */ 2675 if (koutput->connector_type_id == 1) { 2676 switch(koutput->connector_type) { 2677 case DRM_MODE_CONNECTOR_DVII: 2678 case DRM_MODE_CONNECTOR_DVID: 2679 case DRM_MODE_CONNECTOR_DVIA: 2680 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 2681 (*num_dvi)++; 2682 break; 2683 case DRM_MODE_CONNECTOR_HDMIA: 2684 case DRM_MODE_CONNECTOR_HDMIB: 2685 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 2686 (*num_hdmi)++; 2687 break; 2688 case DRM_MODE_CONNECTOR_VGA: 2689 case DRM_MODE_CONNECTOR_DisplayPort: 2690 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2691 break; 2692 default: 2693 snprintf(name, 32, "%s", output_names[koutput->connector_type]); 2694 break; 2695 } 2696 } else { 2697 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2698 } 2699 } 2700 } 2701} 2702 2703 2704static unsigned int 2705drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 2706{ 2707 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2708 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2709 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2710 xf86OutputPtr output; 2711 drmModeConnectorPtr koutput; 2712 drmModeEncoderPtr *kencoders = NULL; 2713 drmmode_output_private_ptr drmmode_output; 2714 drmModePropertyBlobPtr path_blob = NULL; 2715#if XF86_CRTC_VERSION >= 8 2716 Bool nonDesktop = FALSE; 2717#endif 2718 char name[32]; 2719 int i; 2720 const char *s; 2721 2722 koutput = 2723 drmModeGetConnector(pAMDGPUEnt->fd, 2724 mode_res->connectors[num]); 2725 if (!koutput) 2726 return 0; 2727 2728 path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH"); 2729 2730#if XF86_CRTC_VERSION >= 8 2731 i = koutput_get_prop_idx(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_RANGE, 2732 "non-desktop"); 2733 if (i >= 0) 2734 nonDesktop = koutput->prop_values[i] != 0; 2735#endif 2736 2737 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2738 if (!kencoders) { 2739 goto out_free_encoders; 2740 } 2741 2742 for (i = 0; i < koutput->count_encoders; i++) { 2743 kencoders[i] = 2744 drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 2745 if (!kencoders[i]) { 2746 goto out_free_encoders; 2747 } 2748 } 2749 2750 drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 2751 if (path_blob) { 2752 drmModeFreePropertyBlob(path_blob); 2753 } 2754 2755 if (path_blob && dynamic) { 2756 /* See if we have an output with this name already 2757 * and hook stuff up. 2758 */ 2759 for (i = 0; i < xf86_config->num_output; i++) { 2760 output = xf86_config->output[i]; 2761 2762 if (strncmp(output->name, name, 32)) 2763 continue; 2764 2765 drmmode_output = output->driver_private; 2766 drmmode_output->output_id = mode_res->connectors[num]; 2767 drmmode_output->mode_output = koutput; 2768#if XF86_CRTC_VERSION >= 8 2769 output->non_desktop = nonDesktop; 2770#endif 2771 for (i = 0; i < koutput->count_encoders; i++) { 2772 drmModeFreeEncoder(kencoders[i]); 2773 } 2774 free(kencoders); 2775 return 1; 2776 } 2777 } 2778 2779 if (xf86IsEntityShared(pScrn->entityList[0])) { 2780 if ((s = 2781 xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2782 if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 2783 goto out_free_encoders; 2784 } else { 2785 if (info->instance_id != num) 2786 goto out_free_encoders; 2787 } 2788 } 2789 2790 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 2791 if (!output) { 2792 goto out_free_encoders; 2793 } 2794 2795 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2796 if (!drmmode_output) { 2797 xf86OutputDestroy(output); 2798 goto out_free_encoders; 2799 } 2800 2801 drmmode_output->output_id = mode_res->connectors[num]; 2802 drmmode_output->mode_output = koutput; 2803 drmmode_output->mode_encoders = kencoders; 2804 drmmode_output->drmmode = drmmode; 2805 output->mm_width = koutput->mmWidth; 2806 output->mm_height = koutput->mmHeight; 2807 2808 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2809 output->interlaceAllowed = TRUE; 2810 output->doubleScanAllowed = TRUE; 2811 output->driver_private = drmmode_output; 2812#if XF86_CRTC_VERSION >= 8 2813 output->non_desktop = nonDesktop; 2814#endif 2815 2816 output->possible_crtcs = 0xffffffff; 2817 for (i = 0; i < koutput->count_encoders; i++) { 2818 output->possible_crtcs &= kencoders[i]->possible_crtcs; 2819 } 2820 /* work out the possible clones later */ 2821 output->possible_clones = 0; 2822 2823 drmmode_output->dpms_enum_id = 2824 koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM, 2825 "DPMS"); 2826 2827 if (dynamic) { 2828 output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 2829 drmmode_output_create_resources(output); 2830 } 2831 2832 return 1; 2833out_free_encoders: 2834 if (kencoders) { 2835 for (i = 0; i < koutput->count_encoders; i++) 2836 drmModeFreeEncoder(kencoders[i]); 2837 free(kencoders); 2838 } 2839 drmModeFreeConnector(koutput); 2840 return 0; 2841} 2842 2843uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2844{ 2845 drmmode_output_private_ptr drmmode_output = 2846 output->driver_private, clone_drmout; 2847 int i; 2848 xf86OutputPtr clone_output; 2849 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2850 int index_mask = 0; 2851 2852 if (drmmode_output->enc_clone_mask == 0) 2853 return index_mask; 2854 2855 for (i = 0; i < xf86_config->num_output; i++) { 2856 clone_output = xf86_config->output[i]; 2857 clone_drmout = clone_output->driver_private; 2858 if (output == clone_output) 2859 continue; 2860 2861 if (clone_drmout->enc_mask == 0) 2862 continue; 2863 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2864 index_mask |= (1 << i); 2865 } 2866 return index_mask; 2867} 2868 2869static void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2870{ 2871 int i, j; 2872 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2873 2874 for (i = 0; i < xf86_config->num_output; i++) { 2875 xf86OutputPtr output = xf86_config->output[i]; 2876 drmmode_output_private_ptr drmmode_output; 2877 2878 drmmode_output = output->driver_private; 2879 drmmode_output->enc_clone_mask = 0xff; 2880 /* and all the possible encoder clones for this output together */ 2881 for (j = 0; j < drmmode_output->mode_output->count_encoders; 2882 j++) { 2883 int k; 2884 for (k = 0; k < mode_res->count_encoders; k++) { 2885 if (mode_res->encoders[k] == 2886 drmmode_output-> 2887 mode_encoders[j]->encoder_id) 2888 drmmode_output->enc_mask |= (1 << k); 2889 } 2890 2891 drmmode_output->enc_clone_mask &= 2892 drmmode_output->mode_encoders[j]->possible_clones; 2893 } 2894 } 2895 2896 for (i = 0; i < xf86_config->num_output; i++) { 2897 xf86OutputPtr output = xf86_config->output[i]; 2898 output->possible_clones = find_clones(scrn, output); 2899 } 2900} 2901 2902/* returns pitch alignment in pixels */ 2903int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 2904{ 2905 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2906 2907 if (info->have_tiling_info) 2908 /* linear aligned requirements */ 2909 return MAX(64, info->group_bytes / bpe); 2910 else 2911 /* default to 512 elements if we don't know the real 2912 * group size otherwise the kernel may reject the CS 2913 * if the group sizes don't match as the pitch won't 2914 * be aligned properly. 2915 */ 2916 return 512; 2917} 2918 2919static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 2920{ 2921 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2922 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2923 struct amdgpu_buffer *old_front = NULL; 2924 ScreenPtr screen = xf86ScrnToScreen(scrn); 2925 int i, pitch, old_width, old_height, old_pitch; 2926 int cpp = info->pixel_bytes; 2927 PixmapPtr ppix = screen->GetScreenPixmap(screen); 2928 void *fb_shadow; 2929 int hint = 0; 2930 2931 if (scrn->virtualX == width && scrn->virtualY == height) 2932 return TRUE; 2933 2934 if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 2935 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2936 "Xorg tried resizing screen to %dx%d, but maximum " 2937 "supported is %dx%d\n", width, height, 2938 xf86_config->maxWidth, xf86_config->maxHeight); 2939 return FALSE; 2940 } 2941 2942 if (info->shadow_primary) 2943 hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2944 else if (!info->use_glamor) 2945 hint = AMDGPU_CREATE_PIXMAP_LINEAR; 2946 2947 xf86DrvMsg(scrn->scrnIndex, X_INFO, 2948 "Allocate new frame buffer %dx%d\n", width, height); 2949 2950 old_width = scrn->virtualX; 2951 old_height = scrn->virtualY; 2952 old_pitch = scrn->displayWidth; 2953 old_front = info->front_buffer; 2954 2955 scrn->virtualX = width; 2956 scrn->virtualY = height; 2957 2958 info->front_buffer = 2959 amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 2960 scrn->depth, hint, scrn->bitsPerPixel, 2961 &pitch); 2962 if (!info->front_buffer) { 2963 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2964 "Failed to allocate front buffer memory\n"); 2965 goto fail; 2966 } 2967 2968 if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 2969 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2970 "Failed to map front buffer memory\n"); 2971 goto fail; 2972 } 2973 2974 xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 2975 scrn->displayWidth = pitch / cpp; 2976 2977 if (info->use_glamor || 2978 (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2979 screen->ModifyPixmapHeader(ppix, 2980 width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 2981 } else { 2982 fb_shadow = calloc(1, pitch * scrn->virtualY); 2983 if (!fb_shadow) 2984 goto fail; 2985 free(info->fb_shadow); 2986 info->fb_shadow = fb_shadow; 2987 screen->ModifyPixmapHeader(ppix, 2988 width, height, -1, -1, pitch, 2989 info->fb_shadow); 2990 } 2991 2992 if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 2993 goto fail; 2994 2995 if (info->use_glamor || info->dri2.enabled) { 2996 if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 2997 goto fail; 2998 } 2999 3000 amdgpu_pixmap_clear(ppix); 3001 amdgpu_glamor_finish(scrn); 3002 3003 for (i = 0; i < xf86_config->num_crtc; i++) { 3004 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3005 3006 if (!crtc->enabled) 3007 continue; 3008 3009 drmmode_set_mode_major(crtc, &crtc->mode, 3010 crtc->rotation, crtc->x, crtc->y); 3011 } 3012 3013 if (old_front) { 3014 amdgpu_bo_unref(&old_front); 3015 } 3016 3017 return TRUE; 3018 3019fail: 3020 if (info->front_buffer) { 3021 amdgpu_bo_unref(&info->front_buffer); 3022 } 3023 info->front_buffer = old_front; 3024 scrn->virtualX = old_width; 3025 scrn->virtualY = old_height; 3026 scrn->displayWidth = old_pitch; 3027 3028 return FALSE; 3029} 3030 3031static void 3032drmmode_validate_leases(ScrnInfoPtr scrn) 3033{ 3034#ifdef XF86_LEASE_VERSION 3035 ScreenPtr screen = scrn->pScreen; 3036 rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 3037 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3038 drmModeLesseeListPtr lessees; 3039 RRLeasePtr lease, next; 3040 int l; 3041 3042 /* We can't talk to the kernel about leases when VT switched */ 3043 if (!scrn->vtSema) 3044 return; 3045 3046 lessees = drmModeListLessees(pAMDGPUEnt->fd); 3047 if (!lessees) 3048 return; 3049 3050 xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 3051 drmmode_lease_private_ptr lease_private = lease->devPrivate; 3052 3053 for (l = 0; l < lessees->count; l++) { 3054 if (lessees->lessees[l] == lease_private->lessee_id) 3055 break; 3056 } 3057 3058 /* check to see if the lease has gone away */ 3059 if (l == lessees->count) { 3060 free(lease_private); 3061 lease->devPrivate = NULL; 3062 xf86CrtcLeaseTerminated(lease); 3063 } 3064 } 3065 3066 free(lessees); 3067#endif 3068} 3069 3070#ifdef XF86_LEASE_VERSION 3071 3072static int 3073drmmode_create_lease(RRLeasePtr lease, int *fd) 3074{ 3075 ScreenPtr screen = lease->screen; 3076 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3077 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3078 drmmode_lease_private_ptr lease_private; 3079 int noutput = lease->numOutputs; 3080 int ncrtc = lease->numCrtcs; 3081 uint32_t *objects; 3082 size_t nobjects; 3083 int lease_fd; 3084 int c, o; 3085 int i; 3086 3087 nobjects = ncrtc + noutput; 3088 if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 3089 ncrtc > (SIZE_MAX - noutput)) 3090 return BadValue; 3091 3092 lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 3093 if (!lease_private) 3094 return BadAlloc; 3095 3096 objects = malloc(nobjects * 4); 3097 if (!objects) { 3098 free(lease_private); 3099 return BadAlloc; 3100 } 3101 3102 i = 0; 3103 3104 /* Add CRTC ids */ 3105 for (c = 0; c < ncrtc; c++) { 3106 xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 3107 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3108 3109 objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 3110 } 3111 3112 /* Add connector ids */ 3113 for (o = 0; o < noutput; o++) { 3114 xf86OutputPtr output = lease->outputs[o]->devPrivate; 3115 drmmode_output_private_ptr drmmode_output = output->driver_private; 3116 3117 objects[i++] = drmmode_output->mode_output->connector_id; 3118 } 3119 3120 /* call kernel to create lease */ 3121 assert (i == nobjects); 3122 3123 lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, 3124 &lease_private->lessee_id); 3125 3126 free(objects); 3127 3128 if (lease_fd < 0) { 3129 free(lease_private); 3130 return BadMatch; 3131 } 3132 3133 lease->devPrivate = lease_private; 3134 3135 xf86CrtcLeaseStarted(lease); 3136 3137 *fd = lease_fd; 3138 return Success; 3139} 3140 3141static void 3142drmmode_terminate_lease(RRLeasePtr lease) 3143{ 3144 drmmode_lease_private_ptr lease_private = lease->devPrivate; 3145 ScreenPtr screen = lease->screen; 3146 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3147 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3148 3149 if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) { 3150 free(lease_private); 3151 lease->devPrivate = NULL; 3152 xf86CrtcLeaseTerminated(lease); 3153 } 3154} 3155 3156#endif // XF86_LEASE_VERSION 3157 3158static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 3159 .resize = drmmode_xf86crtc_resize, 3160#ifdef XF86_LEASE_VERSION 3161 .create_lease = drmmode_create_lease, 3162 .terminate_lease = drmmode_terminate_lease 3163#endif 3164}; 3165 3166static void 3167drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 3168{ 3169 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3170 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3171 drmmode_flipdata_ptr flipdata = event_data; 3172 int crtc_id = drmmode_get_crtc_id(crtc); 3173 struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3174 3175 if (drmmode_crtc->flip_pending == *fb) { 3176 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 3177 NULL); 3178 } 3179 drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3180 3181 if (--flipdata->flip_count == 0) { 3182 if (!flipdata->fe_crtc) 3183 flipdata->fe_crtc = crtc; 3184 flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 3185 free(flipdata); 3186 } 3187} 3188 3189static void 3190drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 3191{ 3192 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3193 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3194 drmmode_flipdata_ptr flipdata = event_data; 3195 int crtc_id = drmmode_get_crtc_id(crtc); 3196 struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3197 3198 /* Is this the event whose info shall be delivered to higher level? */ 3199 if (crtc == flipdata->fe_crtc) { 3200 /* Yes: Cache msc, ust for later delivery. */ 3201 flipdata->fe_frame = frame; 3202 flipdata->fe_usec = usec; 3203 } 3204 3205 if (*fb) { 3206 if (drmmode_crtc->flip_pending == *fb) { 3207 drmmode_fb_reference(pAMDGPUEnt->fd, 3208 &drmmode_crtc->flip_pending, NULL); 3209 } 3210 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb); 3211 drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3212 } 3213 3214 if (--flipdata->flip_count == 0) { 3215 /* Deliver MSC & UST from reference/current CRTC to flip event 3216 * handler 3217 */ 3218 if (flipdata->fe_crtc) 3219 flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 3220 flipdata->fe_usec, flipdata->event_data); 3221 else 3222 flipdata->handler(crtc, frame, usec, flipdata->event_data); 3223 3224 free(flipdata); 3225 } 3226} 3227 3228#if HAVE_NOTIFY_FD 3229static void drmmode_notify_fd(int fd, int notify, void *data) 3230{ 3231 drmmode_ptr drmmode = data; 3232 amdgpu_drm_handle_event(fd, &drmmode->event_context); 3233} 3234#else 3235static void drm_wakeup_handler(pointer data, int err, pointer p) 3236{ 3237 drmmode_ptr drmmode = data; 3238 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 3239 fd_set *read_mask = p; 3240 3241 if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 3242 amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context); 3243 } 3244} 3245#endif 3246 3247static Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) 3248{ 3249 uint64_t cap_value; 3250 3251 return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 3252 &cap_value) == 0 && cap_value != 0; 3253} 3254 3255static int 3256drmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, 3257 int fb_id, uint32_t flags, uintptr_t drm_queue_seq) 3258{ 3259 flags |= DRM_MODE_PAGE_FLIP_EVENT; 3260 return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 3261 fb_id, flags, (void*)drm_queue_seq); 3262} 3263 3264int 3265drmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, 3266 drmmode_crtc_private_ptr drmmode_crtc, 3267 int fb_id, uint32_t flags, 3268 uintptr_t drm_queue_seq, uint32_t target_msc) 3269{ 3270 if (pAMDGPUEnt->has_page_flip_target) { 3271 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 3272 return drmModePageFlipTarget(pAMDGPUEnt->fd, 3273 drmmode_crtc->mode_crtc->crtc_id, 3274 fb_id, flags, (void*)drm_queue_seq, 3275 target_msc); 3276 } 3277 3278 return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 3279 drm_queue_seq); 3280} 3281 3282int 3283drmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, 3284 drmmode_crtc_private_ptr drmmode_crtc, 3285 int fb_id, uint32_t flags, 3286 uintptr_t drm_queue_seq, uint32_t target_msc) 3287{ 3288 if (pAMDGPUEnt->has_page_flip_target) { 3289 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 3290 return drmModePageFlipTarget(pAMDGPUEnt->fd, 3291 drmmode_crtc->mode_crtc->crtc_id, 3292 fb_id, flags, (void*)drm_queue_seq, 3293 target_msc); 3294 } 3295 3296 return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 3297 drm_queue_seq); 3298} 3299 3300/** 3301 * Initialize DDX color management support. It does two things: 3302 * 3303 * 1. Cache DRM color management property type IDs, as they do not change. They 3304 * will be used later to modify color management via DRM, or to determine if 3305 * there's kernel support for color management. 3306 * 3307 * 2. Cache degamma/gamma LUT sizes, since all CRTCs have the same LUT sizes on 3308 * AMD hardware. 3309 * 3310 * If the cached ID's are all 0 after calling this function, then color 3311 * management is not supported. For short, checking if the gamma LUT size 3312 * property ID == 0 is sufficient. 3313 * 3314 * This should be called before CRTCs are initialized within pre_init, as the 3315 * cached values will be used there. 3316 * 3317 * @drm_fd: DRM file descriptor 3318 * @drmmode: drmmode object, where the cached IDs are stored 3319 * @mode_res: The DRM mode resource containing the CRTC ids 3320 */ 3321static void drmmode_cm_init(int drm_fd, drmmode_ptr drmmode, 3322 drmModeResPtr mode_res) 3323{ 3324 drmModeObjectPropertiesPtr drm_props; 3325 drmModePropertyPtr drm_prop; 3326 enum drmmode_cm_prop cm_prop; 3327 uint32_t cm_enabled = 0; 3328 uint32_t cm_all_enabled = (1 << CM_NUM_PROPS) - 1; 3329 int i; 3330 3331 memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 3332 drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 3333 3334 if (!mode_res->crtcs) 3335 return; 3336 3337 /* AMD hardware has color management support on all pipes. It is 3338 * therefore sufficient to only check the first CRTC. 3339 */ 3340 drm_props = drmModeObjectGetProperties(drm_fd, 3341 mode_res->crtcs[0], 3342 DRM_MODE_OBJECT_CRTC); 3343 if (!drm_props) 3344 return; 3345 3346 for (i = 0; i < drm_props->count_props; i++) { 3347 drm_prop = drmModeGetProperty(drm_fd, 3348 drm_props->props[i]); 3349 if (!drm_prop) 3350 continue; 3351 3352 cm_prop = get_cm_enum_from_str(drm_prop->name); 3353 if (cm_prop == CM_INVALID_PROP) 3354 continue; 3355 3356 if (cm_prop == CM_DEGAMMA_LUT_SIZE) 3357 drmmode->degamma_lut_size = drm_props->prop_values[i]; 3358 else if (cm_prop == CM_GAMMA_LUT_SIZE) 3359 drmmode->gamma_lut_size = drm_props->prop_values[i]; 3360 3361 drmmode->cm_prop_ids[cm_prop] = drm_props->props[i]; 3362 cm_enabled |= 1 << cm_prop; 3363 3364 drmModeFreeProperty(drm_prop); 3365 } 3366 drmModeFreeObjectProperties(drm_props); 3367 3368 /* cm is enabled only if all prop ids are found */ 3369 if (cm_enabled == cm_all_enabled) 3370 return; 3371 3372 /* Otherwise, disable DDX cm support */ 3373 memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 3374 drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 3375} 3376 3377Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 3378{ 3379 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3380 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3381 int i, num_dvi = 0, num_hdmi = 0; 3382 unsigned int crtcs_needed = 0; 3383 unsigned int crtcs_got = 0; 3384 drmModeResPtr mode_res; 3385 char *bus_id_string, *provider_name; 3386 3387 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 3388 3389 drmmode->scrn = pScrn; 3390 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3391 if (!mode_res) 3392 return FALSE; 3393 3394 drmmode->count_crtcs = mode_res->count_crtcs; 3395 xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 3396 mode_res->max_height); 3397 3398 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3399 "Initializing outputs ...\n"); 3400 for (i = 0; i < mode_res->count_connectors; i++) 3401 crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 3402 3403 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3404 "%d crtcs needed for screen.\n", crtcs_needed); 3405 3406 /* Need per-screen drmmode_crtc_funcs, based on our global template, 3407 * so we can disable some functions, depending on screen settings. 3408 */ 3409 info->drmmode_crtc_funcs = drmmode_crtc_funcs; 3410 3411 if (!info->use_glamor) { 3412 /* Rotation requires hardware acceleration */ 3413 info->drmmode_crtc_funcs.shadow_allocate = NULL; 3414 info->drmmode_crtc_funcs.shadow_create = NULL; 3415 info->drmmode_crtc_funcs.shadow_destroy = NULL; 3416 } 3417 3418 drmmode_cm_init(pAMDGPUEnt->fd, drmmode, mode_res); 3419 3420 /* Spare the server the effort to compute and update unused CLUTs. */ 3421 if (pScrn->depth == 30 && !drmmode_cm_enabled(drmmode)) 3422 info->drmmode_crtc_funcs.gamma_set = NULL; 3423 3424 for (i = 0; i < mode_res->count_crtcs; i++) { 3425 if (!xf86IsEntityShared(pScrn->entityList[0]) || 3426 (crtcs_got < crtcs_needed && 3427 !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 3428 crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 3429 } 3430 3431 /* All ZaphodHeads outputs provided with matching crtcs? */ 3432 if (crtcs_got < crtcs_needed) { 3433 if (crtcs_got == 0) { 3434 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 3435 "No ZaphodHeads CRTC available, needed %u\n", 3436 crtcs_needed); 3437 return FALSE; 3438 } 3439 3440 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3441 "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 3442 crtcs_needed); 3443 } 3444 3445 /* workout clones */ 3446 drmmode_clones_init(pScrn, drmmode, mode_res); 3447 3448 bus_id_string = DRICreatePCIBusID(info->PciInfo); 3449 XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 3450 free(bus_id_string); 3451 xf86ProviderSetup(pScrn, NULL, provider_name); 3452 free(provider_name); 3453 3454 xf86InitialConfiguration(pScrn, TRUE); 3455 3456 pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); 3457 3458 drmModeFreeResources(mode_res); 3459 return TRUE; 3460} 3461 3462void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3463{ 3464 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3465 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3466 3467 info->drmmode_inited = TRUE; 3468 if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 3469#if HAVE_NOTIFY_FD 3470 SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 3471#else 3472 AddGeneralSocket(pAMDGPUEnt->fd); 3473 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3474 drm_wakeup_handler, drmmode); 3475#endif 3476 pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 3477 pAMDGPUEnt->fd_wakeup_ref = 1; 3478 } else 3479 pAMDGPUEnt->fd_wakeup_ref++; 3480} 3481 3482void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3483{ 3484 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3485 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3486 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3487 int c; 3488 3489 if (!info->drmmode_inited) 3490 return; 3491 3492 for (c = 0; c < config->num_crtc; c++) 3493 drmmode_crtc_scanout_free(config->crtc[c]); 3494 3495 if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 3496 !--pAMDGPUEnt->fd_wakeup_ref) { 3497#if HAVE_NOTIFY_FD 3498 RemoveNotifyFd(pAMDGPUEnt->fd); 3499#else 3500 RemoveGeneralSocket(pAMDGPUEnt->fd); 3501 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3502 drm_wakeup_handler, drmmode); 3503#endif 3504 } 3505} 3506 3507static void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv, 3508 ScrnInfoPtr scrn, int x, int y) 3509{ 3510 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3511 CursorPtr cursor = device_priv->cursor; 3512 Bool sprite_visible = device_priv->sprite_visible; 3513 3514 if (cursor) { 3515 x -= cursor->bits->xhot; 3516 y -= cursor->bits->yhot; 3517 3518 device_priv->sprite_visible = 3519 x < scrn->virtualX && y < scrn->virtualY && 3520 (x + cursor->bits->width > 0) && 3521 (y + cursor->bits->height > 0); 3522 } else { 3523 device_priv->sprite_visible = FALSE; 3524 } 3525 3526 info->sprites_visible += device_priv->sprite_visible - sprite_visible; 3527} 3528 3529static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 3530 CursorPtr pCursor, int x, int y) 3531{ 3532 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3533 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3534 struct amdgpu_device_priv *device_priv = 3535 dixLookupScreenPrivate(&pDev->devPrivates, 3536 &amdgpu_device_private_key, pScreen); 3537 3538 device_priv->cursor = pCursor; 3539 drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 3540 3541 info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 3542} 3543 3544static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 3545 int x, int y) 3546{ 3547 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3548 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3549 struct amdgpu_device_priv *device_priv = 3550 dixLookupScreenPrivate(&pDev->devPrivates, 3551 &amdgpu_device_private_key, pScreen); 3552 3553 drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 3554 3555 info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 3556} 3557 3558static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 3559 ScreenPtr pScreen, 3560 CursorPtr pCursor) 3561{ 3562 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3563 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3564 3565 return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 3566} 3567 3568static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 3569 ScreenPtr pScreen, 3570 CursorPtr pCursor) 3571{ 3572 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3573 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3574 3575 return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 3576} 3577 3578static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 3579 ScreenPtr pScreen) 3580{ 3581 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3582 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3583 3584 return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 3585} 3586 3587static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 3588 ScreenPtr pScreen) 3589{ 3590 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3591 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3592 3593 info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 3594} 3595 3596miPointerSpriteFuncRec drmmode_sprite_funcs = { 3597 .RealizeCursor = drmmode_sprite_realize_realize_cursor, 3598 .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 3599 .SetCursor = drmmode_sprite_set_cursor, 3600 .MoveCursor = drmmode_sprite_move_cursor, 3601 .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 3602 .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 3603}; 3604 3605 3606void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3607{ 3608 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3609 xf86OutputPtr output = config->output[config->compat_output]; 3610 xf86CrtcPtr crtc = output->crtc; 3611 3612 if (crtc && crtc->enabled) { 3613 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 3614 } 3615} 3616 3617Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 3618 Bool set_hw) 3619{ 3620 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3621 unsigned num_desired = 0, num_on = 0; 3622 int c; 3623 3624 /* First, disable all unused CRTCs */ 3625 if (set_hw) { 3626 for (c = 0; c < config->num_crtc; c++) { 3627 xf86CrtcPtr crtc = config->crtc[c]; 3628 3629 /* Skip disabled CRTCs */ 3630 if (crtc->enabled) 3631 continue; 3632 3633 drmmode_crtc_dpms(crtc, DPMSModeOff); 3634 } 3635 } 3636 3637 /* Then, try setting the chosen mode on each CRTC */ 3638 for (c = 0; c < config->num_crtc; c++) { 3639 xf86CrtcPtr crtc = config->crtc[c]; 3640 xf86OutputPtr output = NULL; 3641 int o; 3642 3643 if (!crtc->enabled) 3644 continue; 3645 3646 if (config->output[config->compat_output]->crtc == crtc) 3647 output = config->output[config->compat_output]; 3648 else { 3649 for (o = 0; o < config->num_output; o++) 3650 if (config->output[o]->crtc == crtc) { 3651 output = config->output[o]; 3652 break; 3653 } 3654 } 3655 /* paranoia */ 3656 if (!output) 3657 continue; 3658 3659 num_desired++; 3660 3661 /* Mark that we'll need to re-set the mode for sure */ 3662 memset(&crtc->mode, 0, sizeof(crtc->mode)); 3663 if (!crtc->desiredMode.CrtcHDisplay) { 3664 DisplayModePtr mode = xf86OutputFindClosestMode(output, 3665 pScrn-> 3666 currentMode); 3667 3668 if (!mode) { 3669 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3670 "Failed to find mode for CRTC %d\n", c); 3671 continue; 3672 } 3673 crtc->desiredMode = *mode; 3674 crtc->desiredRotation = RR_Rotate_0; 3675 crtc->desiredX = 0; 3676 crtc->desiredY = 0; 3677 } 3678 3679 if (set_hw) { 3680 if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 3681 crtc->desiredRotation, 3682 crtc->desiredX, 3683 crtc->desiredY)) { 3684 num_on++; 3685 } else { 3686 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3687 "Failed to set mode on CRTC %d\n", c); 3688 RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 3689 crtc->rotation, 0, NULL); 3690 } 3691 } else { 3692 crtc->mode = crtc->desiredMode; 3693 crtc->rotation = crtc->desiredRotation; 3694 crtc->x = crtc->desiredX; 3695 crtc->y = crtc->desiredY; 3696 if (drmmode_handle_transform(crtc)) 3697 num_on++; 3698 } 3699 } 3700 3701 if (num_on == 0 && num_desired > 0) { 3702 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 3703 return FALSE; 3704 } 3705 3706 /* Validate leases on VT re-entry */ 3707 if (dixPrivateKeyRegistered(rrPrivKey)) 3708 drmmode_validate_leases(pScrn); 3709 3710 return TRUE; 3711} 3712 3713Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3714{ 3715 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3716 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3717 int i; 3718 3719 if (xf86_config->num_crtc) { 3720 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3721 "Initializing kms color map\n"); 3722 if (!miCreateDefColormap(pScreen)) 3723 return FALSE; 3724 3725 if (pScrn->depth == 30) { 3726 if (!drmmode_cm_enabled(&info->drmmode)) 3727 return TRUE; 3728 3729 for (i = 0; i < xf86_config->num_crtc; i++) { 3730 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3731 void *gamma; 3732 3733 if (crtc->gamma_size == 1024) 3734 continue; 3735 3736 gamma = malloc(1024 * 3 * sizeof(CARD16)); 3737 if (!gamma) { 3738 ErrorF("Failed to allocate gamma LUT memory\n"); 3739 return FALSE; 3740 } 3741 3742 free(crtc->gamma_red); 3743 crtc->gamma_size = 1024; 3744 crtc->gamma_red = gamma; 3745 crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 3746 crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 3747 } 3748 } 3749 3750 /* All Radeons support 10 bit CLUTs. */ 3751 if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10, 3752 NULL, NULL, CMAP_PALETTED_TRUECOLOR 3753 | CMAP_RELOAD_ON_MODE_SWITCH)) 3754 return FALSE; 3755 3756 for (i = 0; i < xf86_config->num_crtc; i++) { 3757 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3758 3759 drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 3760 crtc->gamma_green, 3761 crtc->gamma_blue, 3762 crtc->gamma_size); 3763 } 3764 } 3765 3766 return TRUE; 3767} 3768 3769static Bool 3770drmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 3771 int *num_hdmi) 3772{ 3773 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3774 int i; 3775 3776 for (i = 0; i < config->num_output; i++) { 3777 xf86OutputPtr output = config->output[i]; 3778 drmmode_output_private_ptr drmmode_output = output->driver_private; 3779 3780 if (drmmode_output->output_id == output_id) { 3781 switch(drmmode_output->mode_output->connector_type) { 3782 case DRM_MODE_CONNECTOR_DVII: 3783 case DRM_MODE_CONNECTOR_DVID: 3784 case DRM_MODE_CONNECTOR_DVIA: 3785 (*num_dvi)++; 3786 break; 3787 case DRM_MODE_CONNECTOR_HDMIA: 3788 case DRM_MODE_CONNECTOR_HDMIB: 3789 (*num_hdmi)++; 3790 break; 3791 } 3792 3793 return TRUE; 3794 } 3795 } 3796 3797 return FALSE; 3798} 3799 3800void 3801amdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3802{ 3803 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3804 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3805 drmModeResPtr mode_res; 3806 int i, j; 3807 Bool found; 3808 Bool changed = FALSE; 3809 int num_dvi = 0, num_hdmi = 0; 3810 3811 /* Try to re-set the mode on all the connectors with a BAD link-state: 3812 * This may happen if a link degrades and a new modeset is necessary, using 3813 * different link-training parameters. If the kernel found that the current 3814 * mode is not achievable anymore, it should have pruned the mode before 3815 * sending the hotplug event. Try to re-set the currently-set mode to keep 3816 * the display alive, this will fail if the mode has been pruned. 3817 * In any case, we will send randr events for the Desktop Environment to 3818 * deal with it, if it wants to. 3819 */ 3820 for (i = 0; i < config->num_output; i++) { 3821 xf86OutputPtr output = config->output[i]; 3822 xf86CrtcPtr crtc = output->crtc; 3823 drmmode_output_private_ptr drmmode_output = output->driver_private; 3824 3825 drmmode_output_detect(output); 3826 3827 if (!crtc || !drmmode_output->mode_output) 3828 continue; 3829 3830 /* Get an updated view of the properties for the current connector and 3831 * look for the link-status property 3832 */ 3833 for (j = 0; j < drmmode_output->num_props; j++) { 3834 drmmode_prop_ptr p = &drmmode_output->props[j]; 3835 3836 if (!strcmp(p->mode_prop->name, "link-status")) { 3837 if (p->value != DRM_MODE_LINK_STATUS_BAD) 3838 break; 3839 3840 /* the connector got a link failure, re-set the current mode */ 3841 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 3842 crtc->x, crtc->y); 3843 3844 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3845 "hotplug event: connector %u's link-state is BAD, " 3846 "tried resetting the current mode. You may be left" 3847 "with a black screen if this fails...\n", 3848 drmmode_output->mode_output->connector_id); 3849 3850 break; 3851 } 3852 } 3853 } 3854 3855 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3856 if (!mode_res) 3857 goto out; 3858 3859restart_destroy: 3860 for (i = 0; i < config->num_output; i++) { 3861 xf86OutputPtr output = config->output[i]; 3862 drmmode_output_private_ptr drmmode_output = output->driver_private; 3863 found = FALSE; 3864 for (j = 0; j < mode_res->count_connectors; j++) { 3865 if (mode_res->connectors[j] == drmmode_output->output_id) { 3866 found = TRUE; 3867 break; 3868 } 3869 } 3870 if (found) 3871 continue; 3872 3873 drmModeFreeConnector(drmmode_output->mode_output); 3874 drmmode_output->mode_output = NULL; 3875 drmmode_output->output_id = -1; 3876 3877 changed = TRUE; 3878 if (drmmode->delete_dp_12_displays) { 3879 RROutputDestroy(output->randr_output); 3880 xf86OutputDestroy(output); 3881 goto restart_destroy; 3882 } 3883 } 3884 3885 /* find new output ids we don't have outputs for */ 3886 for (i = 0; i < mode_res->count_connectors; i++) { 3887 for (j = 0; j < pAMDGPUEnt->num_scrns; j++) { 3888 if (drmmode_find_output(pAMDGPUEnt->scrn[j], 3889 mode_res->connectors[i], 3890 &num_dvi, &num_hdmi)) 3891 break; 3892 } 3893 3894 if (j < pAMDGPUEnt->num_scrns) 3895 continue; 3896 3897 if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 3898 &num_hdmi, 1) != 0) 3899 changed = TRUE; 3900 } 3901 3902 /* Check to see if a lessee has disappeared */ 3903 drmmode_validate_leases(scrn); 3904 3905 if (changed) { 3906#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 3907 RRSetChanged(xf86ScrnToScreen(scrn)); 3908#else 3909 rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 3910 rrScrPriv->changed = TRUE; 3911#endif 3912 RRTellChanged(xf86ScrnToScreen(scrn)); 3913 } 3914 3915 drmModeFreeResources(mode_res); 3916out: 3917 RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 3918} 3919 3920#ifdef HAVE_LIBUDEV 3921static void drmmode_handle_uevents(int fd, void *closure) 3922{ 3923 drmmode_ptr drmmode = closure; 3924 ScrnInfoPtr scrn = drmmode->scrn; 3925 struct udev_device *dev; 3926 Bool received = FALSE; 3927 struct timeval tv = { 0, 0 }; 3928 fd_set readfd; 3929 3930 FD_ZERO(&readfd); 3931 FD_SET(fd, &readfd); 3932 3933 while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 3934 FD_ISSET(fd, &readfd)) { 3935 /* select() ensured that this will not block */ 3936 dev = udev_monitor_receive_device(drmmode->uevent_monitor); 3937 if (dev) { 3938 udev_device_unref(dev); 3939 received = TRUE; 3940 } 3941 } 3942 3943 if (received) 3944 amdgpu_mode_hotplug(scrn, drmmode); 3945} 3946#endif 3947 3948void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3949{ 3950#ifdef HAVE_LIBUDEV 3951 struct udev *u; 3952 struct udev_monitor *mon; 3953 3954 u = udev_new(); 3955 if (!u) 3956 return; 3957 mon = udev_monitor_new_from_netlink(u, "udev"); 3958 if (!mon) { 3959 udev_unref(u); 3960 return; 3961 } 3962 3963 if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3964 "drm", 3965 "drm_minor") < 0 || 3966 udev_monitor_enable_receiving(mon) < 0) { 3967 udev_monitor_unref(mon); 3968 udev_unref(u); 3969 return; 3970 } 3971 3972 drmmode->uevent_handler = 3973 xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3974 drmmode_handle_uevents, drmmode); 3975 3976 drmmode->uevent_monitor = mon; 3977#endif 3978} 3979 3980void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3981{ 3982#ifdef HAVE_LIBUDEV 3983 if (drmmode->uevent_handler) { 3984 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3985 xf86RemoveGeneralHandler(drmmode->uevent_handler); 3986 3987 udev_monitor_unref(drmmode->uevent_monitor); 3988 udev_unref(u); 3989 } 3990#endif 3991} 3992 3993Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 3994 PixmapPtr new_front, uint64_t id, void *data, 3995 xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler, 3996 amdgpu_drm_abort_proc abort, 3997 enum drmmode_flip_sync flip_sync, 3998 uint32_t target_msc) 3999{ 4000 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 4001 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 4002 xf86CrtcPtr crtc = NULL; 4003 drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 4004 int crtc_id; 4005 uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 4006 drmmode_flipdata_ptr flipdata; 4007 Bool handle_deferred = FALSE; 4008 uintptr_t drm_queue_seq = 0; 4009 struct drmmode_fb *fb; 4010 int i = 0; 4011 4012 flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 4013 sizeof(flipdata->fb[0])); 4014 if (!flipdata) { 4015 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4016 "flip queue: data alloc failed.\n"); 4017 goto error; 4018 } 4019 4020 fb = amdgpu_pixmap_get_fb(new_front); 4021 if (!fb) { 4022 ErrorF("Failed to get FB for flip\n"); 4023 goto error; 4024 } 4025 4026 /* 4027 * Queue flips on all enabled CRTCs 4028 * Note that if/when we get per-CRTC buffers, we'll have to update this. 4029 * Right now it assumes a single shared fb across all CRTCs, with the 4030 * kernel fixing up the offset of each CRTC as necessary. 4031 * 4032 * Also, flips queued on disabled or incorrectly configured displays 4033 * may never complete; this is a configuration error. 4034 */ 4035 4036 flipdata->event_data = data; 4037 flipdata->handler = handler; 4038 flipdata->abort = abort; 4039 flipdata->fe_crtc = ref_crtc; 4040 4041 for (i = 0; i < config->num_crtc; i++) { 4042 crtc = config->crtc[i]; 4043 drmmode_crtc = crtc->driver_private; 4044 crtc_id = drmmode_get_crtc_id(crtc); 4045 4046 if (!drmmode_crtc_can_flip(crtc) || 4047 (drmmode_crtc->tear_free && crtc != ref_crtc)) 4048 continue; 4049 4050 flipdata->flip_count++; 4051 4052 drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 4053 flipdata, 4054 drmmode_flip_handler, 4055 drmmode_flip_abort, 4056 TRUE); 4057 if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 4058 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4059 "Allocating DRM queue event entry failed.\n"); 4060 goto error; 4061 } 4062 4063 if (drmmode_crtc->tear_free) { 4064 BoxRec extents = { .x1 = 0, .y1 = 0, 4065 .x2 = new_front->drawable.width, 4066 .y2 = new_front->drawable.height }; 4067 int scanout_id = drmmode_crtc->scanout_id ^ 1; 4068 4069 if (flip_sync == FLIP_ASYNC) { 4070 if (!drmmode_wait_vblank(crtc, 4071 DRM_VBLANK_RELATIVE | 4072 DRM_VBLANK_EVENT, 4073 0, drm_queue_seq, 4074 NULL, NULL)) 4075 goto flip_error; 4076 goto next; 4077 } 4078 4079 drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], 4080 amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 4081 if (!flipdata->fb[crtc_id]) { 4082 ErrorF("Failed to get FB for TearFree flip\n"); 4083 goto error; 4084 } 4085 4086 amdgpu_scanout_do_update(crtc, scanout_id, new_front, 4087 extents); 4088 amdgpu_glamor_flush(crtc->scrn); 4089 4090 if (drmmode_crtc->scanout_update_pending) { 4091 amdgpu_drm_wait_pending_flip(crtc); 4092 handle_deferred = TRUE; 4093 amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 4094 drmmode_crtc->scanout_update_pending = 0; 4095 } 4096 } else { 4097 drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], fb); 4098 } 4099 4100 if (crtc == ref_crtc) { 4101 if (drmmode_page_flip_target_absolute(pAMDGPUEnt, 4102 drmmode_crtc, 4103 flipdata->fb[crtc_id]->handle, 4104 flip_flags, 4105 drm_queue_seq, 4106 target_msc) != 0) 4107 goto flip_error; 4108 } else { 4109 if (drmmode_page_flip_target_relative(pAMDGPUEnt, 4110 drmmode_crtc, 4111 flipdata->fb[crtc_id]->handle, 4112 flip_flags, 4113 drm_queue_seq, 0) != 0) 4114 goto flip_error; 4115 } 4116 4117 if (drmmode_crtc->tear_free) { 4118 drmmode_crtc->scanout_id ^= 1; 4119 drmmode_crtc->ignore_damage = TRUE; 4120 } 4121 4122 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 4123 flipdata->fb[crtc_id]); 4124 4125 next: 4126 drm_queue_seq = 0; 4127 } 4128 4129 if (handle_deferred) 4130 amdgpu_drm_queue_handle_deferred(ref_crtc); 4131 if (flipdata->flip_count > 0) 4132 return TRUE; 4133 4134flip_error: 4135 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 4136 strerror(errno)); 4137 4138error: 4139 if (drm_queue_seq) 4140 amdgpu_drm_abort_entry(drm_queue_seq); 4141 else if (crtc) 4142 drmmode_flip_abort(crtc, flipdata); 4143 else { 4144 abort(NULL, data); 4145 free(flipdata); 4146 } 4147 4148 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 4149 strerror(errno)); 4150 if (handle_deferred) 4151 amdgpu_drm_queue_handle_deferred(ref_crtc); 4152 return FALSE; 4153} 4154