drmmode_display.c revision 852bcc3b
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 void 2146drmmode_output_attach_tile(xf86OutputPtr output) 2147{ 2148#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 2149 drmmode_output_private_ptr drmmode_output = output->driver_private; 2150 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2151 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2152 struct xf86CrtcTileInfo tile_info, *set = NULL; 2153 int i; 2154 2155 if (!koutput) { 2156 xf86OutputSetTile(output, NULL); 2157 return; 2158 } 2159 2160 /* look for a TILE property */ 2161 for (i = 0; i < koutput->count_props; i++) { 2162 drmModePropertyPtr props; 2163 props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]); 2164 if (!props) 2165 continue; 2166 2167 if (!(props->flags & DRM_MODE_PROP_BLOB)) { 2168 drmModeFreeProperty(props); 2169 continue; 2170 } 2171 2172 if (!strcmp(props->name, "TILE")) { 2173 drmModeFreePropertyBlob(drmmode_output->tile_blob); 2174 drmmode_output->tile_blob = 2175 drmModeGetPropertyBlob(pAMDGPUEnt->fd, 2176 koutput->prop_values[i]); 2177 } 2178 drmModeFreeProperty(props); 2179 } 2180 if (drmmode_output->tile_blob) { 2181 if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, 2182 drmmode_output->tile_blob->length, 2183 &tile_info) == TRUE) 2184 set = &tile_info; 2185 } 2186 xf86OutputSetTile(output, set); 2187#endif 2188} 2189 2190static int 2191koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 2192 int type, const char *name) 2193{ 2194 int idx = -1; 2195 2196 for (int i = 0; i < koutput->count_props; i++) { 2197 drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 2198 2199 if (!prop) 2200 continue; 2201 2202 if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 2203 idx = i; 2204 2205 drmModeFreeProperty(prop); 2206 2207 if (idx > -1) 2208 break; 2209 } 2210 2211 return idx; 2212} 2213 2214static int 2215koutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 2216 int type, const char *name) 2217{ 2218 int idx = koutput_get_prop_idx(fd, koutput, type, name); 2219 2220 return (idx > -1) ? koutput->props[idx] : -1; 2221} 2222 2223static drmModePropertyBlobPtr 2224koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 2225{ 2226 drmModePropertyBlobPtr blob = NULL; 2227 int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 2228 2229 if (idx > -1) 2230 blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 2231 2232 return blob; 2233} 2234 2235static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 2236{ 2237 drmmode_output_private_ptr drmmode_output = output->driver_private; 2238 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2239 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2240 int i; 2241 DisplayModePtr Modes = NULL, Mode; 2242 xf86MonPtr mon = NULL; 2243 2244 if (!koutput) 2245 return NULL; 2246 2247 drmModeFreePropertyBlob(drmmode_output->edid_blob); 2248 2249 /* look for an EDID property */ 2250 drmmode_output->edid_blob = 2251 koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID"); 2252 2253 if (drmmode_output->edid_blob) { 2254 mon = xf86InterpretEDID(output->scrn->scrnIndex, 2255 drmmode_output->edid_blob->data); 2256 if (mon && drmmode_output->edid_blob->length > 128) 2257 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 2258 } 2259 xf86OutputSetEDID(output, mon); 2260 2261 drmmode_output_attach_tile(output); 2262 2263 /* modes should already be available */ 2264 for (i = 0; i < koutput->count_modes; i++) { 2265 Mode = xnfalloc(sizeof(DisplayModeRec)); 2266 2267 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 2268 Mode); 2269 Modes = xf86ModesAdd(Modes, Mode); 2270 2271 } 2272 return Modes; 2273} 2274 2275static void drmmode_output_destroy(xf86OutputPtr output) 2276{ 2277 drmmode_output_private_ptr drmmode_output = output->driver_private; 2278 int i; 2279 2280 drmModeFreePropertyBlob(drmmode_output->edid_blob); 2281#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 2282 drmModeFreePropertyBlob(drmmode_output->tile_blob); 2283#endif 2284 2285 for (i = 0; i < drmmode_output->num_props; i++) { 2286 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 2287 free(drmmode_output->props[i].atoms); 2288 } 2289 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 2290 drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 2291 } 2292 free(drmmode_output->mode_encoders); 2293 free(drmmode_output->props); 2294 drmModeFreeConnector(drmmode_output->mode_output); 2295 free(drmmode_output); 2296 output->driver_private = NULL; 2297} 2298 2299static void drmmode_output_dpms(xf86OutputPtr output, int mode) 2300{ 2301 drmmode_output_private_ptr drmmode_output = output->driver_private; 2302 xf86CrtcPtr crtc = output->crtc; 2303 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2304 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2305 2306 if (!koutput) 2307 return; 2308 2309 if (mode != DPMSModeOn && crtc) 2310 drmmode_do_crtc_dpms(crtc, mode); 2311 2312 drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 2313 drmmode_output->dpms_enum_id, mode); 2314 2315 if (mode == DPMSModeOn && crtc) { 2316 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2317 2318 if (drmmode_crtc->need_modeset) 2319 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2320 crtc->x, crtc->y); 2321 else 2322 drmmode_do_crtc_dpms(output->crtc, mode); 2323 } 2324} 2325 2326static Bool drmmode_property_ignore(drmModePropertyPtr prop) 2327{ 2328 if (!prop) 2329 return TRUE; 2330 /* ignore blob prop */ 2331 if (prop->flags & DRM_MODE_PROP_BLOB) 2332 return TRUE; 2333 /* ignore standard property */ 2334 if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 2335 return TRUE; 2336 2337 return FALSE; 2338} 2339 2340static void drmmode_output_create_resources(xf86OutputPtr output) 2341{ 2342 AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); 2343 drmmode_output_private_ptr drmmode_output = output->driver_private; 2344 drmmode_crtc_private_ptr drmmode_crtc; 2345 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 2346 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2347 drmModePropertyPtr drmmode_prop, tearfree_prop; 2348 int i, j, err; 2349 Atom name; 2350 2351 /* Create CONNECTOR_ID property */ 2352 name = MakeAtom("CONNECTOR_ID", 12, TRUE); 2353 if (name != BAD_RESOURCE) { 2354 INT32 value = mode_output->connector_id; 2355 2356 err = RRConfigureOutputProperty(output->randr_output, name, 2357 FALSE, FALSE, TRUE, 1, &value); 2358 if (err != Success) { 2359 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2360 "RRConfigureOutputProperty error, %d\n", err); 2361 } 2362 2363 err = RRChangeOutputProperty(output->randr_output, name, 2364 XA_INTEGER, 32, PropModeReplace, 1, 2365 &value, FALSE, FALSE); 2366 if (err != Success) { 2367 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2368 "RRChangeOutputProperty error, %d\n", err); 2369 } 2370 } 2371 2372 drmmode_output->props = 2373 calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 2374 if (!drmmode_output->props) 2375 return; 2376 2377 drmmode_output->num_props = 0; 2378 for (i = 0, j = 0; i < mode_output->count_props; i++) { 2379 drmmode_prop = 2380 drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 2381 if (drmmode_property_ignore(drmmode_prop)) { 2382 drmModeFreeProperty(drmmode_prop); 2383 continue; 2384 } 2385 drmmode_output->props[j].mode_prop = drmmode_prop; 2386 drmmode_output->props[j].value = mode_output->prop_values[i]; 2387 drmmode_output->num_props++; 2388 j++; 2389 } 2390 2391 /* Userspace-only property for TearFree */ 2392 tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 2393 tearfree_prop->flags = DRM_MODE_PROP_ENUM; 2394 strcpy(tearfree_prop->name, "TearFree"); 2395 tearfree_prop->count_enums = 3; 2396 tearfree_prop->enums = calloc(tearfree_prop->count_enums, 2397 sizeof(*tearfree_prop->enums)); 2398 strcpy(tearfree_prop->enums[0].name, "off"); 2399 strcpy(tearfree_prop->enums[1].name, "on"); 2400 tearfree_prop->enums[1].value = 1; 2401 strcpy(tearfree_prop->enums[2].name, "auto"); 2402 tearfree_prop->enums[2].value = 2; 2403 drmmode_output->props[j].mode_prop = tearfree_prop; 2404 drmmode_output->props[j].value = info->tear_free; 2405 drmmode_output->tear_free = info->tear_free; 2406 drmmode_output->num_props++; 2407 2408 for (i = 0; i < drmmode_output->num_props; i++) { 2409 drmmode_prop_ptr p = &drmmode_output->props[i]; 2410 drmmode_prop = p->mode_prop; 2411 2412 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 2413 INT32 range[2]; 2414 INT32 value = p->value; 2415 2416 p->num_atoms = 1; 2417 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2418 if (!p->atoms) 2419 continue; 2420 p->atoms[0] = 2421 MakeAtom(drmmode_prop->name, 2422 strlen(drmmode_prop->name), TRUE); 2423 range[0] = drmmode_prop->values[0]; 2424 range[1] = drmmode_prop->values[1]; 2425 err = 2426 RRConfigureOutputProperty(output->randr_output, 2427 p->atoms[0], FALSE, TRUE, 2428 drmmode_prop->flags & 2429 DRM_MODE_PROP_IMMUTABLE ? 2430 TRUE : FALSE, 2, range); 2431 if (err != 0) { 2432 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2433 "RRConfigureOutputProperty error, %d\n", 2434 err); 2435 } 2436 err = 2437 RRChangeOutputProperty(output->randr_output, 2438 p->atoms[0], XA_INTEGER, 32, 2439 PropModeReplace, 1, &value, 2440 FALSE, TRUE); 2441 if (err != 0) { 2442 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2443 "RRChangeOutputProperty error, %d\n", 2444 err); 2445 } 2446 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 2447 p->num_atoms = drmmode_prop->count_enums + 1; 2448 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2449 if (!p->atoms) 2450 continue; 2451 p->atoms[0] = 2452 MakeAtom(drmmode_prop->name, 2453 strlen(drmmode_prop->name), TRUE); 2454 for (j = 1; j <= drmmode_prop->count_enums; j++) { 2455 struct drm_mode_property_enum *e = 2456 &drmmode_prop->enums[j - 1]; 2457 p->atoms[j] = 2458 MakeAtom(e->name, strlen(e->name), TRUE); 2459 } 2460 err = 2461 RRConfigureOutputProperty(output->randr_output, 2462 p->atoms[0], FALSE, FALSE, 2463 drmmode_prop->flags & 2464 DRM_MODE_PROP_IMMUTABLE ? 2465 TRUE : FALSE, 2466 p->num_atoms - 1, 2467 (INT32 *) & p->atoms[1]); 2468 if (err != 0) { 2469 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2470 "RRConfigureOutputProperty error, %d\n", 2471 err); 2472 } 2473 for (j = 0; j < drmmode_prop->count_enums; j++) 2474 if (drmmode_prop->enums[j].value == p->value) 2475 break; 2476 /* there's always a matching value */ 2477 err = 2478 RRChangeOutputProperty(output->randr_output, 2479 p->atoms[0], XA_ATOM, 32, 2480 PropModeReplace, 1, 2481 &p->atoms[j + 1], FALSE, 2482 TRUE); 2483 if (err != 0) { 2484 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2485 "RRChangeOutputProperty error, %d\n", 2486 err); 2487 } 2488 } 2489 } 2490 2491 /* Do not configure cm properties on output if there's no support. */ 2492 if (!drmmode_cm_enabled(drmmode_output->drmmode)) 2493 return; 2494 2495 drmmode_crtc = output->crtc ? output->crtc->driver_private : NULL; 2496 2497 for (i = 0; i < CM_NUM_PROPS; i++) 2498 rr_configure_and_change_cm_property(output, drmmode_crtc, i); 2499} 2500 2501static void 2502drmmode_output_set_tear_free(AMDGPUEntPtr pAMDGPUEnt, 2503 drmmode_output_private_ptr drmmode_output, 2504 xf86CrtcPtr crtc, int tear_free) 2505{ 2506 if (drmmode_output->tear_free == tear_free) 2507 return; 2508 2509 drmmode_output->tear_free = tear_free; 2510 2511 if (crtc) { 2512 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2513 crtc->x, crtc->y); 2514 } 2515} 2516 2517static Bool 2518drmmode_output_set_property(xf86OutputPtr output, Atom property, 2519 RRPropertyValuePtr value) 2520{ 2521 drmmode_output_private_ptr drmmode_output = output->driver_private; 2522 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2523 enum drmmode_cm_prop cm_prop_index; 2524 int i; 2525 2526 cm_prop_index = get_cm_enum_from_str(NameForAtom(property)); 2527 if (cm_prop_index >= 0 && cm_prop_index < CM_DEGAMMA_LUT_SIZE) { 2528 if (!output->crtc) 2529 return FALSE; 2530 if (drmmode_crtc_stage_cm_prop(output->crtc, cm_prop_index, 2531 value)) 2532 return FALSE; 2533 if (drmmode_crtc_push_cm_prop(output->crtc, cm_prop_index)) 2534 return FALSE; 2535 return TRUE; 2536 } 2537 2538 for (i = 0; i < drmmode_output->num_props; i++) { 2539 drmmode_prop_ptr p = &drmmode_output->props[i]; 2540 2541 if (p->atoms[0] != property) 2542 continue; 2543 2544 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 2545 uint32_t val; 2546 2547 if (value->type != XA_INTEGER || value->format != 32 || 2548 value->size != 1) 2549 return FALSE; 2550 val = *(uint32_t *) value->data; 2551 2552 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2553 drmmode_output->output_id, 2554 p->mode_prop->prop_id, 2555 (uint64_t) val); 2556 return TRUE; 2557 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2558 Atom atom; 2559 const char *name; 2560 int j; 2561 2562 if (value->type != XA_ATOM || value->format != 32 2563 || value->size != 1) 2564 return FALSE; 2565 memcpy(&atom, value->data, 4); 2566 if (!(name = NameForAtom(atom))) 2567 return FALSE; 2568 2569 /* search for matching name string, then set its value down */ 2570 for (j = 0; j < p->mode_prop->count_enums; j++) { 2571 if (!strcmp(p->mode_prop->enums[j].name, name)) { 2572 if (i == (drmmode_output->num_props - 1)) { 2573 drmmode_output_set_tear_free(pAMDGPUEnt, 2574 drmmode_output, 2575 output->crtc, j); 2576 } else { 2577 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2578 drmmode_output->output_id, 2579 p->mode_prop->prop_id, 2580 p->mode_prop->enums[j].value); 2581 } 2582 2583 return TRUE; 2584 } 2585 } 2586 } 2587 } 2588 2589 return TRUE; 2590} 2591 2592static Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 2593{ 2594 drmmode_crtc_private_ptr drmmode_crtc; 2595 enum drmmode_cm_prop cm_prop_id; 2596 int ret; 2597 2598 /* First, see if it's a cm property */ 2599 cm_prop_id = get_cm_enum_from_str(NameForAtom(property)); 2600 if (output->crtc && cm_prop_id != CM_INVALID_PROP) { 2601 drmmode_crtc = output->crtc->driver_private; 2602 2603 ret = rr_configure_and_change_cm_property(output, drmmode_crtc, 2604 cm_prop_id); 2605 if (ret) { 2606 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2607 "Error getting color property: %d\n", 2608 ret); 2609 return FALSE; 2610 } 2611 return TRUE; 2612 } 2613 2614 /* Otherwise, must be an output property. */ 2615 return TRUE; 2616} 2617 2618static const xf86OutputFuncsRec drmmode_output_funcs = { 2619 .dpms = drmmode_output_dpms, 2620 .create_resources = drmmode_output_create_resources, 2621 .set_property = drmmode_output_set_property, 2622 .get_property = drmmode_output_get_property, 2623 .detect = drmmode_output_detect, 2624 .mode_valid = drmmode_output_mode_valid, 2625 2626 .get_modes = drmmode_output_get_modes, 2627 .destroy = drmmode_output_destroy 2628}; 2629 2630static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2631 SubPixelHorizontalRGB, 2632 SubPixelHorizontalBGR, 2633 SubPixelVerticalRGB, 2634 SubPixelVerticalBGR, 2635 SubPixelNone 2636}; 2637 2638const char *output_names[] = { "None", 2639 "VGA", 2640 "DVI-I", 2641 "DVI-D", 2642 "DVI-A", 2643 "Composite", 2644 "S-video", 2645 "LVDS", 2646 "CTV", 2647 "DIN", 2648 "DisplayPort", 2649 "HDMI-A", 2650 "HDMI-B", 2651 "TV", 2652 "eDP", 2653 "Virtual", 2654 "DSI", 2655}; 2656 2657#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 2658 2659static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 2660{ 2661 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2662 int i; 2663 for (i = 0; i < xf86_config->num_output; i++) { 2664 xf86OutputPtr output = xf86_config->output[i]; 2665 drmmode_output_private_ptr drmmode_output; 2666 drmmode_output = output->driver_private; 2667 if (drmmode_output->output_id == id) 2668 return output; 2669 } 2670 return NULL; 2671} 2672 2673static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 2674{ 2675 char *conn; 2676 char conn_id[5]; 2677 int id, len; 2678 char *blob_data; 2679 2680 if (!path_blob) 2681 return -1; 2682 2683 blob_data = path_blob->data; 2684 /* we only handle MST paths for now */ 2685 if (strncmp(blob_data, "mst:", 4)) 2686 return -1; 2687 2688 conn = strchr(blob_data + 4, '-'); 2689 if (!conn) 2690 return -1; 2691 len = conn - (blob_data + 4); 2692 if (len + 1 > 5) 2693 return -1; 2694 memcpy(conn_id, blob_data + 4, len); 2695 conn_id[len] = '\0'; 2696 id = strtoul(conn_id, NULL, 10); 2697 2698 *conn_base_id = id; 2699 2700 *path = conn + 1; 2701 return 0; 2702} 2703 2704static void 2705drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 2706 drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 2707{ 2708 xf86OutputPtr output; 2709 int conn_id; 2710 char *extra_path; 2711 2712 output = NULL; 2713 if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 2714 output = find_output(pScrn, conn_id); 2715 if (output) { 2716 snprintf(name, 32, "%s-%s", output->name, extra_path); 2717 } else { 2718 if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 2719 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 2720 } else if (pScrn->is_gpu) { 2721 snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 2722 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 2723 } else { 2724 /* need to do smart conversion here for compat with non-kms ATI driver */ 2725 if (koutput->connector_type_id == 1) { 2726 switch(koutput->connector_type) { 2727 case DRM_MODE_CONNECTOR_DVII: 2728 case DRM_MODE_CONNECTOR_DVID: 2729 case DRM_MODE_CONNECTOR_DVIA: 2730 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 2731 (*num_dvi)++; 2732 break; 2733 case DRM_MODE_CONNECTOR_HDMIA: 2734 case DRM_MODE_CONNECTOR_HDMIB: 2735 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 2736 (*num_hdmi)++; 2737 break; 2738 case DRM_MODE_CONNECTOR_VGA: 2739 case DRM_MODE_CONNECTOR_DisplayPort: 2740 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2741 break; 2742 default: 2743 snprintf(name, 32, "%s", output_names[koutput->connector_type]); 2744 break; 2745 } 2746 } else { 2747 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2748 } 2749 } 2750 } 2751} 2752 2753 2754static unsigned int 2755drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 2756{ 2757 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2758 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2759 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2760 xf86OutputPtr output; 2761 drmModeConnectorPtr koutput; 2762 drmModeEncoderPtr *kencoders = NULL; 2763 drmmode_output_private_ptr drmmode_output; 2764 drmModePropertyBlobPtr path_blob = NULL; 2765#if XF86_CRTC_VERSION >= 8 2766 Bool nonDesktop = FALSE; 2767#endif 2768 char name[32]; 2769 int i; 2770 const char *s; 2771 2772 koutput = 2773 drmModeGetConnector(pAMDGPUEnt->fd, 2774 mode_res->connectors[num]); 2775 if (!koutput) 2776 return 0; 2777 2778 path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH"); 2779 2780#if XF86_CRTC_VERSION >= 8 2781 i = koutput_get_prop_idx(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_RANGE, 2782 "non-desktop"); 2783 if (i >= 0) 2784 nonDesktop = koutput->prop_values[i] != 0; 2785#endif 2786 2787 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2788 if (!kencoders) { 2789 goto out_free_encoders; 2790 } 2791 2792 for (i = 0; i < koutput->count_encoders; i++) { 2793 kencoders[i] = 2794 drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 2795 if (!kencoders[i]) { 2796 goto out_free_encoders; 2797 } 2798 } 2799 2800 drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 2801 if (path_blob) { 2802 drmModeFreePropertyBlob(path_blob); 2803 } 2804 2805 if (path_blob && dynamic) { 2806 /* See if we have an output with this name already 2807 * and hook stuff up. 2808 */ 2809 for (i = 0; i < xf86_config->num_output; i++) { 2810 output = xf86_config->output[i]; 2811 2812 if (strncmp(output->name, name, 32)) 2813 continue; 2814 2815 drmmode_output = output->driver_private; 2816 drmmode_output->output_id = mode_res->connectors[num]; 2817 drmmode_output->mode_output = koutput; 2818#if XF86_CRTC_VERSION >= 8 2819 output->non_desktop = nonDesktop; 2820#endif 2821 for (i = 0; i < koutput->count_encoders; i++) { 2822 drmModeFreeEncoder(kencoders[i]); 2823 } 2824 free(kencoders); 2825 return 1; 2826 } 2827 } 2828 2829 if (xf86IsEntityShared(pScrn->entityList[0])) { 2830 if ((s = 2831 xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2832 if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 2833 goto out_free_encoders; 2834 } else { 2835 if (info->instance_id != num) 2836 goto out_free_encoders; 2837 } 2838 } 2839 2840 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 2841 if (!output) { 2842 goto out_free_encoders; 2843 } 2844 2845 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2846 if (!drmmode_output) { 2847 xf86OutputDestroy(output); 2848 goto out_free_encoders; 2849 } 2850 2851 drmmode_output->output_id = mode_res->connectors[num]; 2852 drmmode_output->mode_output = koutput; 2853 drmmode_output->mode_encoders = kencoders; 2854 drmmode_output->drmmode = drmmode; 2855 output->mm_width = koutput->mmWidth; 2856 output->mm_height = koutput->mmHeight; 2857 2858 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2859 output->interlaceAllowed = TRUE; 2860 output->doubleScanAllowed = TRUE; 2861 output->driver_private = drmmode_output; 2862#if XF86_CRTC_VERSION >= 8 2863 output->non_desktop = nonDesktop; 2864#endif 2865 2866 output->possible_crtcs = 0xffffffff; 2867 for (i = 0; i < koutput->count_encoders; i++) { 2868 output->possible_crtcs &= kencoders[i]->possible_crtcs; 2869 } 2870 /* work out the possible clones later */ 2871 output->possible_clones = 0; 2872 2873 drmmode_output->dpms_enum_id = 2874 koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM, 2875 "DPMS"); 2876 2877 if (dynamic) { 2878 output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 2879 drmmode_output_create_resources(output); 2880 } 2881 2882 return 1; 2883out_free_encoders: 2884 if (kencoders) { 2885 for (i = 0; i < koutput->count_encoders; i++) 2886 drmModeFreeEncoder(kencoders[i]); 2887 free(kencoders); 2888 } 2889 drmModeFreeConnector(koutput); 2890 return 0; 2891} 2892 2893uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2894{ 2895 drmmode_output_private_ptr drmmode_output = 2896 output->driver_private, clone_drmout; 2897 int i; 2898 xf86OutputPtr clone_output; 2899 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2900 int index_mask = 0; 2901 2902 if (drmmode_output->enc_clone_mask == 0) 2903 return index_mask; 2904 2905 for (i = 0; i < xf86_config->num_output; i++) { 2906 clone_output = xf86_config->output[i]; 2907 clone_drmout = clone_output->driver_private; 2908 if (output == clone_output) 2909 continue; 2910 2911 if (clone_drmout->enc_mask == 0) 2912 continue; 2913 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2914 index_mask |= (1 << i); 2915 } 2916 return index_mask; 2917} 2918 2919static void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2920{ 2921 int i, j; 2922 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2923 2924 for (i = 0; i < xf86_config->num_output; i++) { 2925 xf86OutputPtr output = xf86_config->output[i]; 2926 drmmode_output_private_ptr drmmode_output; 2927 2928 drmmode_output = output->driver_private; 2929 drmmode_output->enc_clone_mask = 0xff; 2930 /* and all the possible encoder clones for this output together */ 2931 for (j = 0; j < drmmode_output->mode_output->count_encoders; 2932 j++) { 2933 int k; 2934 for (k = 0; k < mode_res->count_encoders; k++) { 2935 if (mode_res->encoders[k] == 2936 drmmode_output-> 2937 mode_encoders[j]->encoder_id) 2938 drmmode_output->enc_mask |= (1 << k); 2939 } 2940 2941 drmmode_output->enc_clone_mask &= 2942 drmmode_output->mode_encoders[j]->possible_clones; 2943 } 2944 } 2945 2946 for (i = 0; i < xf86_config->num_output; i++) { 2947 xf86OutputPtr output = xf86_config->output[i]; 2948 output->possible_clones = find_clones(scrn, output); 2949 } 2950} 2951 2952/* returns pitch alignment in pixels */ 2953int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 2954{ 2955 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2956 2957 if (info->have_tiling_info) 2958 /* linear aligned requirements */ 2959 return MAX(64, info->group_bytes / bpe); 2960 else 2961 /* default to 512 elements if we don't know the real 2962 * group size otherwise the kernel may reject the CS 2963 * if the group sizes don't match as the pitch won't 2964 * be aligned properly. 2965 */ 2966 return 512; 2967} 2968 2969static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 2970{ 2971 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2972 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2973 struct amdgpu_buffer *old_front = NULL; 2974 ScreenPtr screen = xf86ScrnToScreen(scrn); 2975 int i, pitch, old_width, old_height, old_pitch; 2976 int cpp = info->pixel_bytes; 2977 PixmapPtr ppix = screen->GetScreenPixmap(screen); 2978 void *fb_shadow; 2979 int hint = 0; 2980 2981 if (scrn->virtualX == width && scrn->virtualY == height) 2982 return TRUE; 2983 2984 if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 2985 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2986 "Xorg tried resizing screen to %dx%d, but maximum " 2987 "supported is %dx%d\n", width, height, 2988 xf86_config->maxWidth, xf86_config->maxHeight); 2989 return FALSE; 2990 } 2991 2992 if (info->shadow_primary) 2993 hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2994 else if (!info->use_glamor) 2995 hint = AMDGPU_CREATE_PIXMAP_LINEAR; 2996 2997 xf86DrvMsg(scrn->scrnIndex, X_INFO, 2998 "Allocate new frame buffer %dx%d\n", width, height); 2999 3000 old_width = scrn->virtualX; 3001 old_height = scrn->virtualY; 3002 old_pitch = scrn->displayWidth; 3003 old_front = info->front_buffer; 3004 3005 scrn->virtualX = width; 3006 scrn->virtualY = height; 3007 3008 info->front_buffer = 3009 amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 3010 scrn->depth, hint, scrn->bitsPerPixel, 3011 &pitch); 3012 if (!info->front_buffer) { 3013 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 3014 "Failed to allocate front buffer memory\n"); 3015 goto fail; 3016 } 3017 3018 if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 3019 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 3020 "Failed to map front buffer memory\n"); 3021 goto fail; 3022 } 3023 3024 xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 3025 scrn->displayWidth = pitch / cpp; 3026 3027 if (info->use_glamor || 3028 (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 3029 screen->ModifyPixmapHeader(ppix, 3030 width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 3031 } else { 3032 fb_shadow = calloc(1, pitch * scrn->virtualY); 3033 if (!fb_shadow) 3034 goto fail; 3035 free(info->fb_shadow); 3036 info->fb_shadow = fb_shadow; 3037 screen->ModifyPixmapHeader(ppix, 3038 width, height, -1, -1, pitch, 3039 info->fb_shadow); 3040 } 3041 3042 if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 3043 goto fail; 3044 3045 if (info->use_glamor || info->dri2.enabled) { 3046 if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 3047 goto fail; 3048 } 3049 3050 amdgpu_pixmap_clear(ppix); 3051 amdgpu_glamor_finish(scrn); 3052 3053 for (i = 0; i < xf86_config->num_crtc; i++) { 3054 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3055 3056 if (!crtc->enabled) 3057 continue; 3058 3059 drmmode_set_mode_major(crtc, &crtc->mode, 3060 crtc->rotation, crtc->x, crtc->y); 3061 } 3062 3063 if (old_front) { 3064 amdgpu_bo_unref(&old_front); 3065 } 3066 3067 return TRUE; 3068 3069fail: 3070 if (info->front_buffer) { 3071 amdgpu_bo_unref(&info->front_buffer); 3072 } 3073 info->front_buffer = old_front; 3074 scrn->virtualX = old_width; 3075 scrn->virtualY = old_height; 3076 scrn->displayWidth = old_pitch; 3077 3078 return FALSE; 3079} 3080 3081static void 3082drmmode_validate_leases(ScrnInfoPtr scrn) 3083{ 3084#ifdef XF86_LEASE_VERSION 3085 ScreenPtr screen = scrn->pScreen; 3086 rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 3087 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3088 drmModeLesseeListPtr lessees; 3089 RRLeasePtr lease, next; 3090 int l; 3091 3092 /* We can't talk to the kernel about leases when VT switched */ 3093 if (!scrn->vtSema) 3094 return; 3095 3096 lessees = drmModeListLessees(pAMDGPUEnt->fd); 3097 if (!lessees) 3098 return; 3099 3100 xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 3101 drmmode_lease_private_ptr lease_private = lease->devPrivate; 3102 3103 for (l = 0; l < lessees->count; l++) { 3104 if (lessees->lessees[l] == lease_private->lessee_id) 3105 break; 3106 } 3107 3108 /* check to see if the lease has gone away */ 3109 if (l == lessees->count) { 3110 free(lease_private); 3111 lease->devPrivate = NULL; 3112 xf86CrtcLeaseTerminated(lease); 3113 } 3114 } 3115 3116 free(lessees); 3117#endif 3118} 3119 3120#ifdef XF86_LEASE_VERSION 3121 3122static int 3123drmmode_create_lease(RRLeasePtr lease, int *fd) 3124{ 3125 ScreenPtr screen = lease->screen; 3126 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3127 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3128 drmmode_lease_private_ptr lease_private; 3129 int noutput = lease->numOutputs; 3130 int ncrtc = lease->numCrtcs; 3131 uint32_t *objects; 3132 size_t nobjects; 3133 int lease_fd; 3134 int c, o; 3135 int i; 3136 3137 nobjects = ncrtc + noutput; 3138 if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 3139 ncrtc > (SIZE_MAX - noutput)) 3140 return BadValue; 3141 3142 lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 3143 if (!lease_private) 3144 return BadAlloc; 3145 3146 objects = malloc(nobjects * 4); 3147 if (!objects) { 3148 free(lease_private); 3149 return BadAlloc; 3150 } 3151 3152 i = 0; 3153 3154 /* Add CRTC ids */ 3155 for (c = 0; c < ncrtc; c++) { 3156 xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 3157 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3158 3159 objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 3160 } 3161 3162 /* Add connector ids */ 3163 for (o = 0; o < noutput; o++) { 3164 xf86OutputPtr output = lease->outputs[o]->devPrivate; 3165 drmmode_output_private_ptr drmmode_output = output->driver_private; 3166 3167 objects[i++] = drmmode_output->mode_output->connector_id; 3168 } 3169 3170 /* call kernel to create lease */ 3171 assert (i == nobjects); 3172 3173 lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, 3174 &lease_private->lessee_id); 3175 3176 free(objects); 3177 3178 if (lease_fd < 0) { 3179 free(lease_private); 3180 return BadMatch; 3181 } 3182 3183 lease->devPrivate = lease_private; 3184 3185 xf86CrtcLeaseStarted(lease); 3186 3187 *fd = lease_fd; 3188 return Success; 3189} 3190 3191static void 3192drmmode_terminate_lease(RRLeasePtr lease) 3193{ 3194 drmmode_lease_private_ptr lease_private = lease->devPrivate; 3195 ScreenPtr screen = lease->screen; 3196 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3197 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3198 3199 if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) { 3200 free(lease_private); 3201 lease->devPrivate = NULL; 3202 xf86CrtcLeaseTerminated(lease); 3203 } 3204} 3205 3206#endif // XF86_LEASE_VERSION 3207 3208static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 3209 .resize = drmmode_xf86crtc_resize, 3210#ifdef XF86_LEASE_VERSION 3211 .create_lease = drmmode_create_lease, 3212 .terminate_lease = drmmode_terminate_lease 3213#endif 3214}; 3215 3216static void 3217drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 3218{ 3219 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3220 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3221 drmmode_flipdata_ptr flipdata = event_data; 3222 int crtc_id = drmmode_get_crtc_id(crtc); 3223 struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3224 3225 if (drmmode_crtc->flip_pending == *fb) { 3226 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 3227 NULL); 3228 } 3229 drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3230 3231 if (--flipdata->flip_count == 0) { 3232 if (!flipdata->fe_crtc) 3233 flipdata->fe_crtc = crtc; 3234 flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 3235 free(flipdata); 3236 } 3237} 3238 3239static void 3240drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 3241{ 3242 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3243 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3244 drmmode_flipdata_ptr flipdata = event_data; 3245 int crtc_id = drmmode_get_crtc_id(crtc); 3246 struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3247 3248 /* Is this the event whose info shall be delivered to higher level? */ 3249 if (crtc == flipdata->fe_crtc) { 3250 /* Yes: Cache msc, ust for later delivery. */ 3251 flipdata->fe_frame = frame; 3252 flipdata->fe_usec = usec; 3253 } 3254 3255 if (*fb) { 3256 if (drmmode_crtc->flip_pending == *fb) { 3257 drmmode_fb_reference(pAMDGPUEnt->fd, 3258 &drmmode_crtc->flip_pending, NULL); 3259 } 3260 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb); 3261 drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3262 } 3263 3264 if (--flipdata->flip_count == 0) { 3265 /* Deliver MSC & UST from reference/current CRTC to flip event 3266 * handler 3267 */ 3268 if (flipdata->fe_crtc) 3269 flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 3270 flipdata->fe_usec, flipdata->event_data); 3271 else 3272 flipdata->handler(crtc, frame, usec, flipdata->event_data); 3273 3274 free(flipdata); 3275 } 3276} 3277 3278#if HAVE_NOTIFY_FD 3279static void drmmode_notify_fd(int fd, int notify, void *data) 3280{ 3281 drmmode_ptr drmmode = data; 3282 amdgpu_drm_handle_event(fd, &drmmode->event_context); 3283} 3284#else 3285static void drm_wakeup_handler(pointer data, int err, pointer p) 3286{ 3287 drmmode_ptr drmmode = data; 3288 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 3289 fd_set *read_mask = p; 3290 3291 if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 3292 amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context); 3293 } 3294} 3295#endif 3296 3297static Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) 3298{ 3299 uint64_t cap_value; 3300 3301 return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 3302 &cap_value) == 0 && cap_value != 0; 3303} 3304 3305static int 3306drmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, 3307 int fb_id, uint32_t flags, uintptr_t drm_queue_seq) 3308{ 3309 flags |= DRM_MODE_PAGE_FLIP_EVENT; 3310 return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 3311 fb_id, flags, (void*)drm_queue_seq); 3312} 3313 3314int 3315drmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, 3316 drmmode_crtc_private_ptr drmmode_crtc, 3317 int fb_id, uint32_t flags, 3318 uintptr_t drm_queue_seq, uint32_t target_msc) 3319{ 3320 if (pAMDGPUEnt->has_page_flip_target) { 3321 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 3322 return drmModePageFlipTarget(pAMDGPUEnt->fd, 3323 drmmode_crtc->mode_crtc->crtc_id, 3324 fb_id, flags, (void*)drm_queue_seq, 3325 target_msc); 3326 } 3327 3328 return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 3329 drm_queue_seq); 3330} 3331 3332int 3333drmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, 3334 drmmode_crtc_private_ptr drmmode_crtc, 3335 int fb_id, uint32_t flags, 3336 uintptr_t drm_queue_seq, uint32_t target_msc) 3337{ 3338 if (pAMDGPUEnt->has_page_flip_target) { 3339 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 3340 return drmModePageFlipTarget(pAMDGPUEnt->fd, 3341 drmmode_crtc->mode_crtc->crtc_id, 3342 fb_id, flags, (void*)drm_queue_seq, 3343 target_msc); 3344 } 3345 3346 return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 3347 drm_queue_seq); 3348} 3349 3350/** 3351 * Initialize DDX color management support. It does two things: 3352 * 3353 * 1. Cache DRM color management property type IDs, as they do not change. They 3354 * will be used later to modify color management via DRM, or to determine if 3355 * there's kernel support for color management. 3356 * 3357 * 2. Cache degamma/gamma LUT sizes, since all CRTCs have the same LUT sizes on 3358 * AMD hardware. 3359 * 3360 * If the cached ID's are all 0 after calling this function, then color 3361 * management is not supported. For short, checking if the gamma LUT size 3362 * property ID == 0 is sufficient. 3363 * 3364 * This should be called before CRTCs are initialized within pre_init, as the 3365 * cached values will be used there. 3366 * 3367 * @drm_fd: DRM file descriptor 3368 * @drmmode: drmmode object, where the cached IDs are stored 3369 * @mode_res: The DRM mode resource containing the CRTC ids 3370 */ 3371static void drmmode_cm_init(int drm_fd, drmmode_ptr drmmode, 3372 drmModeResPtr mode_res) 3373{ 3374 drmModeObjectPropertiesPtr drm_props; 3375 drmModePropertyPtr drm_prop; 3376 enum drmmode_cm_prop cm_prop; 3377 uint32_t cm_enabled = 0; 3378 uint32_t cm_all_enabled = (1 << CM_NUM_PROPS) - 1; 3379 int i; 3380 3381 memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 3382 drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 3383 3384 if (!mode_res->crtcs) 3385 return; 3386 3387 /* AMD hardware has color management support on all pipes. It is 3388 * therefore sufficient to only check the first CRTC. 3389 */ 3390 drm_props = drmModeObjectGetProperties(drm_fd, 3391 mode_res->crtcs[0], 3392 DRM_MODE_OBJECT_CRTC); 3393 if (!drm_props) 3394 return; 3395 3396 for (i = 0; i < drm_props->count_props; i++) { 3397 drm_prop = drmModeGetProperty(drm_fd, 3398 drm_props->props[i]); 3399 if (!drm_prop) 3400 continue; 3401 3402 cm_prop = get_cm_enum_from_str(drm_prop->name); 3403 if (cm_prop == CM_INVALID_PROP) 3404 continue; 3405 3406 if (cm_prop == CM_DEGAMMA_LUT_SIZE) 3407 drmmode->degamma_lut_size = drm_props->prop_values[i]; 3408 else if (cm_prop == CM_GAMMA_LUT_SIZE) 3409 drmmode->gamma_lut_size = drm_props->prop_values[i]; 3410 3411 drmmode->cm_prop_ids[cm_prop] = drm_props->props[i]; 3412 cm_enabled |= 1 << cm_prop; 3413 3414 drmModeFreeProperty(drm_prop); 3415 } 3416 drmModeFreeObjectProperties(drm_props); 3417 3418 /* cm is enabled only if all prop ids are found */ 3419 if (cm_enabled == cm_all_enabled) 3420 return; 3421 3422 /* Otherwise, disable DDX cm support */ 3423 memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 3424 drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 3425} 3426 3427Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 3428{ 3429 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3430 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3431 int i, num_dvi = 0, num_hdmi = 0; 3432 unsigned int crtcs_needed = 0; 3433 unsigned int crtcs_got = 0; 3434 drmModeResPtr mode_res; 3435 char *bus_id_string, *provider_name; 3436 3437 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 3438 3439 drmmode->scrn = pScrn; 3440 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3441 if (!mode_res) 3442 return FALSE; 3443 3444 drmmode->count_crtcs = mode_res->count_crtcs; 3445 xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 3446 mode_res->max_height); 3447 3448 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3449 "Initializing outputs ...\n"); 3450 for (i = 0; i < mode_res->count_connectors; i++) 3451 crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 3452 3453 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3454 "%d crtcs needed for screen.\n", crtcs_needed); 3455 3456 /* Need per-screen drmmode_crtc_funcs, based on our global template, 3457 * so we can disable some functions, depending on screen settings. 3458 */ 3459 info->drmmode_crtc_funcs = drmmode_crtc_funcs; 3460 3461 if (!info->use_glamor) { 3462 /* Rotation requires hardware acceleration */ 3463 info->drmmode_crtc_funcs.shadow_allocate = NULL; 3464 info->drmmode_crtc_funcs.shadow_create = NULL; 3465 info->drmmode_crtc_funcs.shadow_destroy = NULL; 3466 } 3467 3468 drmmode_cm_init(pAMDGPUEnt->fd, drmmode, mode_res); 3469 3470 /* Spare the server the effort to compute and update unused CLUTs. */ 3471 if (pScrn->depth == 30 && !drmmode_cm_enabled(drmmode)) 3472 info->drmmode_crtc_funcs.gamma_set = NULL; 3473 3474 for (i = 0; i < mode_res->count_crtcs; i++) { 3475 if (!xf86IsEntityShared(pScrn->entityList[0]) || 3476 (crtcs_got < crtcs_needed && 3477 !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 3478 crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 3479 } 3480 3481 /* All ZaphodHeads outputs provided with matching crtcs? */ 3482 if (crtcs_got < crtcs_needed) { 3483 if (crtcs_got == 0) { 3484 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 3485 "No ZaphodHeads CRTC available, needed %u\n", 3486 crtcs_needed); 3487 return FALSE; 3488 } 3489 3490 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3491 "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 3492 crtcs_needed); 3493 } 3494 3495 /* workout clones */ 3496 drmmode_clones_init(pScrn, drmmode, mode_res); 3497 3498 bus_id_string = DRICreatePCIBusID(info->PciInfo); 3499 XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 3500 free(bus_id_string); 3501 xf86ProviderSetup(pScrn, NULL, provider_name); 3502 free(provider_name); 3503 3504 xf86InitialConfiguration(pScrn, TRUE); 3505 3506 pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); 3507 3508 drmModeFreeResources(mode_res); 3509 return TRUE; 3510} 3511 3512void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3513{ 3514 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3515 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3516 3517 info->drmmode_inited = TRUE; 3518 if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 3519#if HAVE_NOTIFY_FD 3520 SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 3521#else 3522 AddGeneralSocket(pAMDGPUEnt->fd); 3523 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3524 drm_wakeup_handler, drmmode); 3525#endif 3526 pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 3527 pAMDGPUEnt->fd_wakeup_ref = 1; 3528 } else 3529 pAMDGPUEnt->fd_wakeup_ref++; 3530} 3531 3532void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3533{ 3534 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3535 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3536 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3537 int c; 3538 3539 if (!info->drmmode_inited) 3540 return; 3541 3542 for (c = 0; c < config->num_crtc; c++) 3543 drmmode_crtc_scanout_free(config->crtc[c]); 3544 3545 if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 3546 !--pAMDGPUEnt->fd_wakeup_ref) { 3547#if HAVE_NOTIFY_FD 3548 RemoveNotifyFd(pAMDGPUEnt->fd); 3549#else 3550 RemoveGeneralSocket(pAMDGPUEnt->fd); 3551 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3552 drm_wakeup_handler, drmmode); 3553#endif 3554 } 3555} 3556 3557static void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv, 3558 ScrnInfoPtr scrn, int x, int y) 3559{ 3560 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3561 CursorPtr cursor = device_priv->cursor; 3562 Bool sprite_visible = device_priv->sprite_visible; 3563 3564 if (cursor) { 3565 x -= cursor->bits->xhot; 3566 y -= cursor->bits->yhot; 3567 3568 device_priv->sprite_visible = 3569 x < scrn->virtualX && y < scrn->virtualY && 3570 (x + cursor->bits->width > 0) && 3571 (y + cursor->bits->height > 0); 3572 } else { 3573 device_priv->sprite_visible = FALSE; 3574 } 3575 3576 info->sprites_visible += device_priv->sprite_visible - sprite_visible; 3577} 3578 3579static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 3580 CursorPtr pCursor, int x, int y) 3581{ 3582 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3583 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3584 struct amdgpu_device_priv *device_priv = 3585 dixLookupScreenPrivate(&pDev->devPrivates, 3586 &amdgpu_device_private_key, pScreen); 3587 3588 device_priv->cursor = pCursor; 3589 drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 3590 3591 info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 3592} 3593 3594static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 3595 int x, int y) 3596{ 3597 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3598 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3599 struct amdgpu_device_priv *device_priv = 3600 dixLookupScreenPrivate(&pDev->devPrivates, 3601 &amdgpu_device_private_key, pScreen); 3602 3603 drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 3604 3605 info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 3606} 3607 3608static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 3609 ScreenPtr pScreen, 3610 CursorPtr pCursor) 3611{ 3612 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3613 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3614 3615 return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 3616} 3617 3618static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 3619 ScreenPtr pScreen, 3620 CursorPtr pCursor) 3621{ 3622 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3623 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3624 3625 return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 3626} 3627 3628static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 3629 ScreenPtr pScreen) 3630{ 3631 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3632 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3633 3634 return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 3635} 3636 3637static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 3638 ScreenPtr pScreen) 3639{ 3640 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3641 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3642 3643 info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 3644} 3645 3646miPointerSpriteFuncRec drmmode_sprite_funcs = { 3647 .RealizeCursor = drmmode_sprite_realize_realize_cursor, 3648 .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 3649 .SetCursor = drmmode_sprite_set_cursor, 3650 .MoveCursor = drmmode_sprite_move_cursor, 3651 .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 3652 .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 3653}; 3654 3655 3656void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3657{ 3658 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3659 xf86OutputPtr output = config->output[config->compat_output]; 3660 xf86CrtcPtr crtc = output->crtc; 3661 3662 if (crtc && crtc->enabled) { 3663 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 3664 } 3665} 3666 3667Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 3668 Bool set_hw) 3669{ 3670 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3671 unsigned num_desired = 0, num_on = 0; 3672 int c; 3673 3674 /* First, disable all unused CRTCs */ 3675 if (set_hw) { 3676 for (c = 0; c < config->num_crtc; c++) { 3677 xf86CrtcPtr crtc = config->crtc[c]; 3678 3679 /* Skip disabled CRTCs */ 3680 if (crtc->enabled) 3681 continue; 3682 3683 drmmode_crtc_dpms(crtc, DPMSModeOff); 3684 } 3685 } 3686 3687 /* Then, try setting the chosen mode on each CRTC */ 3688 for (c = 0; c < config->num_crtc; c++) { 3689 xf86CrtcPtr crtc = config->crtc[c]; 3690 xf86OutputPtr output = NULL; 3691 int o; 3692 3693 if (!crtc->enabled) 3694 continue; 3695 3696 if (config->output[config->compat_output]->crtc == crtc) 3697 output = config->output[config->compat_output]; 3698 else { 3699 for (o = 0; o < config->num_output; o++) 3700 if (config->output[o]->crtc == crtc) { 3701 output = config->output[o]; 3702 break; 3703 } 3704 } 3705 /* paranoia */ 3706 if (!output) 3707 continue; 3708 3709 num_desired++; 3710 3711 /* Mark that we'll need to re-set the mode for sure */ 3712 memset(&crtc->mode, 0, sizeof(crtc->mode)); 3713 if (!crtc->desiredMode.CrtcHDisplay) { 3714 DisplayModePtr mode = xf86OutputFindClosestMode(output, 3715 pScrn-> 3716 currentMode); 3717 3718 if (!mode) { 3719 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3720 "Failed to find mode for CRTC %d\n", c); 3721 continue; 3722 } 3723 crtc->desiredMode = *mode; 3724 crtc->desiredRotation = RR_Rotate_0; 3725 crtc->desiredX = 0; 3726 crtc->desiredY = 0; 3727 } 3728 3729 if (set_hw) { 3730 if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 3731 crtc->desiredRotation, 3732 crtc->desiredX, 3733 crtc->desiredY)) { 3734 num_on++; 3735 } else { 3736 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3737 "Failed to set mode on CRTC %d\n", c); 3738 RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 3739 crtc->rotation, 0, NULL); 3740 } 3741 } else { 3742 crtc->mode = crtc->desiredMode; 3743 crtc->rotation = crtc->desiredRotation; 3744 crtc->x = crtc->desiredX; 3745 crtc->y = crtc->desiredY; 3746 if (drmmode_handle_transform(crtc)) 3747 num_on++; 3748 } 3749 } 3750 3751 if (num_on == 0 && num_desired > 0) { 3752 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 3753 return FALSE; 3754 } 3755 3756 /* Validate leases on VT re-entry */ 3757 if (dixPrivateKeyRegistered(rrPrivKey)) 3758 drmmode_validate_leases(pScrn); 3759 3760 return TRUE; 3761} 3762 3763Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3764{ 3765 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3766 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3767 int i; 3768 3769 if (xf86_config->num_crtc) { 3770 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3771 "Initializing kms color map\n"); 3772 if (!miCreateDefColormap(pScreen)) 3773 return FALSE; 3774 3775 if (pScrn->depth == 30) { 3776 if (!drmmode_cm_enabled(&info->drmmode)) 3777 return TRUE; 3778 3779 for (i = 0; i < xf86_config->num_crtc; i++) { 3780 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3781 void *gamma; 3782 3783 if (crtc->gamma_size == 1024) 3784 continue; 3785 3786 gamma = malloc(1024 * 3 * sizeof(CARD16)); 3787 if (!gamma) { 3788 ErrorF("Failed to allocate gamma LUT memory\n"); 3789 return FALSE; 3790 } 3791 3792 free(crtc->gamma_red); 3793 crtc->gamma_size = 1024; 3794 crtc->gamma_red = gamma; 3795 crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 3796 crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 3797 } 3798 } 3799 3800 /* All Radeons support 10 bit CLUTs. */ 3801 if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10, 3802 NULL, NULL, CMAP_PALETTED_TRUECOLOR 3803 | CMAP_RELOAD_ON_MODE_SWITCH)) 3804 return FALSE; 3805 3806 for (i = 0; i < xf86_config->num_crtc; i++) { 3807 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3808 3809 drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 3810 crtc->gamma_green, 3811 crtc->gamma_blue, 3812 crtc->gamma_size); 3813 } 3814 } 3815 3816 return TRUE; 3817} 3818 3819static Bool 3820drmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 3821 int *num_hdmi) 3822{ 3823 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3824 int i; 3825 3826 for (i = 0; i < config->num_output; i++) { 3827 xf86OutputPtr output = config->output[i]; 3828 drmmode_output_private_ptr drmmode_output = output->driver_private; 3829 3830 if (drmmode_output->output_id == output_id) { 3831 switch(drmmode_output->mode_output->connector_type) { 3832 case DRM_MODE_CONNECTOR_DVII: 3833 case DRM_MODE_CONNECTOR_DVID: 3834 case DRM_MODE_CONNECTOR_DVIA: 3835 (*num_dvi)++; 3836 break; 3837 case DRM_MODE_CONNECTOR_HDMIA: 3838 case DRM_MODE_CONNECTOR_HDMIB: 3839 (*num_hdmi)++; 3840 break; 3841 } 3842 3843 return TRUE; 3844 } 3845 } 3846 3847 return FALSE; 3848} 3849 3850void 3851amdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3852{ 3853 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3854 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3855 drmModeResPtr mode_res; 3856 int i, j; 3857 Bool found; 3858 Bool changed = FALSE; 3859 int num_dvi = 0, num_hdmi = 0; 3860 3861 /* Try to re-set the mode on all the connectors with a BAD link-state: 3862 * This may happen if a link degrades and a new modeset is necessary, using 3863 * different link-training parameters. If the kernel found that the current 3864 * mode is not achievable anymore, it should have pruned the mode before 3865 * sending the hotplug event. Try to re-set the currently-set mode to keep 3866 * the display alive, this will fail if the mode has been pruned. 3867 * In any case, we will send randr events for the Desktop Environment to 3868 * deal with it, if it wants to. 3869 */ 3870 for (i = 0; i < config->num_output; i++) { 3871 xf86OutputPtr output = config->output[i]; 3872 xf86CrtcPtr crtc = output->crtc; 3873 drmmode_output_private_ptr drmmode_output = output->driver_private; 3874 3875 drmmode_output_detect(output); 3876 3877 if (!crtc || !drmmode_output->mode_output) 3878 continue; 3879 3880 /* Get an updated view of the properties for the current connector and 3881 * look for the link-status property 3882 */ 3883 for (j = 0; j < drmmode_output->num_props; j++) { 3884 drmmode_prop_ptr p = &drmmode_output->props[j]; 3885 3886 if (!strcmp(p->mode_prop->name, "link-status")) { 3887 if (p->value != DRM_MODE_LINK_STATUS_BAD) 3888 break; 3889 3890 /* the connector got a link failure, re-set the current mode */ 3891 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 3892 crtc->x, crtc->y); 3893 3894 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3895 "hotplug event: connector %u's link-state is BAD, " 3896 "tried resetting the current mode. You may be left" 3897 "with a black screen if this fails...\n", 3898 drmmode_output->mode_output->connector_id); 3899 3900 break; 3901 } 3902 } 3903 } 3904 3905 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3906 if (!mode_res) 3907 goto out; 3908 3909restart_destroy: 3910 for (i = 0; i < config->num_output; i++) { 3911 xf86OutputPtr output = config->output[i]; 3912 drmmode_output_private_ptr drmmode_output = output->driver_private; 3913 found = FALSE; 3914 for (j = 0; j < mode_res->count_connectors; j++) { 3915 if (mode_res->connectors[j] == drmmode_output->output_id) { 3916 found = TRUE; 3917 break; 3918 } 3919 } 3920 if (found) 3921 continue; 3922 3923 drmModeFreeConnector(drmmode_output->mode_output); 3924 drmmode_output->mode_output = NULL; 3925 drmmode_output->output_id = -1; 3926 3927 changed = TRUE; 3928 if (drmmode->delete_dp_12_displays) { 3929 RROutputDestroy(output->randr_output); 3930 xf86OutputDestroy(output); 3931 goto restart_destroy; 3932 } 3933 } 3934 3935 /* find new output ids we don't have outputs for */ 3936 for (i = 0; i < mode_res->count_connectors; i++) { 3937 for (j = 0; j < pAMDGPUEnt->num_scrns; j++) { 3938 if (drmmode_find_output(pAMDGPUEnt->scrn[j], 3939 mode_res->connectors[i], 3940 &num_dvi, &num_hdmi)) 3941 break; 3942 } 3943 3944 if (j < pAMDGPUEnt->num_scrns) 3945 continue; 3946 3947 if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 3948 &num_hdmi, 1) != 0) 3949 changed = TRUE; 3950 } 3951 3952 /* Check to see if a lessee has disappeared */ 3953 drmmode_validate_leases(scrn); 3954 3955 if (changed) { 3956#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 3957 RRSetChanged(xf86ScrnToScreen(scrn)); 3958#else 3959 rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 3960 rrScrPriv->changed = TRUE; 3961#endif 3962 RRTellChanged(xf86ScrnToScreen(scrn)); 3963 } 3964 3965 drmModeFreeResources(mode_res); 3966out: 3967 RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 3968} 3969 3970#ifdef HAVE_LIBUDEV 3971static void drmmode_handle_uevents(int fd, void *closure) 3972{ 3973 drmmode_ptr drmmode = closure; 3974 ScrnInfoPtr scrn = drmmode->scrn; 3975 struct udev_device *dev; 3976 Bool received = FALSE; 3977 struct timeval tv = { 0, 0 }; 3978 fd_set readfd; 3979 3980 FD_ZERO(&readfd); 3981 FD_SET(fd, &readfd); 3982 3983 while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 3984 FD_ISSET(fd, &readfd)) { 3985 /* select() ensured that this will not block */ 3986 dev = udev_monitor_receive_device(drmmode->uevent_monitor); 3987 if (dev) { 3988 udev_device_unref(dev); 3989 received = TRUE; 3990 } 3991 } 3992 3993 if (received) 3994 amdgpu_mode_hotplug(scrn, drmmode); 3995} 3996#endif 3997 3998void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3999{ 4000#ifdef HAVE_LIBUDEV 4001 struct udev *u; 4002 struct udev_monitor *mon; 4003 4004 u = udev_new(); 4005 if (!u) 4006 return; 4007 mon = udev_monitor_new_from_netlink(u, "udev"); 4008 if (!mon) { 4009 udev_unref(u); 4010 return; 4011 } 4012 4013 if (udev_monitor_filter_add_match_subsystem_devtype(mon, 4014 "drm", 4015 "drm_minor") < 0 || 4016 udev_monitor_enable_receiving(mon) < 0) { 4017 udev_monitor_unref(mon); 4018 udev_unref(u); 4019 return; 4020 } 4021 4022 drmmode->uevent_handler = 4023 xf86AddGeneralHandler(udev_monitor_get_fd(mon), 4024 drmmode_handle_uevents, drmmode); 4025 4026 drmmode->uevent_monitor = mon; 4027#endif 4028} 4029 4030void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 4031{ 4032#ifdef HAVE_LIBUDEV 4033 if (drmmode->uevent_handler) { 4034 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 4035 xf86RemoveGeneralHandler(drmmode->uevent_handler); 4036 4037 udev_monitor_unref(drmmode->uevent_monitor); 4038 udev_unref(u); 4039 } 4040#endif 4041} 4042 4043Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 4044 PixmapPtr new_front, uint64_t id, void *data, 4045 xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler, 4046 amdgpu_drm_abort_proc abort, 4047 enum drmmode_flip_sync flip_sync, 4048 uint32_t target_msc) 4049{ 4050 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 4051 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 4052 xf86CrtcPtr crtc = NULL; 4053 drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 4054 int crtc_id; 4055 uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 4056 drmmode_flipdata_ptr flipdata; 4057 Bool handle_deferred = FALSE; 4058 uintptr_t drm_queue_seq = 0; 4059 struct drmmode_fb *fb; 4060 int i = 0; 4061 4062 flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 4063 sizeof(flipdata->fb[0])); 4064 if (!flipdata) { 4065 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4066 "flip queue: data alloc failed.\n"); 4067 goto error; 4068 } 4069 4070 fb = amdgpu_pixmap_get_fb(new_front); 4071 if (!fb) { 4072 ErrorF("Failed to get FB for flip\n"); 4073 goto error; 4074 } 4075 4076 /* 4077 * Queue flips on all enabled CRTCs 4078 * Note that if/when we get per-CRTC buffers, we'll have to update this. 4079 * Right now it assumes a single shared fb across all CRTCs, with the 4080 * kernel fixing up the offset of each CRTC as necessary. 4081 * 4082 * Also, flips queued on disabled or incorrectly configured displays 4083 * may never complete; this is a configuration error. 4084 */ 4085 4086 flipdata->event_data = data; 4087 flipdata->handler = handler; 4088 flipdata->abort = abort; 4089 flipdata->fe_crtc = ref_crtc; 4090 4091 for (i = 0; i < config->num_crtc; i++) { 4092 crtc = config->crtc[i]; 4093 drmmode_crtc = crtc->driver_private; 4094 crtc_id = drmmode_get_crtc_id(crtc); 4095 4096 if (!drmmode_crtc_can_flip(crtc) || 4097 (drmmode_crtc->tear_free && crtc != ref_crtc)) 4098 continue; 4099 4100 flipdata->flip_count++; 4101 4102 drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 4103 flipdata, 4104 drmmode_flip_handler, 4105 drmmode_flip_abort, 4106 TRUE); 4107 if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 4108 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4109 "Allocating DRM queue event entry failed.\n"); 4110 goto error; 4111 } 4112 4113 if (drmmode_crtc->tear_free) { 4114 BoxRec extents = { .x1 = 0, .y1 = 0, 4115 .x2 = new_front->drawable.width, 4116 .y2 = new_front->drawable.height }; 4117 int scanout_id = drmmode_crtc->scanout_id ^ 1; 4118 4119 if (flip_sync == FLIP_ASYNC) { 4120 if (!drmmode_wait_vblank(crtc, 4121 DRM_VBLANK_RELATIVE | 4122 DRM_VBLANK_EVENT, 4123 0, drm_queue_seq, 4124 NULL, NULL)) 4125 goto flip_error; 4126 goto next; 4127 } 4128 4129 drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], 4130 amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap)); 4131 if (!flipdata->fb[crtc_id]) { 4132 ErrorF("Failed to get FB for TearFree flip\n"); 4133 goto error; 4134 } 4135 4136 amdgpu_scanout_do_update(crtc, scanout_id, new_front, 4137 extents); 4138 amdgpu_glamor_flush(crtc->scrn); 4139 4140 if (drmmode_crtc->scanout_update_pending) { 4141 amdgpu_drm_wait_pending_flip(crtc); 4142 handle_deferred = TRUE; 4143 amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 4144 drmmode_crtc->scanout_update_pending = 0; 4145 } 4146 } else { 4147 drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], fb); 4148 } 4149 4150 if (crtc == ref_crtc) { 4151 if (drmmode_page_flip_target_absolute(pAMDGPUEnt, 4152 drmmode_crtc, 4153 flipdata->fb[crtc_id]->handle, 4154 flip_flags, 4155 drm_queue_seq, 4156 target_msc) != 0) 4157 goto flip_error; 4158 } else { 4159 if (drmmode_page_flip_target_relative(pAMDGPUEnt, 4160 drmmode_crtc, 4161 flipdata->fb[crtc_id]->handle, 4162 flip_flags, 4163 drm_queue_seq, 0) != 0) 4164 goto flip_error; 4165 } 4166 4167 if (drmmode_crtc->tear_free) { 4168 drmmode_crtc->scanout_id ^= 1; 4169 drmmode_crtc->ignore_damage = TRUE; 4170 } 4171 4172 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 4173 flipdata->fb[crtc_id]); 4174 4175 next: 4176 drm_queue_seq = 0; 4177 } 4178 4179 if (handle_deferred) 4180 amdgpu_drm_queue_handle_deferred(ref_crtc); 4181 if (flipdata->flip_count > 0) 4182 return TRUE; 4183 4184flip_error: 4185 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 4186 strerror(errno)); 4187 4188error: 4189 if (drm_queue_seq) 4190 amdgpu_drm_abort_entry(drm_queue_seq); 4191 else if (crtc) 4192 drmmode_flip_abort(crtc, flipdata); 4193 else { 4194 abort(NULL, data); 4195 free(flipdata); 4196 } 4197 4198 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 4199 strerror(errno)); 4200 if (handle_deferred) 4201 amdgpu_drm_queue_handle_deferred(ref_crtc); 4202 return FALSE; 4203} 4204