1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 2007 Red Hat, Inc. 3428d7b3dSmrg * Copyright © 2013-2014 Intel Corporation 4428d7b3dSmrg * 5428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 6428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 7428d7b3dSmrg * to deal in the Software without restriction, including without limitation 8428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 10428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 11428d7b3dSmrg * 12428d7b3dSmrg * The above copyright notice and this permission notice (including the next 13428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 14428d7b3dSmrg * Software. 15428d7b3dSmrg * 16428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22428d7b3dSmrg * SOFTWARE. 23428d7b3dSmrg * 24428d7b3dSmrg * Authors: 25428d7b3dSmrg * Dave Airlie <airlied@redhat.com> 26428d7b3dSmrg * 27428d7b3dSmrg */ 28428d7b3dSmrg 29428d7b3dSmrg#ifdef HAVE_CONFIG_H 30428d7b3dSmrg#include "config.h" 31428d7b3dSmrg#endif 32428d7b3dSmrg 33428d7b3dSmrg#include <stdint.h> 34428d7b3dSmrg#include <sys/types.h> 35428d7b3dSmrg#include <sys/stat.h> 36428d7b3dSmrg#include <sys/mman.h> 37428d7b3dSmrg#include <fcntl.h> 38428d7b3dSmrg#include <unistd.h> 39428d7b3dSmrg#include <errno.h> 40428d7b3dSmrg#include <poll.h> 41428d7b3dSmrg#include <ctype.h> 42428d7b3dSmrg 43428d7b3dSmrg#include "sna.h" 44428d7b3dSmrg#include "sna_reg.h" 45428d7b3dSmrg#include "fb/fbpict.h" 46428d7b3dSmrg#include "intel_options.h" 47428d7b3dSmrg#include "backlight.h" 48428d7b3dSmrg 49428d7b3dSmrg#include <xf86Crtc.h> 50428d7b3dSmrg#include <xf86RandR12.h> 51428d7b3dSmrg#include <cursorstr.h> 52428d7b3dSmrg 53428d7b3dSmrg#if XF86_CRTC_VERSION >= 3 54428d7b3dSmrg#define HAS_GAMMA 1 55428d7b3dSmrg#else 56428d7b3dSmrg#define HAS_GAMMA 0 57428d7b3dSmrg#endif 58428d7b3dSmrg 59428d7b3dSmrg#include <X11/Xatom.h> 60428d7b3dSmrg#if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H) 61428d7b3dSmrg#include <X11/extensions/dpmsconst.h> 62428d7b3dSmrg#else 63428d7b3dSmrg#define DPMSModeOn 0 64428d7b3dSmrg#define DPMSModeOff 3 65428d7b3dSmrg#endif 66428d7b3dSmrg#include <xf86DDC.h> /* for xf86InterpretEDID */ 67428d7b3dSmrg 68428d7b3dSmrg#include <xf86drm.h> 69428d7b3dSmrg 70428d7b3dSmrg#ifdef HAVE_VALGRIND 71428d7b3dSmrg#include <valgrind.h> 72428d7b3dSmrg#include <memcheck.h> 73428d7b3dSmrg#endif 74428d7b3dSmrg 75428d7b3dSmrg/* Minor discrepancy between 32-bit/64-bit ABI in old kernels */ 76428d7b3dSmrgunion compat_mode_get_connector{ 77428d7b3dSmrg struct drm_mode_get_connector conn; 78428d7b3dSmrg uint32_t pad[20]; 79428d7b3dSmrg}; 80428d7b3dSmrg 81428d7b3dSmrg#define KNOWN_MODE_FLAGS ((1<<14)-1) 82428d7b3dSmrg 83428d7b3dSmrg#ifndef MONITOR_EDID_COMPLETE_RAWDATA 84428d7b3dSmrg#define MONITOR_EDID_COMPLETE_RAWDATA 1 85428d7b3dSmrg#endif 86428d7b3dSmrg 87428d7b3dSmrg#ifndef DEFAULT_DPI 88428d7b3dSmrg#define DEFAULT_DPI 96 89428d7b3dSmrg#endif 90428d7b3dSmrg 91428d7b3dSmrg#define DRM_MODE_PAGE_FLIP_ASYNC 0x02 92428d7b3dSmrg 93428d7b3dSmrg#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 94428d7b3dSmrg#define DRM_PLANE_TYPE_OVERLAY 0 95428d7b3dSmrg#define DRM_PLANE_TYPE_PRIMARY 1 96428d7b3dSmrg#define DRM_PLANE_TYPE_CURSOR 2 97428d7b3dSmrg 98428d7b3dSmrg#define LOCAL_IOCTL_MODE_OBJ_GETPROPERTIES DRM_IOWR(0xb9, struct local_mode_obj_get_properties) 99428d7b3dSmrgstruct local_mode_obj_get_properties { 100428d7b3dSmrg uint64_t props_ptr; 101428d7b3dSmrg uint64_t prop_values_ptr; 102428d7b3dSmrg uint32_t count_props; 103428d7b3dSmrg uint32_t obj_id; 104428d7b3dSmrg uint32_t obj_type; 105428d7b3dSmrg uint32_t pad; 106428d7b3dSmrg}; 107428d7b3dSmrg#define LOCAL_MODE_OBJECT_PLANE 0xeeeeeeee 108428d7b3dSmrg 109428d7b3dSmrg#if 0 110428d7b3dSmrg#define __DBG DBG 111428d7b3dSmrg#else 112428d7b3dSmrg#define __DBG(x) 113428d7b3dSmrg#endif 114428d7b3dSmrg 115428d7b3dSmrgextern XF86ConfigPtr xf86configptr; 116428d7b3dSmrg 117428d7b3dSmrgstruct sna_crtc { 118428d7b3dSmrg xf86CrtcPtr base; 119428d7b3dSmrg struct drm_mode_modeinfo kmode; 120428d7b3dSmrg int dpms_mode; 121428d7b3dSmrg PixmapPtr slave_pixmap; 122428d7b3dSmrg DamagePtr slave_damage; 123428d7b3dSmrg struct kgem_bo *bo, *shadow_bo, *client_bo; 124428d7b3dSmrg struct sna_cursor *cursor; 125428d7b3dSmrg unsigned int last_cursor_size; 126428d7b3dSmrg uint32_t offset; 127428d7b3dSmrg bool shadow; 128428d7b3dSmrg bool fallback_shadow; 129428d7b3dSmrg bool transform; 130428d7b3dSmrg bool flip_pending; 131428d7b3dSmrg uint8_t id; 132428d7b3dSmrg uint8_t pipe; 133428d7b3dSmrg 134428d7b3dSmrg RegionRec client_damage; /* XXX overlap with shadow damage? */ 135428d7b3dSmrg 136428d7b3dSmrg uint16_t shadow_bo_width, shadow_bo_height; 137428d7b3dSmrg 138428d7b3dSmrg uint32_t rotation; 139428d7b3dSmrg struct plane { 140428d7b3dSmrg uint32_t id; 141428d7b3dSmrg struct { 142428d7b3dSmrg uint32_t prop; 143428d7b3dSmrg uint32_t supported; 144428d7b3dSmrg uint32_t current; 145428d7b3dSmrg } rotation; 146428d7b3dSmrg } primary, sprite; 147428d7b3dSmrg 148428d7b3dSmrg uint32_t mode_serial, flip_serial; 149428d7b3dSmrg 150428d7b3dSmrg uint32_t last_seq, wrap_seq; 151428d7b3dSmrg struct ust_msc swap; 152428d7b3dSmrg 153428d7b3dSmrg sna_flip_handler_t flip_handler; 154428d7b3dSmrg struct kgem_bo *flip_bo; 155428d7b3dSmrg void *flip_data; 156428d7b3dSmrg 157428d7b3dSmrg struct list shadow_link; 158428d7b3dSmrg}; 159428d7b3dSmrg 160428d7b3dSmrgstruct sna_property { 161428d7b3dSmrg drmModePropertyPtr kprop; 162428d7b3dSmrg int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */ 163428d7b3dSmrg Atom *atoms; 164428d7b3dSmrg}; 165428d7b3dSmrg 166428d7b3dSmrgstruct sna_output { 167428d7b3dSmrg xf86OutputPtr base; 168428d7b3dSmrg unsigned id; 169428d7b3dSmrg unsigned serial; 170428d7b3dSmrg 171428d7b3dSmrg unsigned possible_encoders; 172428d7b3dSmrg unsigned attached_encoders; 173428d7b3dSmrg 174428d7b3dSmrg unsigned int is_panel : 1; 175428d7b3dSmrg unsigned int add_default_modes : 1; 176428d7b3dSmrg 177428d7b3dSmrg uint32_t edid_idx; 178428d7b3dSmrg uint32_t edid_blob_id; 179428d7b3dSmrg uint32_t edid_len; 180428d7b3dSmrg void *edid_raw; 181428d7b3dSmrg 182428d7b3dSmrg bool has_panel_limits; 183428d7b3dSmrg int panel_hdisplay; 184428d7b3dSmrg int panel_vdisplay; 185428d7b3dSmrg 186428d7b3dSmrg uint32_t dpms_id; 187428d7b3dSmrg int dpms_mode; 188428d7b3dSmrg struct backlight backlight; 189428d7b3dSmrg int backlight_active_level; 190428d7b3dSmrg 191428d7b3dSmrg int num_modes; 192428d7b3dSmrg struct drm_mode_modeinfo *modes; 193428d7b3dSmrg 194428d7b3dSmrg int num_props; 195428d7b3dSmrg uint32_t *prop_ids; 196428d7b3dSmrg uint64_t *prop_values; 197428d7b3dSmrg struct sna_property *props; 198428d7b3dSmrg}; 199428d7b3dSmrg 200428d7b3dSmrgenum { /* XXX copied from hw/xfree86/modes/xf86Crtc.c */ 201428d7b3dSmrg OPTION_PREFERRED_MODE, 202428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,1,0) 203428d7b3dSmrg OPTION_ZOOM_MODES, 204428d7b3dSmrg#endif 205428d7b3dSmrg OPTION_POSITION, 206428d7b3dSmrg OPTION_BELOW, 207428d7b3dSmrg OPTION_RIGHT_OF, 208428d7b3dSmrg OPTION_ABOVE, 209428d7b3dSmrg OPTION_LEFT_OF, 210428d7b3dSmrg OPTION_ENABLE, 211428d7b3dSmrg OPTION_DISABLE, 212428d7b3dSmrg OPTION_MIN_CLOCK, 213428d7b3dSmrg OPTION_MAX_CLOCK, 214428d7b3dSmrg OPTION_IGNORE, 215428d7b3dSmrg OPTION_ROTATE, 216428d7b3dSmrg OPTION_PANNING, 217428d7b3dSmrg OPTION_PRIMARY, 218428d7b3dSmrg OPTION_DEFAULT_MODES, 219428d7b3dSmrg}; 220428d7b3dSmrg 221428d7b3dSmrgstatic void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc); 222428d7b3dSmrg 223428d7b3dSmrgstatic bool is_zaphod(ScrnInfoPtr scrn) 224428d7b3dSmrg{ 225428d7b3dSmrg return xf86IsEntityShared(scrn->entityList[0]); 226428d7b3dSmrg} 227428d7b3dSmrg 228428d7b3dSmrginline static unsigned count_to_mask(int x) 229428d7b3dSmrg{ 230428d7b3dSmrg return (1 << x) - 1; 231428d7b3dSmrg} 232428d7b3dSmrg 233428d7b3dSmrgstatic inline struct sna_output *to_sna_output(xf86OutputPtr output) 234428d7b3dSmrg{ 235428d7b3dSmrg return output->driver_private; 236428d7b3dSmrg} 237428d7b3dSmrg 238428d7b3dSmrgstatic inline int to_connector_id(xf86OutputPtr output) 239428d7b3dSmrg{ 240428d7b3dSmrg assert(to_sna_output(output)); 241428d7b3dSmrg assert(to_sna_output(output)->id); 242428d7b3dSmrg return to_sna_output(output)->id; 243428d7b3dSmrg} 244428d7b3dSmrg 245428d7b3dSmrgstatic inline struct sna_crtc *to_sna_crtc(xf86CrtcPtr crtc) 246428d7b3dSmrg{ 247428d7b3dSmrg return crtc->driver_private; 248428d7b3dSmrg} 249428d7b3dSmrg 250428d7b3dSmrgstatic inline bool event_pending(int fd) 251428d7b3dSmrg{ 252428d7b3dSmrg struct pollfd pfd; 253428d7b3dSmrg pfd.fd = fd; 254428d7b3dSmrg pfd.events = POLLIN; 255428d7b3dSmrg return poll(&pfd, 1, 0) == 1; 256428d7b3dSmrg} 257428d7b3dSmrg 258428d7b3dSmrgstatic bool sna_mode_wait_for_event(struct sna *sna) 259428d7b3dSmrg{ 260428d7b3dSmrg struct pollfd pfd; 261428d7b3dSmrg pfd.fd = sna->kgem.fd; 262428d7b3dSmrg pfd.events = POLLIN; 263428d7b3dSmrg return poll(&pfd, 1, -1) == 1; 264428d7b3dSmrg} 265428d7b3dSmrg 266428d7b3dSmrgstatic inline uint32_t fb_id(struct kgem_bo *bo) 267428d7b3dSmrg{ 268428d7b3dSmrg return bo->delta; 269428d7b3dSmrg} 270428d7b3dSmrg 271428d7b3dSmrguint32_t sna_crtc_id(xf86CrtcPtr crtc) 272428d7b3dSmrg{ 273428d7b3dSmrg if (to_sna_crtc(crtc) == NULL) 274428d7b3dSmrg return 0; 275428d7b3dSmrg return to_sna_crtc(crtc)->id; 276428d7b3dSmrg} 277428d7b3dSmrg 278428d7b3dSmrgint sna_crtc_to_pipe(xf86CrtcPtr crtc) 279428d7b3dSmrg{ 280428d7b3dSmrg assert(to_sna_crtc(crtc)); 281428d7b3dSmrg return to_sna_crtc(crtc)->pipe; 282428d7b3dSmrg} 283428d7b3dSmrg 284428d7b3dSmrguint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc) 285428d7b3dSmrg{ 286428d7b3dSmrg assert(to_sna_crtc(crtc)); 287428d7b3dSmrg return to_sna_crtc(crtc)->sprite.id; 288428d7b3dSmrg} 289428d7b3dSmrg 290428d7b3dSmrgbool sna_crtc_is_on(xf86CrtcPtr crtc) 291428d7b3dSmrg{ 292428d7b3dSmrg assert(to_sna_crtc(crtc)); 293428d7b3dSmrg return to_sna_crtc(crtc)->bo != NULL; 294428d7b3dSmrg} 295428d7b3dSmrg 296428d7b3dSmrgbool sna_crtc_is_transformed(xf86CrtcPtr crtc) 297428d7b3dSmrg{ 298428d7b3dSmrg assert(to_sna_crtc(crtc)); 299428d7b3dSmrg return to_sna_crtc(crtc)->transform; 300428d7b3dSmrg} 301428d7b3dSmrg 302428d7b3dSmrgstatic inline uint64_t msc64(struct sna_crtc *sna_crtc, uint32_t seq) 303428d7b3dSmrg{ 304428d7b3dSmrg if (seq < sna_crtc->last_seq) { 305428d7b3dSmrg if (sna_crtc->last_seq - seq > 0x40000000) { 306428d7b3dSmrg sna_crtc->wrap_seq++; 307428d7b3dSmrg DBG(("%s: pipe=%d wrapped; was %u, now %u, wraps=%u\n", 308428d7b3dSmrg __FUNCTION__, sna_crtc->pipe, 309428d7b3dSmrg sna_crtc->last_seq, seq, sna_crtc->wrap_seq)); 310428d7b3dSmrg } else { 311428d7b3dSmrg ERR(("%s: pipe=%d msc went backwards; was %u, now %u\n", 312428d7b3dSmrg __FUNCTION__, sna_crtc->pipe, sna_crtc->last_seq, seq)); 313428d7b3dSmrg seq = sna_crtc->last_seq; 314428d7b3dSmrg } 315428d7b3dSmrg } 316428d7b3dSmrg sna_crtc->last_seq = seq; 317428d7b3dSmrg return (uint64_t)sna_crtc->wrap_seq << 32 | seq; 318428d7b3dSmrg} 319428d7b3dSmrg 320428d7b3dSmrguint64_t sna_crtc_record_swap(xf86CrtcPtr crtc, 321428d7b3dSmrg int tv_sec, int tv_usec, unsigned seq) 322428d7b3dSmrg{ 323428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 324428d7b3dSmrg assert(sna_crtc); 325428d7b3dSmrg DBG(("%s: recording last swap on pipe=%d, frame %d, time %d.%06d\n", 326428d7b3dSmrg __FUNCTION__, sna_crtc->pipe, seq, tv_sec, tv_usec)); 327428d7b3dSmrg sna_crtc->swap.tv_sec = tv_sec; 328428d7b3dSmrg sna_crtc->swap.tv_usec = tv_usec; 329428d7b3dSmrg return sna_crtc->swap.msc = msc64(sna_crtc, seq); 330428d7b3dSmrg} 331428d7b3dSmrg 332428d7b3dSmrgconst struct ust_msc *sna_crtc_last_swap(xf86CrtcPtr crtc) 333428d7b3dSmrg{ 334428d7b3dSmrg static struct ust_msc zero; 335428d7b3dSmrg 336428d7b3dSmrg if (crtc == NULL) { 337428d7b3dSmrg return &zero; 338428d7b3dSmrg } else { 339428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 340428d7b3dSmrg assert(sna_crtc); 341428d7b3dSmrg return &sna_crtc->swap; 342428d7b3dSmrg } 343428d7b3dSmrg} 344428d7b3dSmrg 345428d7b3dSmrgxf86CrtcPtr sna_mode_first_crtc(struct sna *sna) 346428d7b3dSmrg{ 347428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 348428d7b3dSmrg if (sna->mode.num_real_crtc) 349428d7b3dSmrg return config->crtc[0]; 350428d7b3dSmrg else 351428d7b3dSmrg return NULL; 352428d7b3dSmrg} 353428d7b3dSmrg 354428d7b3dSmrg#ifndef NDEBUG 355428d7b3dSmrgstatic void gem_close(int fd, uint32_t handle); 356428d7b3dSmrgstatic void assert_scanout(struct kgem *kgem, struct kgem_bo *bo, 357428d7b3dSmrg int width, int height) 358428d7b3dSmrg{ 359428d7b3dSmrg struct drm_mode_fb_cmd info; 360428d7b3dSmrg 361428d7b3dSmrg assert(bo->scanout); 362428d7b3dSmrg 363428d7b3dSmrg VG_CLEAR(info); 364428d7b3dSmrg info.fb_id = fb_id(bo); 365428d7b3dSmrg 366428d7b3dSmrg assert(drmIoctl(kgem->fd, DRM_IOCTL_MODE_GETFB, &info) == 0); 367428d7b3dSmrg gem_close(kgem->fd, info.handle); 368428d7b3dSmrg 369428d7b3dSmrg assert(width == info.width && height == info.height); 370428d7b3dSmrg} 371428d7b3dSmrg#else 372428d7b3dSmrg#define assert_scanout(k, b, w, h) 373428d7b3dSmrg#endif 374428d7b3dSmrg 375428d7b3dSmrgstatic unsigned get_fb(struct sna *sna, struct kgem_bo *bo, 376428d7b3dSmrg int width, int height) 377428d7b3dSmrg{ 378428d7b3dSmrg ScrnInfoPtr scrn = sna->scrn; 379428d7b3dSmrg struct drm_mode_fb_cmd arg; 380428d7b3dSmrg 381428d7b3dSmrg assert(bo->refcnt); 382428d7b3dSmrg assert(bo->proxy == NULL); 383428d7b3dSmrg assert(!bo->snoop); 384428d7b3dSmrg assert(8*bo->pitch >= width * scrn->bitsPerPixel); 385428d7b3dSmrg assert(height * bo->pitch <= kgem_bo_size(bo)); /* XXX crtc offset */ 386428d7b3dSmrg if (fb_id(bo)) { 387428d7b3dSmrg DBG(("%s: reusing fb=%d for handle=%d\n", 388428d7b3dSmrg __FUNCTION__, fb_id(bo), bo->handle)); 389428d7b3dSmrg assert_scanout(&sna->kgem, bo, width, height); 390428d7b3dSmrg return fb_id(bo); 391428d7b3dSmrg } 392428d7b3dSmrg 393428d7b3dSmrg DBG(("%s: create fb %dx%d@%d/%d\n", 394428d7b3dSmrg __FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel)); 395428d7b3dSmrg 396428d7b3dSmrg assert(bo->tiling != I915_TILING_Y); 397428d7b3dSmrg assert((bo->pitch & 63) == 0); 398428d7b3dSmrg 399428d7b3dSmrg VG_CLEAR(arg); 400428d7b3dSmrg arg.width = width; 401428d7b3dSmrg arg.height = height; 402428d7b3dSmrg arg.pitch = bo->pitch; 403428d7b3dSmrg arg.bpp = scrn->bitsPerPixel; 404428d7b3dSmrg arg.depth = scrn->depth; 405428d7b3dSmrg arg.handle = bo->handle; 406428d7b3dSmrg 407428d7b3dSmrg assert(sna->scrn->vtSema); /* must be master */ 408428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_ADDFB, &arg)) { 409428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 410428d7b3dSmrg "%s: failed to add fb: %dx%d depth=%d, bpp=%d, pitch=%d: %d\n", 411428d7b3dSmrg __FUNCTION__, width, height, 412428d7b3dSmrg scrn->depth, scrn->bitsPerPixel, bo->pitch, errno); 413428d7b3dSmrg return 0; 414428d7b3dSmrg } 415428d7b3dSmrg assert(arg.fb_id != 0); 416428d7b3dSmrg 417428d7b3dSmrg DBG(("%s: attached fb=%d to handle=%d\n", 418428d7b3dSmrg __FUNCTION__, arg.fb_id, arg.handle)); 419428d7b3dSmrg 420428d7b3dSmrg bo->scanout = true; 421428d7b3dSmrg return bo->delta = arg.fb_id; 422428d7b3dSmrg} 423428d7b3dSmrg 424428d7b3dSmrgstatic uint32_t gem_create(int fd, int size) 425428d7b3dSmrg{ 426428d7b3dSmrg struct drm_i915_gem_create create; 427428d7b3dSmrg 428428d7b3dSmrg assert((size & 4095) == 0); 429428d7b3dSmrg 430428d7b3dSmrg VG_CLEAR(create); 431428d7b3dSmrg create.handle = 0; 432428d7b3dSmrg create.size = size; 433428d7b3dSmrg (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create); 434428d7b3dSmrg 435428d7b3dSmrg return create.handle; 436428d7b3dSmrg} 437428d7b3dSmrg 438428d7b3dSmrgstatic void *gem_mmap(int fd, int handle, int size) 439428d7b3dSmrg{ 440428d7b3dSmrg struct drm_i915_gem_mmap_gtt mmap_arg; 441428d7b3dSmrg void *ptr; 442428d7b3dSmrg 443428d7b3dSmrg VG_CLEAR(mmap_arg); 444428d7b3dSmrg mmap_arg.handle = handle; 445428d7b3dSmrg if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg)) 446428d7b3dSmrg return NULL; 447428d7b3dSmrg 448428d7b3dSmrg ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, mmap_arg.offset); 449428d7b3dSmrg if (ptr == MAP_FAILED) 450428d7b3dSmrg return NULL; 451428d7b3dSmrg 452428d7b3dSmrg return ptr; 453428d7b3dSmrg} 454428d7b3dSmrg 455428d7b3dSmrgstatic void gem_close(int fd, uint32_t handle) 456428d7b3dSmrg{ 457428d7b3dSmrg struct drm_gem_close close; 458428d7b3dSmrg 459428d7b3dSmrg VG_CLEAR(close); 460428d7b3dSmrg close.handle = handle; 461428d7b3dSmrg (void)drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &close); 462428d7b3dSmrg} 463428d7b3dSmrg 464428d7b3dSmrg#define BACKLIGHT_NAME "Backlight" 465428d7b3dSmrg#define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT" 466428d7b3dSmrgstatic Atom backlight_atom, backlight_deprecated_atom; 467428d7b3dSmrg 468428d7b3dSmrg#if HAVE_UDEV 469428d7b3dSmrgstatic void 470428d7b3dSmrgsna_backlight_uevent(int fd, void *closure) 471428d7b3dSmrg{ 472428d7b3dSmrg struct sna *sna = closure; 473428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 474428d7b3dSmrg int i; 475428d7b3dSmrg 476428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 477428d7b3dSmrg 478428d7b3dSmrg /* Drain the event queue */ 479428d7b3dSmrg while (event_pending(fd)) { 480428d7b3dSmrg struct udev_device *dev; 481428d7b3dSmrg 482428d7b3dSmrg DBG(("%s: waiting for uevent\n", __FUNCTION__)); 483428d7b3dSmrg dev = udev_monitor_receive_device(sna->mode.backlight_monitor); 484428d7b3dSmrg if (dev == NULL) 485428d7b3dSmrg break; 486428d7b3dSmrg 487428d7b3dSmrg udev_device_unref(dev); 488428d7b3dSmrg } 489428d7b3dSmrg 490428d7b3dSmrg /* Query all backlights for any changes */ 491428d7b3dSmrg DBG(("%s: probing backlights for changes\n", __FUNCTION__)); 492428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 493428d7b3dSmrg xf86OutputPtr output = config->output[i]; 494428d7b3dSmrg struct sna_output *sna_output = to_sna_output(output); 495428d7b3dSmrg int val; 496428d7b3dSmrg 497428d7b3dSmrg if (sna_output->dpms_mode != DPMSModeOn) 498428d7b3dSmrg continue; 499428d7b3dSmrg 500428d7b3dSmrg assert(output->randr_output); 501428d7b3dSmrg 502428d7b3dSmrg val = backlight_get(&sna_output->backlight); 503428d7b3dSmrg if (val < 0) 504428d7b3dSmrg continue; 505428d7b3dSmrg DBG(("%s(%s): backlight '%s' was %d, now %d\n", 506428d7b3dSmrg __FUNCTION__, output->name, sna_output->backlight.iface, 507428d7b3dSmrg sna_output->backlight_active_level, val)); 508428d7b3dSmrg 509428d7b3dSmrg if (val == sna_output->backlight_active_level) 510428d7b3dSmrg continue; 511428d7b3dSmrg 512428d7b3dSmrg sna_output->backlight_active_level = val; 513428d7b3dSmrg 514428d7b3dSmrg if (output->randr_output) { 515428d7b3dSmrg DBG(("%s(%s): sending change notification\n", __FUNCTION__, output->name)); 516428d7b3dSmrg RRChangeOutputProperty(output->randr_output, 517428d7b3dSmrg backlight_atom, XA_INTEGER, 518428d7b3dSmrg 32, PropModeReplace, 1, &val, 519428d7b3dSmrg TRUE, FALSE); 520428d7b3dSmrg RRChangeOutputProperty(output->randr_output, 521428d7b3dSmrg backlight_deprecated_atom, XA_INTEGER, 522428d7b3dSmrg 32, PropModeReplace, 1, &val, 523428d7b3dSmrg TRUE, FALSE); 524428d7b3dSmrg } 525428d7b3dSmrg } 526428d7b3dSmrg} 527428d7b3dSmrg 528428d7b3dSmrgstatic void sna_backlight_pre_init(struct sna *sna) 529428d7b3dSmrg{ 530428d7b3dSmrg struct udev *u; 531428d7b3dSmrg struct udev_monitor *mon; 532428d7b3dSmrg 533428d7b3dSmrg#if !USE_BACKLIGHT 534428d7b3dSmrg return; 535428d7b3dSmrg#endif 536428d7b3dSmrg 537428d7b3dSmrg u = udev_new(); 538428d7b3dSmrg if (!u) 539428d7b3dSmrg return; 540428d7b3dSmrg 541428d7b3dSmrg mon = udev_monitor_new_from_netlink(u, "udev"); 542428d7b3dSmrg if (!mon) 543428d7b3dSmrg goto free_udev; 544428d7b3dSmrg 545428d7b3dSmrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, "backlight", NULL)) 546428d7b3dSmrg goto free_monitor; 547428d7b3dSmrg 548428d7b3dSmrg if (udev_monitor_enable_receiving(mon)) 549428d7b3dSmrg goto free_monitor; 550428d7b3dSmrg 551428d7b3dSmrg sna->mode.backlight_handler = 552428d7b3dSmrg xf86AddGeneralHandler(udev_monitor_get_fd(mon), 553428d7b3dSmrg sna_backlight_uevent, sna); 554428d7b3dSmrg if (!sna->mode.backlight_handler) 555428d7b3dSmrg goto free_monitor; 556428d7b3dSmrg 557428d7b3dSmrg DBG(("%s: installed backlight monitor\n", __FUNCTION__)); 558428d7b3dSmrg sna->mode.backlight_monitor = mon; 559428d7b3dSmrg 560428d7b3dSmrg return; 561428d7b3dSmrg 562428d7b3dSmrgfree_monitor: 563428d7b3dSmrg udev_monitor_unref(mon); 564428d7b3dSmrgfree_udev: 565428d7b3dSmrg udev_unref(u); 566428d7b3dSmrg} 567428d7b3dSmrg 568428d7b3dSmrgstatic void sna_backlight_drain_uevents(struct sna *sna) 569428d7b3dSmrg{ 570428d7b3dSmrg if (sna->mode.backlight_monitor == NULL) 571428d7b3dSmrg return; 572428d7b3dSmrg 573428d7b3dSmrg sna_backlight_uevent(udev_monitor_get_fd(sna->mode.backlight_monitor), 574428d7b3dSmrg sna); 575428d7b3dSmrg} 576428d7b3dSmrg 577428d7b3dSmrgstatic void sna_backlight_close(struct sna *sna) 578428d7b3dSmrg{ 579428d7b3dSmrg struct udev *u; 580428d7b3dSmrg 581428d7b3dSmrg if (sna->mode.backlight_handler == NULL) 582428d7b3dSmrg return; 583428d7b3dSmrg 584428d7b3dSmrg xf86RemoveGeneralHandler(sna->mode.backlight_handler); 585428d7b3dSmrg 586428d7b3dSmrg u = udev_monitor_get_udev(sna->mode.backlight_monitor); 587428d7b3dSmrg udev_monitor_unref(sna->mode.backlight_monitor); 588428d7b3dSmrg udev_unref(u); 589428d7b3dSmrg 590428d7b3dSmrg sna->mode.backlight_handler = NULL; 591428d7b3dSmrg sna->mode.backlight_monitor = NULL; 592428d7b3dSmrg} 593428d7b3dSmrg#else 594428d7b3dSmrgstatic void sna_backlight_pre_init(struct sna *sna) { } 595428d7b3dSmrgstatic void sna_backlight_drain_uevents(struct sna *sna) { } 596428d7b3dSmrgstatic void sna_backlight_close(struct sna *sna) { } 597428d7b3dSmrg#endif 598428d7b3dSmrg 599428d7b3dSmrgstatic void 600428d7b3dSmrgsna_output_backlight_disable(struct sna_output *sna_output) 601428d7b3dSmrg{ 602428d7b3dSmrg xf86OutputPtr output = sna_output->base; 603428d7b3dSmrg 604428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 605428d7b3dSmrg "Failed to set backlight %s for output %s, disabling\n", 606428d7b3dSmrg sna_output->backlight.iface, output->name); 607428d7b3dSmrg backlight_disable(&sna_output->backlight); 608428d7b3dSmrg if (output->randr_output) { 609428d7b3dSmrg RRDeleteOutputProperty(output->randr_output, backlight_atom); 610428d7b3dSmrg RRDeleteOutputProperty(output->randr_output, backlight_deprecated_atom); 611428d7b3dSmrg } 612428d7b3dSmrg} 613428d7b3dSmrg 614428d7b3dSmrgstatic int 615428d7b3dSmrgsna_output_backlight_set(struct sna_output *sna_output, int level) 616428d7b3dSmrg{ 617428d7b3dSmrg int ret = 0; 618428d7b3dSmrg 619428d7b3dSmrg DBG(("%s(%s) level=%d, max=%d\n", __FUNCTION__, 620428d7b3dSmrg sna_output->base->name, level, sna_output->backlight.max)); 621428d7b3dSmrg 622428d7b3dSmrg if (backlight_set(&sna_output->backlight, level)) { 623428d7b3dSmrg sna_output_backlight_disable(sna_output); 624428d7b3dSmrg ret = -1; 625428d7b3dSmrg } 626428d7b3dSmrg 627428d7b3dSmrg /* Consume the uevent notification now so that we don't misconstrue 628428d7b3dSmrg * the change latter when we wake up and the output is in a different 629428d7b3dSmrg * state. 630428d7b3dSmrg */ 631428d7b3dSmrg sna_backlight_drain_uevents(to_sna(sna_output->base->scrn)); 632428d7b3dSmrg return ret; 633428d7b3dSmrg} 634428d7b3dSmrg 635428d7b3dSmrgstatic void 636428d7b3dSmrgsna_output_backlight_off(struct sna_output *sna_output) 637428d7b3dSmrg{ 638428d7b3dSmrg DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name)); 639428d7b3dSmrg backlight_off(&sna_output->backlight); 640428d7b3dSmrg sna_output_backlight_set(sna_output, 0); 641428d7b3dSmrg} 642428d7b3dSmrg 643428d7b3dSmrgstatic void 644428d7b3dSmrgsna_output_backlight_on(struct sna_output *sna_output) 645428d7b3dSmrg{ 646428d7b3dSmrg DBG(("%s(%s)\n", __FUNCTION__, sna_output->base->name)); 647428d7b3dSmrg sna_output_backlight_set(sna_output, 648428d7b3dSmrg sna_output->backlight_active_level); 649428d7b3dSmrg if (backlight_on(&sna_output->backlight) < 0) 650428d7b3dSmrg sna_output_backlight_disable(sna_output); 651428d7b3dSmrg} 652428d7b3dSmrg 653428d7b3dSmrgstatic int 654428d7b3dSmrgsna_output_backlight_get(xf86OutputPtr output) 655428d7b3dSmrg{ 656428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 657428d7b3dSmrg int level = backlight_get(&sna_output->backlight); 658428d7b3dSmrg DBG(("%s(%s) level=%d, max=%d\n", __FUNCTION__, 659428d7b3dSmrg output->name, level, sna_output->backlight.max)); 660428d7b3dSmrg return level; 661428d7b3dSmrg} 662428d7b3dSmrg 663428d7b3dSmrgstatic char * 664428d7b3dSmrghas_user_backlight_override(xf86OutputPtr output) 665428d7b3dSmrg{ 666428d7b3dSmrg struct sna *sna = to_sna(output->scrn); 667428d7b3dSmrg const char *str; 668428d7b3dSmrg 669428d7b3dSmrg str = xf86GetOptValString(sna->Options, OPTION_BACKLIGHT); 670428d7b3dSmrg if (str == NULL) 671428d7b3dSmrg return NULL; 672428d7b3dSmrg 673428d7b3dSmrg DBG(("%s(%s) requested %s\n", __FUNCTION__, output->name, str)); 674428d7b3dSmrg if (*str == '\0') 675428d7b3dSmrg return (char *)str; 676428d7b3dSmrg 677428d7b3dSmrg if (backlight_exists(str) == BL_NONE) { 678428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 679428d7b3dSmrg "Unrecognised backlight control interface '%s'\n", 680428d7b3dSmrg str); 681428d7b3dSmrg return NULL; 682428d7b3dSmrg } 683428d7b3dSmrg 684428d7b3dSmrg return strdup(str); 685428d7b3dSmrg} 686428d7b3dSmrg 687428d7b3dSmrgstatic void 688428d7b3dSmrgsna_output_backlight_init(xf86OutputPtr output) 689428d7b3dSmrg{ 690428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 691428d7b3dSmrg struct pci_device *pci; 692428d7b3dSmrg MessageType from; 693428d7b3dSmrg char *best_iface; 694428d7b3dSmrg 695428d7b3dSmrg#if !USE_BACKLIGHT 696428d7b3dSmrg return; 697428d7b3dSmrg#endif 698428d7b3dSmrg 699428d7b3dSmrg from = X_CONFIG; 700428d7b3dSmrg best_iface = has_user_backlight_override(output); 701428d7b3dSmrg if (best_iface) 702428d7b3dSmrg goto done; 703428d7b3dSmrg 704428d7b3dSmrg /* XXX detect right backlight for multi-GPU/panels */ 705428d7b3dSmrg from = X_PROBED; 706428d7b3dSmrg pci = xf86GetPciInfoForEntity(to_sna(output->scrn)->pEnt->index); 707428d7b3dSmrg if (pci != NULL) 708428d7b3dSmrg best_iface = backlight_find_for_device(pci); 709428d7b3dSmrg 710428d7b3dSmrgdone: 711428d7b3dSmrg DBG(("%s(%s) opening backlight %s\n", __FUNCTION__, 712428d7b3dSmrg output->name, best_iface ?: "none")); 713428d7b3dSmrg sna_output->backlight_active_level = 714428d7b3dSmrg backlight_open(&sna_output->backlight, best_iface); 715428d7b3dSmrg DBG(("%s(%s): initial backlight value %d\n", 716428d7b3dSmrg __FUNCTION__, output->name, sna_output->backlight_active_level)); 717428d7b3dSmrg if (sna_output->backlight_active_level < 0) 718428d7b3dSmrg return; 719428d7b3dSmrg 720428d7b3dSmrg switch (sna_output->backlight.type) { 721428d7b3dSmrg case BL_FIRMWARE: best_iface = (char *)"firmware"; break; 722428d7b3dSmrg case BL_PLATFORM: best_iface = (char *)"platform"; break; 723428d7b3dSmrg case BL_RAW: best_iface = (char *)"raw"; break; 724428d7b3dSmrg default: best_iface = (char *)"unknown"; break; 725428d7b3dSmrg } 726428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, from, 727428d7b3dSmrg "Found backlight control interface %s (type '%s') for output %s\n", 728428d7b3dSmrg sna_output->backlight.iface, best_iface, output->name); 729428d7b3dSmrg} 730428d7b3dSmrg 731428d7b3dSmrgstatic char *canonical_kmode_name(const struct drm_mode_modeinfo *kmode) 732428d7b3dSmrg{ 733428d7b3dSmrg char tmp[32], *buf; 734428d7b3dSmrg int len; 735428d7b3dSmrg 736428d7b3dSmrg len = sprintf(tmp, "%dx%d%s", 737428d7b3dSmrg kmode->hdisplay, kmode->vdisplay, 738428d7b3dSmrg kmode->flags & V_INTERLACE ? "i" : ""); 739428d7b3dSmrg if ((unsigned)len >= sizeof(tmp)) 740428d7b3dSmrg return NULL; 741428d7b3dSmrg 742428d7b3dSmrg buf = malloc(len + 1); 743428d7b3dSmrg if (buf == NULL) 744428d7b3dSmrg return NULL; 745428d7b3dSmrg 746428d7b3dSmrg return memcpy(buf, tmp, len + 1); 747428d7b3dSmrg} 748428d7b3dSmrg 749428d7b3dSmrgstatic char *get_kmode_name(const struct drm_mode_modeinfo *kmode) 750428d7b3dSmrg{ 751428d7b3dSmrg if (*kmode->name == '\0') 752428d7b3dSmrg return canonical_kmode_name(kmode); 753428d7b3dSmrg 754428d7b3dSmrg return strdup(kmode->name); 755428d7b3dSmrg} 756428d7b3dSmrg 757428d7b3dSmrgstatic DisplayModePtr 758428d7b3dSmrgmode_from_kmode(ScrnInfoPtr scrn, 759428d7b3dSmrg const struct drm_mode_modeinfo *kmode, 760428d7b3dSmrg DisplayModePtr mode) 761428d7b3dSmrg{ 762428d7b3dSmrg DBG(("kmode: %s, clock=%d, %d %d %d %d %d, %d %d %d %d %d, flags=%x, type=%x\n", 763428d7b3dSmrg kmode->name, kmode->clock, 764428d7b3dSmrg kmode->hdisplay, kmode->hsync_start, kmode->hsync_end, kmode->htotal, kmode->hskew, 765428d7b3dSmrg kmode->vdisplay, kmode->vsync_start, kmode->vsync_end, kmode->vtotal, kmode->vscan, 766428d7b3dSmrg kmode->flags, kmode->type)); 767428d7b3dSmrg 768428d7b3dSmrg mode->status = MODE_OK; 769428d7b3dSmrg 770428d7b3dSmrg mode->Clock = kmode->clock; 771428d7b3dSmrg 772428d7b3dSmrg mode->HDisplay = kmode->hdisplay; 773428d7b3dSmrg mode->HSyncStart = kmode->hsync_start; 774428d7b3dSmrg mode->HSyncEnd = kmode->hsync_end; 775428d7b3dSmrg mode->HTotal = kmode->htotal; 776428d7b3dSmrg mode->HSkew = kmode->hskew; 777428d7b3dSmrg 778428d7b3dSmrg mode->VDisplay = kmode->vdisplay; 779428d7b3dSmrg mode->VSyncStart = kmode->vsync_start; 780428d7b3dSmrg mode->VSyncEnd = kmode->vsync_end; 781428d7b3dSmrg mode->VTotal = kmode->vtotal; 782428d7b3dSmrg mode->VScan = kmode->vscan; 783428d7b3dSmrg 784428d7b3dSmrg mode->Flags = kmode->flags; 785428d7b3dSmrg mode->name = get_kmode_name(kmode); 786428d7b3dSmrg 787428d7b3dSmrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 788428d7b3dSmrg mode->type = M_T_DRIVER; 789428d7b3dSmrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 790428d7b3dSmrg mode->type |= M_T_PREFERRED; 791428d7b3dSmrg 792428d7b3dSmrg if (mode->status == MODE_OK && kmode->flags & ~KNOWN_MODE_FLAGS) 793428d7b3dSmrg mode->status = MODE_BAD; /* unknown flags => unhandled */ 794428d7b3dSmrg 795428d7b3dSmrg xf86SetModeCrtc(mode, scrn->adjustFlags); 796428d7b3dSmrg return mode; 797428d7b3dSmrg} 798428d7b3dSmrg 799428d7b3dSmrgstatic void 800428d7b3dSmrgmode_to_kmode(struct drm_mode_modeinfo *kmode, DisplayModePtr mode) 801428d7b3dSmrg{ 802428d7b3dSmrg memset(kmode, 0, sizeof(*kmode)); 803428d7b3dSmrg 804428d7b3dSmrg kmode->clock = mode->Clock; 805428d7b3dSmrg kmode->hdisplay = mode->HDisplay; 806428d7b3dSmrg kmode->hsync_start = mode->HSyncStart; 807428d7b3dSmrg kmode->hsync_end = mode->HSyncEnd; 808428d7b3dSmrg kmode->htotal = mode->HTotal; 809428d7b3dSmrg kmode->hskew = mode->HSkew; 810428d7b3dSmrg 811428d7b3dSmrg kmode->vdisplay = mode->VDisplay; 812428d7b3dSmrg kmode->vsync_start = mode->VSyncStart; 813428d7b3dSmrg kmode->vsync_end = mode->VSyncEnd; 814428d7b3dSmrg kmode->vtotal = mode->VTotal; 815428d7b3dSmrg kmode->vscan = mode->VScan; 816428d7b3dSmrg 817428d7b3dSmrg kmode->flags = mode->Flags; 818428d7b3dSmrg if (mode->name) 819428d7b3dSmrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 820428d7b3dSmrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 821428d7b3dSmrg} 822428d7b3dSmrg 823428d7b3dSmrgstatic void 824428d7b3dSmrgsna_crtc_force_outputs_on(xf86CrtcPtr crtc) 825428d7b3dSmrg{ 826428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 827428d7b3dSmrg int i; 828428d7b3dSmrg 829428d7b3dSmrg assert(to_sna_crtc(crtc)); 830428d7b3dSmrg DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__, 831428d7b3dSmrg to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode)); 832428d7b3dSmrg 833428d7b3dSmrg /* DPMS handling by the kernel is inconsistent, so after setting a 834428d7b3dSmrg * mode on an output presume that we intend for it to be on, or that 835428d7b3dSmrg * the kernel will force it on. 836428d7b3dSmrg * 837428d7b3dSmrg * So force DPMS to be on for all connected outputs, and restore 838428d7b3dSmrg * the backlight. 839428d7b3dSmrg */ 840428d7b3dSmrg for (i = 0; i < config->num_output; i++) { 841428d7b3dSmrg xf86OutputPtr output = config->output[i]; 842428d7b3dSmrg 843428d7b3dSmrg if (output->crtc != crtc) 844428d7b3dSmrg continue; 845428d7b3dSmrg 846428d7b3dSmrg output->funcs->dpms(output, DPMSModeOn); 847428d7b3dSmrg } 848428d7b3dSmrg 849428d7b3dSmrg to_sna_crtc(crtc)->dpms_mode = DPMSModeOn; 850428d7b3dSmrg#if XF86_CRTC_VERSION >= 3 851428d7b3dSmrg crtc->active = TRUE; 852428d7b3dSmrg#endif 853428d7b3dSmrg} 854428d7b3dSmrg 855428d7b3dSmrgstatic void 856428d7b3dSmrgsna_crtc_force_outputs_off(xf86CrtcPtr crtc) 857428d7b3dSmrg{ 858428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 859428d7b3dSmrg int i; 860428d7b3dSmrg 861428d7b3dSmrg assert(to_sna_crtc(crtc)); 862428d7b3dSmrg DBG(("%s(pipe=%d), currently? %d\n", __FUNCTION__, 863428d7b3dSmrg to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->dpms_mode)); 864428d7b3dSmrg 865428d7b3dSmrg /* DPMS handling by the kernel is inconsistent, so after setting a 866428d7b3dSmrg * mode on an output presume that we intend for it to be on, or that 867428d7b3dSmrg * the kernel will force it on. 868428d7b3dSmrg * 869428d7b3dSmrg * So force DPMS to be on for all connected outputs, and restore 870428d7b3dSmrg * the backlight. 871428d7b3dSmrg */ 872428d7b3dSmrg for (i = 0; i < config->num_output; i++) { 873428d7b3dSmrg xf86OutputPtr output = config->output[i]; 874428d7b3dSmrg 875428d7b3dSmrg if (output->crtc != crtc) 876428d7b3dSmrg continue; 877428d7b3dSmrg 878428d7b3dSmrg output->funcs->dpms(output, DPMSModeOff); 879428d7b3dSmrg } 880428d7b3dSmrg 881428d7b3dSmrg to_sna_crtc(crtc)->dpms_mode = DPMSModeOff; 882428d7b3dSmrg} 883428d7b3dSmrg 884428d7b3dSmrgstatic unsigned 885428d7b3dSmrgrotation_reduce(struct plane *p, unsigned rotation) 886428d7b3dSmrg{ 887428d7b3dSmrg unsigned unsupported_rotations = rotation & ~p->rotation.supported; 888428d7b3dSmrg 889428d7b3dSmrg if (unsupported_rotations == 0) 890428d7b3dSmrg return rotation; 891428d7b3dSmrg 892428d7b3dSmrg#define RR_Reflect_XY (RR_Reflect_X | RR_Reflect_Y) 893428d7b3dSmrg 894428d7b3dSmrg if ((unsupported_rotations & RR_Reflect_XY) == RR_Reflect_XY && 895428d7b3dSmrg p->rotation.supported& RR_Rotate_180) { 896428d7b3dSmrg rotation &= ~RR_Reflect_XY; 897428d7b3dSmrg rotation ^= RR_Rotate_180; 898428d7b3dSmrg } 899428d7b3dSmrg 900428d7b3dSmrg if ((unsupported_rotations & RR_Rotate_180) && 901428d7b3dSmrg (p->rotation.supported& RR_Reflect_XY) == RR_Reflect_XY) { 902428d7b3dSmrg rotation ^= RR_Reflect_XY; 903428d7b3dSmrg rotation &= ~RR_Rotate_180; 904428d7b3dSmrg } 905428d7b3dSmrg 906428d7b3dSmrg#undef RR_Reflect_XY 907428d7b3dSmrg 908428d7b3dSmrg return rotation; 909428d7b3dSmrg} 910428d7b3dSmrg 911428d7b3dSmrgstatic bool 912428d7b3dSmrgrotation_set(struct sna *sna, struct plane *p, uint32_t desired) 913428d7b3dSmrg{ 914428d7b3dSmrg#define LOCAL_IOCTL_MODE_OBJ_SETPROPERTY DRM_IOWR(0xbA, struct local_mode_obj_set_property) 915428d7b3dSmrg struct local_mode_obj_set_property { 916428d7b3dSmrg uint64_t value; 917428d7b3dSmrg uint32_t prop_id; 918428d7b3dSmrg uint32_t obj_id; 919428d7b3dSmrg uint32_t obj_type; 920428d7b3dSmrg uint32_t pad; 921428d7b3dSmrg } prop; 922428d7b3dSmrg 923428d7b3dSmrg if (desired == p->rotation.current) 924428d7b3dSmrg return true; 925428d7b3dSmrg 926428d7b3dSmrg if ((desired & p->rotation.supported) == 0) { 927428d7b3dSmrg errno = EINVAL; 928428d7b3dSmrg return false; 929428d7b3dSmrg } 930428d7b3dSmrg 931428d7b3dSmrg DBG(("%s: obj=%d, type=%x prop=%d set-rotation=%x\n", 932428d7b3dSmrg __FUNCTION__, p->id, LOCAL_MODE_OBJECT_PLANE, p->rotation.prop, desired)); 933428d7b3dSmrg 934428d7b3dSmrg assert(p->id); 935428d7b3dSmrg assert(p->rotation.prop); 936428d7b3dSmrg 937428d7b3dSmrg VG_CLEAR(prop); 938428d7b3dSmrg prop.obj_id = p->id; 939428d7b3dSmrg prop.obj_type = LOCAL_MODE_OBJECT_PLANE; 940428d7b3dSmrg prop.prop_id = p->rotation.prop; 941428d7b3dSmrg prop.value = desired; 942428d7b3dSmrg 943428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_OBJ_SETPROPERTY, &prop)) 944428d7b3dSmrg return false; 945428d7b3dSmrg 946428d7b3dSmrg p->rotation.current = desired; 947428d7b3dSmrg return true; 948428d7b3dSmrg} 949428d7b3dSmrg 950428d7b3dSmrgstatic void 951428d7b3dSmrgrotation_reset(struct plane *p) 952428d7b3dSmrg{ 953428d7b3dSmrg if (p->rotation.prop == 0) 954428d7b3dSmrg return; 955428d7b3dSmrg 956428d7b3dSmrg p->rotation.current = 0; 957428d7b3dSmrg} 958428d7b3dSmrg 959428d7b3dSmrgbool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation) 960428d7b3dSmrg{ 961428d7b3dSmrg assert(to_sna_crtc(crtc)); 962428d7b3dSmrg DBG(("%s: CRTC:%d [pipe=%d], sprite=%u set-rotation=%x\n", 963428d7b3dSmrg __FUNCTION__, 964428d7b3dSmrg to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, to_sna_crtc(crtc)->sprite.id, 965428d7b3dSmrg rotation)); 966428d7b3dSmrg 967428d7b3dSmrg return rotation_set(to_sna(crtc->scrn), 968428d7b3dSmrg &to_sna_crtc(crtc)->sprite, 969428d7b3dSmrg rotation_reduce(&to_sna_crtc(crtc)->sprite, rotation)); 970428d7b3dSmrg} 971428d7b3dSmrg 972428d7b3dSmrgstatic bool 973428d7b3dSmrgsna_crtc_apply(xf86CrtcPtr crtc) 974428d7b3dSmrg{ 975428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 976428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 977428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 978428d7b3dSmrg struct drm_mode_crtc arg; 979428d7b3dSmrg uint32_t output_ids[32]; 980428d7b3dSmrg int output_count = 0; 981428d7b3dSmrg int i; 982428d7b3dSmrg 983428d7b3dSmrg DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle)); 984428d7b3dSmrg if (!sna_crtc->kmode.clock) { 985428d7b3dSmrg ERR(("%s(CRTC:%d [pipe=%d]): attempted to set an invalid mode\n", 986428d7b3dSmrg __FUNCTION__, sna_crtc->id, sna_crtc->pipe)); 987428d7b3dSmrg return false; 988428d7b3dSmrg } 989428d7b3dSmrg 990428d7b3dSmrg assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids)); 991428d7b3dSmrg sna_crtc_disable_cursor(sna, sna_crtc); 992428d7b3dSmrg 993428d7b3dSmrg if (!rotation_set(sna, &sna_crtc->primary, sna_crtc->rotation)) { 994428d7b3dSmrg ERR(("%s: set-primary-rotation failed (rotation-id=%d, rotation=%d) on CRTC:%d [pipe=%d], errno=%d\n", 995428d7b3dSmrg __FUNCTION__, sna_crtc->primary.rotation.prop, sna_crtc->rotation, sna_crtc->id, sna_crtc->pipe, errno)); 996428d7b3dSmrg sna_crtc->primary.rotation.supported &= ~sna_crtc->rotation; 997428d7b3dSmrg return false; 998428d7b3dSmrg } 999428d7b3dSmrg DBG(("%s: CRTC:%d [pipe=%d] primary rotation set to %x\n", 1000428d7b3dSmrg __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->rotation)); 1001428d7b3dSmrg 1002428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 1003428d7b3dSmrg xf86OutputPtr output = config->output[i]; 1004428d7b3dSmrg 1005428d7b3dSmrg /* Make sure we mark the output as off (and save the backlight) 1006428d7b3dSmrg * before the kernel turns it off due to changing the pipe. 1007428d7b3dSmrg * This is necessary as the kernel may turn off the backlight 1008428d7b3dSmrg * and we lose track of the user settings. 1009428d7b3dSmrg */ 1010428d7b3dSmrg if (output->crtc == NULL) 1011428d7b3dSmrg output->funcs->dpms(output, DPMSModeOff); 1012428d7b3dSmrg 1013428d7b3dSmrg if (output->crtc != crtc) 1014428d7b3dSmrg continue; 1015428d7b3dSmrg 1016428d7b3dSmrg /* Skip over any hotunplugged outputs so that we can 1017428d7b3dSmrg * recover in cases where the previous mode is now 1018428d7b3dSmrg * only partially valid. 1019428d7b3dSmrg */ 1020428d7b3dSmrg if (!to_sna_output(output)->id) 1021428d7b3dSmrg continue; 1022428d7b3dSmrg 1023428d7b3dSmrg DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n", 1024428d7b3dSmrg __FUNCTION__, output->name, i, to_connector_id(output), 1025428d7b3dSmrg sna_crtc->id, sna_crtc->pipe, 1026428d7b3dSmrg (uint32_t)output->possible_crtcs, 1027428d7b3dSmrg (uint32_t)output->possible_clones)); 1028428d7b3dSmrg 1029428d7b3dSmrg assert(output->possible_crtcs & (1 << sna_crtc->pipe) || 1030428d7b3dSmrg is_zaphod(crtc->scrn)); 1031428d7b3dSmrg 1032428d7b3dSmrg output_ids[output_count] = to_connector_id(output); 1033428d7b3dSmrg if (++output_count == ARRAY_SIZE(output_ids)) { 1034428d7b3dSmrg DBG(("%s: too many outputs (%d) for me!\n", 1035428d7b3dSmrg __FUNCTION__, output_count)); 1036428d7b3dSmrg errno = EINVAL; 1037428d7b3dSmrg return false; 1038428d7b3dSmrg } 1039428d7b3dSmrg } 1040428d7b3dSmrg if (output_count == 0) { 1041428d7b3dSmrg DBG(("%s: no outputs\n", __FUNCTION__)); 1042428d7b3dSmrg errno = EINVAL; 1043428d7b3dSmrg return false; 1044428d7b3dSmrg } 1045428d7b3dSmrg 1046428d7b3dSmrg VG_CLEAR(arg); 1047428d7b3dSmrg arg.crtc_id = sna_crtc->id; 1048428d7b3dSmrg arg.fb_id = fb_id(sna_crtc->bo); 1049428d7b3dSmrg if (sna_crtc->transform || sna_crtc->slave_pixmap) { 1050428d7b3dSmrg arg.x = 0; 1051428d7b3dSmrg arg.y = 0; 1052428d7b3dSmrg sna_crtc->offset = 0; 1053428d7b3dSmrg } else { 1054428d7b3dSmrg arg.x = crtc->x; 1055428d7b3dSmrg arg.y = crtc->y; 1056428d7b3dSmrg sna_crtc->offset = arg.y << 16 | arg.x; 1057428d7b3dSmrg } 1058428d7b3dSmrg arg.set_connectors_ptr = (uintptr_t)output_ids; 1059428d7b3dSmrg arg.count_connectors = output_count; 1060428d7b3dSmrg arg.mode = sna_crtc->kmode; 1061428d7b3dSmrg arg.mode_valid = 1; 1062428d7b3dSmrg 1063428d7b3dSmrg DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d%s%s update to %d outputs [%d...]\n", 1064428d7b3dSmrg __FUNCTION__, sna_crtc->id, sna_crtc->pipe, 1065428d7b3dSmrg arg.mode.hdisplay, 1066428d7b3dSmrg arg.mode.vdisplay, 1067428d7b3dSmrg arg.x, arg.y, 1068428d7b3dSmrg arg.mode.clock, 1069428d7b3dSmrg arg.fb_id, 1070428d7b3dSmrg sna_crtc->shadow ? " [shadow]" : "", 1071428d7b3dSmrg sna_crtc->transform ? " [transformed]" : "", 1072428d7b3dSmrg output_count, output_count ? output_ids[0] : 0)); 1073428d7b3dSmrg 1074428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg)) 1075428d7b3dSmrg return false; 1076428d7b3dSmrg 1077428d7b3dSmrg sna_crtc->mode_serial++; 1078428d7b3dSmrg sna_crtc_force_outputs_on(crtc); 1079428d7b3dSmrg return true; 1080428d7b3dSmrg} 1081428d7b3dSmrg 1082428d7b3dSmrgstatic bool overlap(const BoxRec *a, const BoxRec *b) 1083428d7b3dSmrg{ 1084428d7b3dSmrg if (a->x1 >= b->x2) 1085428d7b3dSmrg return false; 1086428d7b3dSmrg if (a->x2 <= b->x1) 1087428d7b3dSmrg return false; 1088428d7b3dSmrg 1089428d7b3dSmrg if (a->y1 >= b->y2) 1090428d7b3dSmrg return false; 1091428d7b3dSmrg if (a->y2 <= b->y1) 1092428d7b3dSmrg return false; 1093428d7b3dSmrg 1094428d7b3dSmrg return true; 1095428d7b3dSmrg} 1096428d7b3dSmrg 1097428d7b3dSmrgstatic bool wait_for_shadow(struct sna *sna, 1098428d7b3dSmrg struct sna_pixmap *priv, 1099428d7b3dSmrg unsigned flags) 1100428d7b3dSmrg{ 1101428d7b3dSmrg PixmapPtr pixmap = priv->pixmap; 1102428d7b3dSmrg DamagePtr damage; 1103428d7b3dSmrg struct kgem_bo *bo, *tmp; 1104428d7b3dSmrg int flip_active; 1105428d7b3dSmrg bool ret = true; 1106428d7b3dSmrg 1107428d7b3dSmrg DBG(("%s: flags=%x, flips=%d, handle=%d, shadow=%d\n", 1108428d7b3dSmrg __FUNCTION__, flags, sna->mode.flip_active, 1109428d7b3dSmrg priv->gpu_bo->handle, sna->mode.shadow->handle)); 1110428d7b3dSmrg 1111428d7b3dSmrg assert(priv->move_to_gpu_data == sna); 1112428d7b3dSmrg assert(sna->mode.shadow != priv->gpu_bo); 1113428d7b3dSmrg 1114428d7b3dSmrg if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_damage) 1115428d7b3dSmrg goto done; 1116428d7b3dSmrg 1117428d7b3dSmrg if ((flags & MOVE_WRITE) == 0) { 1118428d7b3dSmrg if ((flags & __MOVE_SCANOUT) == 0) { 1119428d7b3dSmrg struct sna_crtc *crtc; 1120428d7b3dSmrg 1121428d7b3dSmrg list_for_each_entry(crtc, &sna->mode.shadow_crtc, shadow_link) { 1122428d7b3dSmrg if (overlap(&sna->mode.shadow_region.extents, 1123428d7b3dSmrg &crtc->base->bounds)) { 1124428d7b3dSmrg DrawableRec draw; 1125428d7b3dSmrg RegionRec region; 1126428d7b3dSmrg 1127428d7b3dSmrg draw.width = crtc->base->mode.HDisplay; 1128428d7b3dSmrg draw.height = crtc->base->mode.VDisplay; 1129428d7b3dSmrg draw.depth = sna->front->drawable.depth; 1130428d7b3dSmrg draw.bitsPerPixel = sna->front->drawable.bitsPerPixel; 1131428d7b3dSmrg 1132428d7b3dSmrg DBG(("%s: copying replaced CRTC: (%d, %d), (%d, %d), handle=%d\n", 1133428d7b3dSmrg __FUNCTION__, 1134428d7b3dSmrg crtc->base->bounds.x1, 1135428d7b3dSmrg crtc->base->bounds.y1, 1136428d7b3dSmrg crtc->base->bounds.x2, 1137428d7b3dSmrg crtc->base->bounds.y2, 1138428d7b3dSmrg crtc->client_bo->handle)); 1139428d7b3dSmrg 1140428d7b3dSmrg ret &= sna->render.copy_boxes(sna, GXcopy, 1141428d7b3dSmrg &draw, crtc->client_bo, -crtc->base->bounds.x1, -crtc->base->bounds.y1, 1142428d7b3dSmrg &pixmap->drawable, priv->gpu_bo, 0, 0, 1143428d7b3dSmrg &crtc->base->bounds, 1, 1144428d7b3dSmrg 0); 1145428d7b3dSmrg 1146428d7b3dSmrg region.extents = crtc->base->bounds; 1147428d7b3dSmrg region.data = NULL; 1148428d7b3dSmrg RegionSubtract(&sna->mode.shadow_region, &sna->mode.shadow_region, ®ion); 1149428d7b3dSmrg } 1150428d7b3dSmrg } 1151428d7b3dSmrg } 1152428d7b3dSmrg 1153428d7b3dSmrg return ret; 1154428d7b3dSmrg } 1155428d7b3dSmrg 1156428d7b3dSmrg assert(sna->mode.shadow_active); 1157428d7b3dSmrg 1158428d7b3dSmrg damage = sna->mode.shadow_damage; 1159428d7b3dSmrg sna->mode.shadow_damage = NULL; 1160428d7b3dSmrg 1161428d7b3dSmrg flip_active = sna->mode.flip_active; 1162428d7b3dSmrg if (flip_active) { 1163428d7b3dSmrg struct sna_crtc *crtc; 1164428d7b3dSmrg list_for_each_entry(crtc, &sna->mode.shadow_crtc, shadow_link) 1165428d7b3dSmrg flip_active -= crtc->flip_pending; 1166428d7b3dSmrg DBG(("%s: %d flips still pending, shadow flip_active=%d\n", 1167428d7b3dSmrg __FUNCTION__, sna->mode.flip_active, flip_active)); 1168428d7b3dSmrg } 1169428d7b3dSmrg if (flip_active) { 1170428d7b3dSmrg /* raw cmd to avoid setting wedged in the middle of an op */ 1171428d7b3dSmrg drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_THROTTLE, 0); 1172428d7b3dSmrg sna->kgem.need_throttle = false; 1173428d7b3dSmrg 1174428d7b3dSmrg while (flip_active && sna_mode_wakeup(sna)) { 1175428d7b3dSmrg struct sna_crtc *crtc; 1176428d7b3dSmrg 1177428d7b3dSmrg flip_active = sna->mode.flip_active; 1178428d7b3dSmrg list_for_each_entry(crtc, &sna->mode.shadow_crtc, shadow_link) 1179428d7b3dSmrg flip_active -= crtc->flip_pending; 1180428d7b3dSmrg } 1181428d7b3dSmrg DBG(("%s: after waiting %d flips outstanding, flip_active=%d\n", 1182428d7b3dSmrg __FUNCTION__, sna->mode.flip_active, flip_active)); 1183428d7b3dSmrg } 1184428d7b3dSmrg 1185428d7b3dSmrg bo = sna->mode.shadow; 1186428d7b3dSmrg if (flip_active) { 1187428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 1188428d7b3dSmrg pixmap->drawable.width, 1189428d7b3dSmrg pixmap->drawable.height, 1190428d7b3dSmrg pixmap->drawable.bitsPerPixel, 1191428d7b3dSmrg priv->gpu_bo->tiling, 1192428d7b3dSmrg CREATE_EXACT | CREATE_SCANOUT); 1193428d7b3dSmrg if (bo != NULL) { 1194428d7b3dSmrg DBG(("%s: replacing still-attached GPU bo handle=%d, flips=%d\n", 1195428d7b3dSmrg __FUNCTION__, priv->gpu_bo->tiling, sna->mode.flip_active)); 1196428d7b3dSmrg 1197428d7b3dSmrg RegionUninit(&sna->mode.shadow_region); 1198428d7b3dSmrg sna->mode.shadow_region.extents.x1 = 0; 1199428d7b3dSmrg sna->mode.shadow_region.extents.y1 = 0; 1200428d7b3dSmrg sna->mode.shadow_region.extents.x2 = pixmap->drawable.width; 1201428d7b3dSmrg sna->mode.shadow_region.extents.y2 = pixmap->drawable.height; 1202428d7b3dSmrg sna->mode.shadow_region.data = NULL; 1203428d7b3dSmrg } else { 1204428d7b3dSmrg while (sna->mode.flip_active && 1205428d7b3dSmrg sna_mode_wait_for_event(sna)) 1206428d7b3dSmrg sna_mode_wakeup(sna); 1207428d7b3dSmrg 1208428d7b3dSmrg bo = sna->mode.shadow; 1209428d7b3dSmrg } 1210428d7b3dSmrg } 1211428d7b3dSmrg 1212428d7b3dSmrg if (bo->refcnt > 1) { 1213428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 1214428d7b3dSmrg pixmap->drawable.width, 1215428d7b3dSmrg pixmap->drawable.height, 1216428d7b3dSmrg pixmap->drawable.bitsPerPixel, 1217428d7b3dSmrg priv->gpu_bo->tiling, 1218428d7b3dSmrg CREATE_EXACT | CREATE_SCANOUT); 1219428d7b3dSmrg if (bo != NULL) { 1220428d7b3dSmrg DBG(("%s: replacing exported GPU bo\n", 1221428d7b3dSmrg __FUNCTION__)); 1222428d7b3dSmrg 1223428d7b3dSmrg RegionUninit(&sna->mode.shadow_region); 1224428d7b3dSmrg sna->mode.shadow_region.extents.x1 = 0; 1225428d7b3dSmrg sna->mode.shadow_region.extents.y1 = 0; 1226428d7b3dSmrg sna->mode.shadow_region.extents.x2 = pixmap->drawable.width; 1227428d7b3dSmrg sna->mode.shadow_region.extents.y2 = pixmap->drawable.height; 1228428d7b3dSmrg sna->mode.shadow_region.data = NULL; 1229428d7b3dSmrg } else 1230428d7b3dSmrg bo = sna->mode.shadow; 1231428d7b3dSmrg } 1232428d7b3dSmrg 1233428d7b3dSmrg sna->mode.shadow_damage = damage; 1234428d7b3dSmrg 1235428d7b3dSmrg RegionSubtract(&sna->mode.shadow_region, 1236428d7b3dSmrg &sna->mode.shadow_region, 1237428d7b3dSmrg &sna->mode.shadow_cancel); 1238428d7b3dSmrg 1239428d7b3dSmrg while (!list_is_empty(&sna->mode.shadow_crtc)) { 1240428d7b3dSmrg struct sna_crtc *crtc = 1241428d7b3dSmrg list_first_entry(&sna->mode.shadow_crtc, struct sna_crtc, shadow_link); 1242428d7b3dSmrg if (overlap(&crtc->base->bounds, 1243428d7b3dSmrg &sna->mode.shadow_region.extents)) { 1244428d7b3dSmrg RegionRec region; 1245428d7b3dSmrg DrawableRec draw; 1246428d7b3dSmrg 1247428d7b3dSmrg draw.width = crtc->base->mode.HDisplay; 1248428d7b3dSmrg draw.height = crtc->base->mode.VDisplay; 1249428d7b3dSmrg draw.depth = sna->front->drawable.depth; 1250428d7b3dSmrg draw.bitsPerPixel = sna->front->drawable.bitsPerPixel; 1251428d7b3dSmrg 1252428d7b3dSmrg DBG(("%s: copying replaced CRTC: (%d, %d), (%d, %d), handle=%d\n", 1253428d7b3dSmrg __FUNCTION__, 1254428d7b3dSmrg crtc->base->bounds.x1, 1255428d7b3dSmrg crtc->base->bounds.y1, 1256428d7b3dSmrg crtc->base->bounds.x2, 1257428d7b3dSmrg crtc->base->bounds.y2, 1258428d7b3dSmrg crtc->client_bo->handle)); 1259428d7b3dSmrg 1260428d7b3dSmrg ret = sna->render.copy_boxes(sna, GXcopy, 1261428d7b3dSmrg &draw, crtc->client_bo, -crtc->base->bounds.x1, -crtc->base->bounds.y1, 1262428d7b3dSmrg &pixmap->drawable, bo, 0, 0, 1263428d7b3dSmrg &crtc->base->bounds, 1, 1264428d7b3dSmrg 0); 1265428d7b3dSmrg 1266428d7b3dSmrg 1267428d7b3dSmrg region.extents = crtc->base->bounds; 1268428d7b3dSmrg region.data = NULL; 1269428d7b3dSmrg RegionSubtract(&sna->mode.shadow_region, &sna->mode.shadow_region, ®ion); 1270428d7b3dSmrg } 1271428d7b3dSmrg 1272428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->client_bo); 1273428d7b3dSmrg crtc->client_bo = NULL; 1274428d7b3dSmrg list_del(&crtc->shadow_link); 1275428d7b3dSmrg } 1276428d7b3dSmrg 1277428d7b3dSmrg if (RegionNotEmpty(&sna->mode.shadow_region)) { 1278428d7b3dSmrg DBG(("%s: copying existing GPU damage: %dx(%d, %d), (%d, %d)\n", 1279428d7b3dSmrg __FUNCTION__, region_num_rects(&sna->mode.shadow_region), 1280428d7b3dSmrg sna->mode.shadow_region.extents.x1, 1281428d7b3dSmrg sna->mode.shadow_region.extents.y1, 1282428d7b3dSmrg sna->mode.shadow_region.extents.x2, 1283428d7b3dSmrg sna->mode.shadow_region.extents.y2)); 1284428d7b3dSmrg ret = sna->render.copy_boxes(sna, GXcopy, 1285428d7b3dSmrg &pixmap->drawable, priv->gpu_bo, 0, 0, 1286428d7b3dSmrg &pixmap->drawable, bo, 0, 0, 1287428d7b3dSmrg region_rects(&sna->mode.shadow_region), 1288428d7b3dSmrg region_num_rects(&sna->mode.shadow_region), 1289428d7b3dSmrg 0); 1290428d7b3dSmrg } 1291428d7b3dSmrg 1292428d7b3dSmrg if (priv->cow) 1293428d7b3dSmrg sna_pixmap_undo_cow(sna, priv, 0); 1294428d7b3dSmrg 1295428d7b3dSmrg sna_pixmap_unmap(pixmap, priv); 1296428d7b3dSmrg 1297428d7b3dSmrg DBG(("%s: setting front pixmap to handle=%d\n", __FUNCTION__, bo->handle)); 1298428d7b3dSmrg tmp = priv->gpu_bo; 1299428d7b3dSmrg priv->gpu_bo = bo; 1300428d7b3dSmrg if (bo != sna->mode.shadow) 1301428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna->mode.shadow); 1302428d7b3dSmrg sna->mode.shadow = tmp; 1303428d7b3dSmrg 1304428d7b3dSmrg sna_dri2_pixmap_update_bo(sna, pixmap, bo); 1305428d7b3dSmrg 1306428d7b3dSmrgdone: 1307428d7b3dSmrg RegionEmpty(&sna->mode.shadow_cancel); 1308428d7b3dSmrg RegionEmpty(&sna->mode.shadow_region); 1309428d7b3dSmrg sna->mode.shadow_dirty = false; 1310428d7b3dSmrg 1311428d7b3dSmrg priv->move_to_gpu_data = NULL; 1312428d7b3dSmrg priv->move_to_gpu = NULL; 1313428d7b3dSmrg 1314428d7b3dSmrg return ret; 1315428d7b3dSmrg} 1316428d7b3dSmrg 1317428d7b3dSmrgbool sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv, 1318428d7b3dSmrg const RegionRec *region) 1319428d7b3dSmrg{ 1320428d7b3dSmrg struct sna *sna; 1321428d7b3dSmrg 1322428d7b3dSmrg if (priv->move_to_gpu != wait_for_shadow) 1323428d7b3dSmrg return false; 1324428d7b3dSmrg 1325428d7b3dSmrg sna = priv->move_to_gpu_data; 1326428d7b3dSmrg if (region) { 1327428d7b3dSmrg DBG(("%s: discarding region %dx[(%d, %d), (%d, %d)] from damage %dx[(%d, %d], (%d, %d)]\n", 1328428d7b3dSmrg __FUNCTION__, 1329428d7b3dSmrg region_num_rects(region), 1330428d7b3dSmrg region->extents.x1, region->extents.y1, 1331428d7b3dSmrg region->extents.x2, region->extents.y2, 1332428d7b3dSmrg region_num_rects(&sna->mode.shadow_region), 1333428d7b3dSmrg sna->mode.shadow_region.extents.x1, sna->mode.shadow_region.extents.y1, 1334428d7b3dSmrg sna->mode.shadow_region.extents.x2, sna->mode.shadow_region.extents.y2)); 1335428d7b3dSmrg 1336428d7b3dSmrg RegionSubtract(&sna->mode.shadow_region, 1337428d7b3dSmrg &sna->mode.shadow_region, 1338428d7b3dSmrg (RegionPtr)region); 1339428d7b3dSmrg RegionUnion(&sna->mode.shadow_cancel, 1340428d7b3dSmrg &sna->mode.shadow_cancel, 1341428d7b3dSmrg (RegionPtr)region); 1342428d7b3dSmrg } else { 1343428d7b3dSmrg DBG(("%s: discarding all damage %dx[(%d, %d], (%d, %d)]\n", 1344428d7b3dSmrg __FUNCTION__, 1345428d7b3dSmrg region_num_rects(&sna->mode.shadow_region), 1346428d7b3dSmrg sna->mode.shadow_region.extents.x1, sna->mode.shadow_region.extents.y1, 1347428d7b3dSmrg sna->mode.shadow_region.extents.x2, sna->mode.shadow_region.extents.y2)); 1348428d7b3dSmrg RegionEmpty(&sna->mode.shadow_region); 1349428d7b3dSmrg 1350428d7b3dSmrg RegionUninit(&sna->mode.shadow_cancel); 1351428d7b3dSmrg sna->mode.shadow_cancel.extents.x1 = 0; 1352428d7b3dSmrg sna->mode.shadow_cancel.extents.y1 = 0; 1353428d7b3dSmrg sna->mode.shadow_cancel.extents.x2 = sna->front->drawable.width; 1354428d7b3dSmrg sna->mode.shadow_cancel.extents.y2 = sna->front->drawable.height; 1355428d7b3dSmrg sna->mode.shadow_cancel.data = NULL; 1356428d7b3dSmrg } 1357428d7b3dSmrg 1358428d7b3dSmrg return RegionNil(&sna->mode.shadow_region); 1359428d7b3dSmrg} 1360428d7b3dSmrg 1361428d7b3dSmrgstatic bool sna_mode_enable_shadow(struct sna *sna) 1362428d7b3dSmrg{ 1363428d7b3dSmrg ScreenPtr screen = sna->scrn->pScreen; 1364428d7b3dSmrg 1365428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 1366428d7b3dSmrg assert(sna->mode.shadow == NULL); 1367428d7b3dSmrg assert(sna->mode.shadow_damage == NULL); 1368428d7b3dSmrg assert(sna->mode.shadow_active == 0); 1369428d7b3dSmrg 1370428d7b3dSmrg sna->mode.shadow_damage = DamageCreate(NULL, NULL, 1371428d7b3dSmrg DamageReportNone, TRUE, 1372428d7b3dSmrg screen, screen); 1373428d7b3dSmrg if (!sna->mode.shadow_damage) 1374428d7b3dSmrg return false; 1375428d7b3dSmrg 1376428d7b3dSmrg DamageRegister(&sna->front->drawable, sna->mode.shadow_damage); 1377428d7b3dSmrg return true; 1378428d7b3dSmrg} 1379428d7b3dSmrg 1380428d7b3dSmrgstatic void sna_mode_disable_shadow(struct sna *sna) 1381428d7b3dSmrg{ 1382428d7b3dSmrg struct sna_pixmap *priv; 1383428d7b3dSmrg 1384428d7b3dSmrg if (!sna->mode.shadow_damage) 1385428d7b3dSmrg return; 1386428d7b3dSmrg 1387428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 1388428d7b3dSmrg 1389428d7b3dSmrg priv = sna_pixmap(sna->front); 1390428d7b3dSmrg if (priv->move_to_gpu == wait_for_shadow) 1391428d7b3dSmrg priv->move_to_gpu(sna, priv, 0); 1392428d7b3dSmrg 1393428d7b3dSmrg DamageUnregister(&sna->front->drawable, sna->mode.shadow_damage); 1394428d7b3dSmrg DamageDestroy(sna->mode.shadow_damage); 1395428d7b3dSmrg sna->mode.shadow_damage = NULL; 1396428d7b3dSmrg 1397428d7b3dSmrg if (sna->mode.shadow) { 1398428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna->mode.shadow); 1399428d7b3dSmrg sna->mode.shadow = NULL; 1400428d7b3dSmrg } 1401428d7b3dSmrg 1402428d7b3dSmrg assert(sna->mode.shadow_active == 0); 1403428d7b3dSmrg sna->mode.shadow_dirty = false; 1404428d7b3dSmrg} 1405428d7b3dSmrg 1406428d7b3dSmrgstatic void sna_crtc_slave_damage(DamagePtr damage, RegionPtr region, void *closure) 1407428d7b3dSmrg{ 1408428d7b3dSmrg struct sna_crtc *crtc = closure; 1409428d7b3dSmrg struct sna *sna = to_sna(crtc->base->scrn); 1410428d7b3dSmrg RegionPtr scr; 1411428d7b3dSmrg 1412428d7b3dSmrg DBG(("%s: pushing damage [(%d, %d), (%d, %d) x %d] to CRTC [pipe=%d] (%d, %d)\n", 1413428d7b3dSmrg __FUNCTION__, 1414428d7b3dSmrg region->extents.x1, region->extents.y1, region->extents.x2, region->extents.y2, 1415428d7b3dSmrg region_num_rects(region), 1416428d7b3dSmrg crtc->pipe, crtc->base->x, crtc->base->y)); 1417428d7b3dSmrg 1418428d7b3dSmrg assert(crtc->slave_damage == damage); 1419428d7b3dSmrg assert(sna->mode.shadow_damage); 1420428d7b3dSmrg 1421428d7b3dSmrg RegionTranslate(region, crtc->base->x, crtc->base->y); 1422428d7b3dSmrg scr = DamageRegion(sna->mode.shadow_damage); 1423428d7b3dSmrg RegionUnion(scr, scr, region); 1424428d7b3dSmrg RegionTranslate(region, -crtc->base->x, -crtc->base->y); 1425428d7b3dSmrg} 1426428d7b3dSmrg 1427428d7b3dSmrgstatic bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc) 1428428d7b3dSmrg{ 1429428d7b3dSmrg if (crtc->shadow) { 1430428d7b3dSmrg assert(sna->mode.shadow_damage && sna->mode.shadow_active); 1431428d7b3dSmrg return true; 1432428d7b3dSmrg } 1433428d7b3dSmrg 1434428d7b3dSmrg DBG(("%s: enabling for crtc %d\n", __FUNCTION__, crtc->id)); 1435428d7b3dSmrg 1436428d7b3dSmrg if (!sna->mode.shadow_active) { 1437428d7b3dSmrg if (!sna_mode_enable_shadow(sna)) 1438428d7b3dSmrg return false; 1439428d7b3dSmrg assert(sna->mode.shadow_damage); 1440428d7b3dSmrg assert(sna->mode.shadow == NULL); 1441428d7b3dSmrg } 1442428d7b3dSmrg 1443428d7b3dSmrg if (crtc->slave_pixmap) { 1444428d7b3dSmrg assert(crtc->slave_damage == NULL); 1445428d7b3dSmrg 1446428d7b3dSmrg crtc->slave_damage = DamageCreate(sna_crtc_slave_damage, NULL, 1447428d7b3dSmrg DamageReportRawRegion, TRUE, 1448428d7b3dSmrg sna->scrn->pScreen, crtc); 1449428d7b3dSmrg if (crtc->slave_damage == NULL) { 1450428d7b3dSmrg if (!--sna->mode.shadow_active) 1451428d7b3dSmrg sna_mode_disable_shadow(sna); 1452428d7b3dSmrg return false; 1453428d7b3dSmrg } 1454428d7b3dSmrg 1455428d7b3dSmrg DamageRegister(&crtc->slave_pixmap->drawable, crtc->slave_damage); 1456428d7b3dSmrg } 1457428d7b3dSmrg 1458428d7b3dSmrg crtc->shadow = true; 1459428d7b3dSmrg sna->mode.shadow_active++; 1460428d7b3dSmrg return true; 1461428d7b3dSmrg} 1462428d7b3dSmrg 1463428d7b3dSmrgstatic void sna_crtc_disable_override(struct sna *sna, struct sna_crtc *crtc) 1464428d7b3dSmrg{ 1465428d7b3dSmrg if (crtc->client_bo == NULL) 1466428d7b3dSmrg return; 1467428d7b3dSmrg 1468428d7b3dSmrg if (!crtc->transform) { 1469428d7b3dSmrg DrawableRec tmp; 1470428d7b3dSmrg 1471428d7b3dSmrg tmp.width = crtc->base->mode.HDisplay; 1472428d7b3dSmrg tmp.height = crtc->base->mode.VDisplay; 1473428d7b3dSmrg tmp.depth = sna->front->drawable.depth; 1474428d7b3dSmrg tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel; 1475428d7b3dSmrg 1476428d7b3dSmrg sna->render.copy_boxes(sna, GXcopy, 1477428d7b3dSmrg &tmp, crtc->client_bo, -crtc->base->bounds.x1, -crtc->base->bounds.y1, 1478428d7b3dSmrg &sna->front->drawable, __sna_pixmap_get_bo(sna->front), 0, 0, 1479428d7b3dSmrg &crtc->base->bounds, 1, 0); 1480428d7b3dSmrg list_del(&crtc->shadow_link); 1481428d7b3dSmrg } 1482428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->client_bo); 1483428d7b3dSmrg crtc->client_bo = NULL; 1484428d7b3dSmrg} 1485428d7b3dSmrg 1486428d7b3dSmrgstatic void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc) 1487428d7b3dSmrg{ 1488428d7b3dSmrg crtc->fallback_shadow = false; 1489428d7b3dSmrg if (!crtc->shadow) 1490428d7b3dSmrg return; 1491428d7b3dSmrg 1492428d7b3dSmrg DBG(("%s: disabling for crtc %d\n", __FUNCTION__, crtc->id)); 1493428d7b3dSmrg assert(sna->mode.shadow_active > 0); 1494428d7b3dSmrg 1495428d7b3dSmrg if (crtc->slave_damage) { 1496428d7b3dSmrg assert(crtc->slave_pixmap); 1497428d7b3dSmrg DamageUnregister(&crtc->slave_pixmap->drawable, crtc->slave_damage); 1498428d7b3dSmrg DamageDestroy(crtc->slave_damage); 1499428d7b3dSmrg crtc->slave_damage = NULL; 1500428d7b3dSmrg } 1501428d7b3dSmrg 1502428d7b3dSmrg sna_crtc_disable_override(sna, crtc); 1503428d7b3dSmrg 1504428d7b3dSmrg if (!--sna->mode.shadow_active) 1505428d7b3dSmrg sna_mode_disable_shadow(sna); 1506428d7b3dSmrg 1507428d7b3dSmrg crtc->shadow = false; 1508428d7b3dSmrg} 1509428d7b3dSmrg 1510428d7b3dSmrgstatic void 1511428d7b3dSmrg__sna_crtc_disable(struct sna *sna, struct sna_crtc *sna_crtc) 1512428d7b3dSmrg{ 1513428d7b3dSmrg sna_crtc->mode_serial++; 1514428d7b3dSmrg 1515428d7b3dSmrg sna_crtc_disable_cursor(sna, sna_crtc); 1516428d7b3dSmrg rotation_set(sna, &sna_crtc->primary, RR_Rotate_0); 1517428d7b3dSmrg sna_crtc_disable_shadow(sna, sna_crtc); 1518428d7b3dSmrg 1519428d7b3dSmrg if (sna_crtc->bo) { 1520428d7b3dSmrg assert(sna_crtc->bo->active_scanout); 1521428d7b3dSmrg assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout); 1522428d7b3dSmrg sna_crtc->bo->active_scanout--; 1523428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna_crtc->bo); 1524428d7b3dSmrg sna_crtc->bo = NULL; 1525428d7b3dSmrg 1526428d7b3dSmrg assert(sna->mode.front_active); 1527428d7b3dSmrg sna->mode.front_active--; 1528428d7b3dSmrg sna->mode.dirty = true; 1529428d7b3dSmrg } 1530428d7b3dSmrg 1531428d7b3dSmrg if (sna_crtc->shadow_bo) { 1532428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna_crtc->shadow_bo); 1533428d7b3dSmrg sna_crtc->shadow_bo = NULL; 1534428d7b3dSmrg } 1535428d7b3dSmrg sna_crtc->transform = false; 1536428d7b3dSmrg 1537428d7b3dSmrg assert(!sna_crtc->shadow); 1538428d7b3dSmrg} 1539428d7b3dSmrg 1540428d7b3dSmrgstatic void 1541428d7b3dSmrgsna_crtc_disable(xf86CrtcPtr crtc) 1542428d7b3dSmrg{ 1543428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 1544428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 1545428d7b3dSmrg struct drm_mode_crtc arg; 1546428d7b3dSmrg 1547428d7b3dSmrg if (sna_crtc == NULL) 1548428d7b3dSmrg return; 1549428d7b3dSmrg 1550428d7b3dSmrg DBG(("%s: disabling crtc [%d, pipe=%d]\n", __FUNCTION__, 1551428d7b3dSmrg sna_crtc->id, sna_crtc->pipe)); 1552428d7b3dSmrg 1553428d7b3dSmrg sna_crtc_force_outputs_off(crtc); 1554428d7b3dSmrg assert(sna_crtc->dpms_mode == DPMSModeOff); 1555428d7b3dSmrg 1556428d7b3dSmrg memset(&arg, 0, sizeof(arg)); 1557428d7b3dSmrg arg.crtc_id = sna_crtc->id; 1558428d7b3dSmrg (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg); 1559428d7b3dSmrg 1560428d7b3dSmrg __sna_crtc_disable(sna, sna_crtc); 1561428d7b3dSmrg} 1562428d7b3dSmrg 1563428d7b3dSmrgstatic void update_flush_interval(struct sna *sna) 1564428d7b3dSmrg{ 1565428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 1566428d7b3dSmrg int i, max_vrefresh = 0; 1567428d7b3dSmrg 1568428d7b3dSmrg DBG(("%s: front_active=%d\n", __FUNCTION__, sna->mode.front_active)); 1569428d7b3dSmrg 1570428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 1571428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 1572428d7b3dSmrg 1573428d7b3dSmrg assert(to_sna_crtc(crtc) != NULL); 1574428d7b3dSmrg 1575428d7b3dSmrg if (!crtc->enabled) { 1576428d7b3dSmrg DBG(("%s: CRTC:%d (pipe %d) disabled\n", 1577428d7b3dSmrg __FUNCTION__,i, to_sna_crtc(crtc)->pipe)); 1578428d7b3dSmrg assert(to_sna_crtc(crtc)->bo == NULL); 1579428d7b3dSmrg continue; 1580428d7b3dSmrg } 1581428d7b3dSmrg 1582428d7b3dSmrg if (to_sna_crtc(crtc)->dpms_mode != DPMSModeOn) { 1583428d7b3dSmrg DBG(("%s: CRTC:%d (pipe %d) turned off\n", 1584428d7b3dSmrg __FUNCTION__,i, to_sna_crtc(crtc)->pipe)); 1585428d7b3dSmrg continue; 1586428d7b3dSmrg } 1587428d7b3dSmrg 1588428d7b3dSmrg DBG(("%s: CRTC:%d (pipe %d) vrefresh=%f\n", 1589428d7b3dSmrg __FUNCTION__, i, to_sna_crtc(crtc)->pipe, 1590428d7b3dSmrg xf86ModeVRefresh(&crtc->mode))); 1591428d7b3dSmrg max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(&crtc->mode)); 1592428d7b3dSmrg } 1593428d7b3dSmrg 1594428d7b3dSmrg if (max_vrefresh == 0) { 1595428d7b3dSmrg assert(sna->mode.front_active == 0); 1596428d7b3dSmrg sna->vblank_interval = 0; 1597428d7b3dSmrg } else 1598428d7b3dSmrg sna->vblank_interval = 1000 / max_vrefresh; /* Hz -> ms */ 1599428d7b3dSmrg 1600428d7b3dSmrg DBG(("max_vrefresh=%d, vblank_interval=%d ms\n", 1601428d7b3dSmrg max_vrefresh, sna->vblank_interval)); 1602428d7b3dSmrg} 1603428d7b3dSmrg 1604428d7b3dSmrgstatic struct kgem_bo *sna_create_bo_for_fbcon(struct sna *sna, 1605428d7b3dSmrg const struct drm_mode_fb_cmd *fbcon) 1606428d7b3dSmrg{ 1607428d7b3dSmrg struct drm_gem_flink flink; 1608428d7b3dSmrg struct kgem_bo *bo; 1609428d7b3dSmrg int ret; 1610428d7b3dSmrg 1611428d7b3dSmrg /* Create a new reference for the fbcon so that we can track it 1612428d7b3dSmrg * using a normal bo and so that when we call gem_close on it we 1613428d7b3dSmrg * delete our reference and not fbcon's! 1614428d7b3dSmrg */ 1615428d7b3dSmrg VG_CLEAR(flink); 1616428d7b3dSmrg flink.handle = fbcon->handle; 1617428d7b3dSmrg ret = drmIoctl(sna->kgem.fd, DRM_IOCTL_GEM_FLINK, &flink); 1618428d7b3dSmrg if (ret) 1619428d7b3dSmrg return NULL; 1620428d7b3dSmrg 1621428d7b3dSmrg bo = kgem_create_for_name(&sna->kgem, flink.name); 1622428d7b3dSmrg if (bo == NULL) 1623428d7b3dSmrg return NULL; 1624428d7b3dSmrg 1625428d7b3dSmrg bo->pitch = fbcon->pitch; 1626428d7b3dSmrg return bo; 1627428d7b3dSmrg} 1628428d7b3dSmrg 1629428d7b3dSmrg/* Copy the current framebuffer contents into the front-buffer for a seamless 1630428d7b3dSmrg * transition from e.g. plymouth. 1631428d7b3dSmrg */ 1632428d7b3dSmrgvoid sna_copy_fbcon(struct sna *sna) 1633428d7b3dSmrg{ 1634428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 1635428d7b3dSmrg struct drm_mode_fb_cmd fbcon; 1636428d7b3dSmrg PixmapRec scratch; 1637428d7b3dSmrg struct sna_pixmap *priv; 1638428d7b3dSmrg struct kgem_bo *bo; 1639428d7b3dSmrg BoxRec box; 1640428d7b3dSmrg bool ok; 1641428d7b3dSmrg int sx, sy; 1642428d7b3dSmrg int dx, dy; 1643428d7b3dSmrg int i; 1644428d7b3dSmrg 1645428d7b3dSmrg if (wedged(sna)) 1646428d7b3dSmrg return; 1647428d7b3dSmrg 1648428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 1649428d7b3dSmrg assert((sna->flags & SNA_IS_HOSTED) == 0); 1650428d7b3dSmrg 1651428d7b3dSmrg priv = sna_pixmap_move_to_gpu(sna->front, MOVE_WRITE | __MOVE_SCANOUT); 1652428d7b3dSmrg if (priv == NULL) 1653428d7b3dSmrg return; 1654428d7b3dSmrg 1655428d7b3dSmrg /* Scan the connectors for a framebuffer and assume that is the fbcon */ 1656428d7b3dSmrg VG_CLEAR(fbcon); 1657428d7b3dSmrg fbcon.fb_id = 0; 1658428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 1659428d7b3dSmrg struct sna_crtc *crtc = to_sna_crtc(config->crtc[i]); 1660428d7b3dSmrg struct drm_mode_crtc mode; 1661428d7b3dSmrg 1662428d7b3dSmrg assert(crtc != NULL); 1663428d7b3dSmrg 1664428d7b3dSmrg VG_CLEAR(mode); 1665428d7b3dSmrg mode.crtc_id = crtc->id; 1666428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode)) 1667428d7b3dSmrg continue; 1668428d7b3dSmrg if (!mode.fb_id) 1669428d7b3dSmrg continue; 1670428d7b3dSmrg 1671428d7b3dSmrg fbcon.fb_id = mode.fb_id; 1672428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETFB, &fbcon)) { 1673428d7b3dSmrg fbcon.fb_id = 0; 1674428d7b3dSmrg continue; 1675428d7b3dSmrg } 1676428d7b3dSmrg break; 1677428d7b3dSmrg } 1678428d7b3dSmrg if (fbcon.fb_id == 0) { 1679428d7b3dSmrg DBG(("%s: no fbcon found\n", __FUNCTION__)); 1680428d7b3dSmrg return; 1681428d7b3dSmrg } 1682428d7b3dSmrg 1683428d7b3dSmrg if (fbcon.fb_id == fb_id(priv->gpu_bo)) { 1684428d7b3dSmrg DBG(("%s: fb already installed as scanout\n", __FUNCTION__)); 1685428d7b3dSmrg return; 1686428d7b3dSmrg } 1687428d7b3dSmrg 1688428d7b3dSmrg DBG(("%s: found fbcon, size=%dx%d, depth=%d, bpp=%d\n", 1689428d7b3dSmrg __FUNCTION__, fbcon.width, fbcon.height, fbcon.depth, fbcon.bpp)); 1690428d7b3dSmrg 1691428d7b3dSmrg bo = sna_create_bo_for_fbcon(sna, &fbcon); 1692428d7b3dSmrg if (bo == NULL) 1693428d7b3dSmrg return; 1694428d7b3dSmrg 1695428d7b3dSmrg DBG(("%s: fbcon handle=%d\n", __FUNCTION__, bo->handle)); 1696428d7b3dSmrg 1697428d7b3dSmrg scratch.drawable.width = fbcon.width; 1698428d7b3dSmrg scratch.drawable.height = fbcon.height; 1699428d7b3dSmrg scratch.drawable.depth = fbcon.depth; 1700428d7b3dSmrg scratch.drawable.bitsPerPixel = fbcon.bpp; 1701428d7b3dSmrg scratch.devPrivate.ptr = NULL; 1702428d7b3dSmrg 1703428d7b3dSmrg box.x1 = box.y1 = 0; 1704428d7b3dSmrg box.x2 = min(fbcon.width, sna->front->drawable.width); 1705428d7b3dSmrg box.y2 = min(fbcon.height, sna->front->drawable.height); 1706428d7b3dSmrg 1707428d7b3dSmrg sx = dx = 0; 1708428d7b3dSmrg if (box.x2 < (uint16_t)fbcon.width) 1709428d7b3dSmrg sx = (fbcon.width - box.x2) / 2; 1710428d7b3dSmrg if (box.x2 < sna->front->drawable.width) 1711428d7b3dSmrg dx = (sna->front->drawable.width - box.x2) / 2; 1712428d7b3dSmrg 1713428d7b3dSmrg sy = dy = 0; 1714428d7b3dSmrg if (box.y2 < (uint16_t)fbcon.height) 1715428d7b3dSmrg sy = (fbcon.height - box.y2) / 2; 1716428d7b3dSmrg if (box.y2 < sna->front->drawable.height) 1717428d7b3dSmrg dy = (sna->front->drawable.height - box.y2) / 2; 1718428d7b3dSmrg 1719428d7b3dSmrg ok = sna->render.copy_boxes(sna, GXcopy, 1720428d7b3dSmrg &scratch.drawable, bo, sx, sy, 1721428d7b3dSmrg &sna->front->drawable, priv->gpu_bo, dx, dy, 1722428d7b3dSmrg &box, 1, 0); 1723428d7b3dSmrg if (!DAMAGE_IS_ALL(priv->gpu_damage)) 1724428d7b3dSmrg sna_damage_add_box(&priv->gpu_damage, &box); 1725428d7b3dSmrg 1726428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 1727428d7b3dSmrg 1728428d7b3dSmrg#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(10, 0) 1729428d7b3dSmrg sna->scrn->pScreen->canDoBGNoneRoot = ok; 1730428d7b3dSmrg#endif 1731428d7b3dSmrg} 1732428d7b3dSmrg 1733428d7b3dSmrgstatic bool use_shadow(struct sna *sna, xf86CrtcPtr crtc) 1734428d7b3dSmrg{ 1735428d7b3dSmrg RRTransformPtr transform; 1736428d7b3dSmrg PictTransform crtc_to_fb; 1737428d7b3dSmrg struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc; 1738428d7b3dSmrg unsigned pitch_limit; 1739428d7b3dSmrg struct sna_pixmap *priv; 1740428d7b3dSmrg BoxRec b; 1741428d7b3dSmrg 1742428d7b3dSmrg assert(sna->scrn->virtualX && sna->scrn->virtualY); 1743428d7b3dSmrg 1744428d7b3dSmrg if (sna->flags & SNA_FORCE_SHADOW) { 1745428d7b3dSmrg DBG(("%s: forcing shadow\n", __FUNCTION__)); 1746428d7b3dSmrg return true; 1747428d7b3dSmrg } 1748428d7b3dSmrg 1749428d7b3dSmrg if (to_sna_crtc(crtc)->fallback_shadow) { 1750428d7b3dSmrg DBG(("%s: fallback shadow\n", __FUNCTION__)); 1751428d7b3dSmrg return true; 1752428d7b3dSmrg } 1753428d7b3dSmrg 1754428d7b3dSmrg if (sna->flags & SNA_TEAR_FREE && to_sna_crtc(crtc)->slave_pixmap) { 1755428d7b3dSmrg DBG(("%s: TearFree shadow required\n", __FUNCTION__)); 1756428d7b3dSmrg return true; 1757428d7b3dSmrg } 1758428d7b3dSmrg 1759428d7b3dSmrg if (sna->scrn->virtualX > sna->mode.max_crtc_width || 1760428d7b3dSmrg sna->scrn->virtualY > sna->mode.max_crtc_height) { 1761428d7b3dSmrg DBG(("%s: framebuffer too large (%dx%d) > (%dx%d)\n", 1762428d7b3dSmrg __FUNCTION__, 1763428d7b3dSmrg sna->scrn->virtualX, sna->scrn->virtualY, 1764428d7b3dSmrg sna->mode.max_crtc_width, sna->mode.max_crtc_height)); 1765428d7b3dSmrg return true; 1766428d7b3dSmrg } 1767428d7b3dSmrg 1768428d7b3dSmrg priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | __MOVE_SCANOUT); 1769428d7b3dSmrg if (priv == NULL) 1770428d7b3dSmrg return true; /* maybe we can create a bo for the scanout? */ 1771428d7b3dSmrg 1772428d7b3dSmrg if (sna->kgem.gen == 071) 1773428d7b3dSmrg pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024; 1774428d7b3dSmrg else if ((sna->kgem.gen >> 3) > 4) 1775428d7b3dSmrg pitch_limit = 32 * 1024; 1776428d7b3dSmrg else if ((sna->kgem.gen >> 3) == 4) 1777428d7b3dSmrg pitch_limit = priv->gpu_bo->tiling ? 16 * 1024 : 32 * 1024; 1778428d7b3dSmrg else if ((sna->kgem.gen >> 3) == 3) 1779428d7b3dSmrg pitch_limit = priv->gpu_bo->tiling ? 8 * 1024 : 16 * 1024; 1780428d7b3dSmrg else 1781428d7b3dSmrg pitch_limit = 8 * 1024; 1782428d7b3dSmrg DBG(("%s: gpu bo handle=%d tiling=%d pitch=%d, limit=%d\n", __FUNCTION__, priv->gpu_bo->handle, priv->gpu_bo->tiling, priv->gpu_bo->pitch, pitch_limit)); 1783428d7b3dSmrg if (priv->gpu_bo->pitch > pitch_limit) 1784428d7b3dSmrg return true; 1785428d7b3dSmrg 1786428d7b3dSmrg if (priv->gpu_bo->tiling && sna->flags & SNA_LINEAR_FB) { 1787428d7b3dSmrg DBG(("%s: gpu bo is tiled, need linear, forcing shadow\n", __FUNCTION__)); 1788428d7b3dSmrg return true; 1789428d7b3dSmrg } 1790428d7b3dSmrg 1791428d7b3dSmrg transform = NULL; 1792428d7b3dSmrg if (crtc->transformPresent) 1793428d7b3dSmrg transform = &crtc->transform; 1794428d7b3dSmrg if (RRTransformCompute(crtc->x, crtc->y, 1795428d7b3dSmrg crtc->mode.HDisplay, crtc->mode.VDisplay, 1796428d7b3dSmrg crtc->rotation, transform, 1797428d7b3dSmrg &crtc_to_fb, 1798428d7b3dSmrg &f_crtc_to_fb, 1799428d7b3dSmrg &f_fb_to_crtc)) { 1800428d7b3dSmrg bool needs_transform = true; 1801428d7b3dSmrg unsigned rotation = rotation_reduce(&to_sna_crtc(crtc)->primary, crtc->rotation); 1802428d7b3dSmrg DBG(("%s: natively supported rotation? rotation=%x & supported=%x == %d\n", 1803428d7b3dSmrg __FUNCTION__, crtc->rotation, to_sna_crtc(crtc)->primary.rotation.supported, 1804428d7b3dSmrg !!(crtc->rotation & to_sna_crtc(crtc)->primary.rotation.supported))); 1805428d7b3dSmrg if (to_sna_crtc(crtc)->primary.rotation.supported & rotation) 1806428d7b3dSmrg needs_transform = RRTransformCompute(crtc->x, crtc->y, 1807428d7b3dSmrg crtc->mode.HDisplay, crtc->mode.VDisplay, 1808428d7b3dSmrg RR_Rotate_0, transform, 1809428d7b3dSmrg NULL, NULL, NULL); 1810428d7b3dSmrg if (needs_transform) { 1811428d7b3dSmrg DBG(("%s: RandR transform present\n", __FUNCTION__)); 1812428d7b3dSmrg return true; 1813428d7b3dSmrg } 1814428d7b3dSmrg } 1815428d7b3dSmrg 1816428d7b3dSmrg /* And finally check that it is entirely visible */ 1817428d7b3dSmrg b.x1 = b.y1 = 0; 1818428d7b3dSmrg b.x2 = crtc->mode.HDisplay; 1819428d7b3dSmrg b.y2 = crtc->mode.VDisplay; 1820428d7b3dSmrg pixman_f_transform_bounds(&f_crtc_to_fb, &b); 1821428d7b3dSmrg DBG(("%s? bounds (%d, %d), (%d, %d), framebufer %dx%d\n", 1822428d7b3dSmrg __FUNCTION__, b.x1, b.y1, b.x2, b.y2, 1823428d7b3dSmrg sna->scrn->virtualX, sna->scrn->virtualY)); 1824428d7b3dSmrg 1825428d7b3dSmrg if (b.x1 < 0 || b.y1 < 0 || 1826428d7b3dSmrg b.x2 > sna->scrn->virtualX || 1827428d7b3dSmrg b.y2 > sna->scrn->virtualY) { 1828428d7b3dSmrg DBG(("%s: scanout is partly outside the framebuffer\n", 1829428d7b3dSmrg __FUNCTION__)); 1830428d7b3dSmrg return true; 1831428d7b3dSmrg } 1832428d7b3dSmrg 1833428d7b3dSmrg return false; 1834428d7b3dSmrg} 1835428d7b3dSmrg 1836428d7b3dSmrgstatic void set_shadow(struct sna *sna, RegionPtr region) 1837428d7b3dSmrg{ 1838428d7b3dSmrg struct sna_pixmap *priv = sna_pixmap(sna->front); 1839428d7b3dSmrg 1840428d7b3dSmrg assert(priv->gpu_bo); 1841428d7b3dSmrg assert(sna->mode.shadow); 1842428d7b3dSmrg 1843428d7b3dSmrg DBG(("%s: waiting for region %dx[(%d, %d), (%d, %d)], front handle=%d, shadow handle=%d\n", 1844428d7b3dSmrg __FUNCTION__, 1845428d7b3dSmrg region_num_rects(region), 1846428d7b3dSmrg region->extents.x1, region->extents.y1, 1847428d7b3dSmrg region->extents.x2, region->extents.y2, 1848428d7b3dSmrg priv->gpu_bo->handle, sna->mode.shadow->handle)); 1849428d7b3dSmrg 1850428d7b3dSmrg assert(priv->pinned & PIN_SCANOUT); 1851428d7b3dSmrg assert((priv->pinned & PIN_PRIME) == 0); 1852428d7b3dSmrg assert(sna->mode.shadow != priv->gpu_bo); 1853428d7b3dSmrg 1854428d7b3dSmrg RegionCopy(&sna->mode.shadow_region, region); 1855428d7b3dSmrg 1856428d7b3dSmrg priv->move_to_gpu = wait_for_shadow; 1857428d7b3dSmrg priv->move_to_gpu_data = sna; 1858428d7b3dSmrg} 1859428d7b3dSmrg 1860428d7b3dSmrgstatic struct kgem_bo * 1861428d7b3dSmrgget_scanout_bo(struct sna *sna, PixmapPtr pixmap) 1862428d7b3dSmrg{ 1863428d7b3dSmrg struct sna_pixmap *priv; 1864428d7b3dSmrg 1865428d7b3dSmrg priv = sna_pixmap_force_to_gpu(pixmap, MOVE_READ | __MOVE_SCANOUT); 1866428d7b3dSmrg if (!priv) 1867428d7b3dSmrg return NULL; 1868428d7b3dSmrg 1869428d7b3dSmrg if (priv->gpu_bo->pitch & 63) { 1870428d7b3dSmrg struct kgem_bo *tmp; 1871428d7b3dSmrg BoxRec b; 1872428d7b3dSmrg 1873428d7b3dSmrg DBG(("%s: converting to scanout bo due to bad pitch [%d]\n", 1874428d7b3dSmrg __FUNCTION__, priv->gpu_bo->pitch)); 1875428d7b3dSmrg 1876428d7b3dSmrg if (priv->pinned) { 1877428d7b3dSmrg DBG(("%s: failed as the Pixmap is already pinned [%x]\n", 1878428d7b3dSmrg __FUNCTION__, priv->pinned)); 1879428d7b3dSmrg return NULL; 1880428d7b3dSmrg } 1881428d7b3dSmrg 1882428d7b3dSmrg tmp = kgem_create_2d(&sna->kgem, 1883428d7b3dSmrg pixmap->drawable.width, 1884428d7b3dSmrg pixmap->drawable.height, 1885428d7b3dSmrg sna->scrn->bitsPerPixel, 1886428d7b3dSmrg priv->gpu_bo->tiling, 1887428d7b3dSmrg CREATE_EXACT | CREATE_SCANOUT); 1888428d7b3dSmrg if (tmp == NULL) { 1889428d7b3dSmrg DBG(("%s: allocation failed\n", __FUNCTION__)); 1890428d7b3dSmrg return NULL; 1891428d7b3dSmrg } 1892428d7b3dSmrg 1893428d7b3dSmrg b.x1 = 0; 1894428d7b3dSmrg b.y1 = 0; 1895428d7b3dSmrg b.x2 = pixmap->drawable.width; 1896428d7b3dSmrg b.y2 = pixmap->drawable.height; 1897428d7b3dSmrg 1898428d7b3dSmrg if (sna->render.copy_boxes(sna, GXcopy, 1899428d7b3dSmrg &pixmap->drawable, priv->gpu_bo, 0, 0, 1900428d7b3dSmrg &pixmap->drawable, tmp, 0, 0, 1901428d7b3dSmrg &b, 1, COPY_LAST)) { 1902428d7b3dSmrg DBG(("%s: copy failed\n", __FUNCTION__)); 1903428d7b3dSmrg kgem_bo_destroy(&sna->kgem, tmp); 1904428d7b3dSmrg return NULL; 1905428d7b3dSmrg } 1906428d7b3dSmrg 1907428d7b3dSmrg kgem_bo_destroy(&sna->kgem, priv->gpu_bo); 1908428d7b3dSmrg priv->gpu_bo = tmp; 1909428d7b3dSmrg } 1910428d7b3dSmrg 1911428d7b3dSmrg priv->pinned |= PIN_SCANOUT; 1912428d7b3dSmrg return priv->gpu_bo; 1913428d7b3dSmrg} 1914428d7b3dSmrg 1915428d7b3dSmrgstatic struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc) 1916428d7b3dSmrg{ 1917428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 1918428d7b3dSmrg ScrnInfoPtr scrn = crtc->scrn; 1919428d7b3dSmrg struct sna *sna = to_sna(scrn); 1920428d7b3dSmrg struct kgem_bo *bo; 1921428d7b3dSmrg 1922428d7b3dSmrg sna_crtc->transform = false; 1923428d7b3dSmrg sna_crtc->rotation = RR_Rotate_0; 1924428d7b3dSmrg 1925428d7b3dSmrg if (use_shadow(sna, crtc)) { 1926428d7b3dSmrg unsigned long tiled_limit; 1927428d7b3dSmrg int tiling; 1928428d7b3dSmrg 1929428d7b3dSmrgforce_shadow: 1930428d7b3dSmrg if (!sna_crtc_enable_shadow(sna, sna_crtc)) { 1931428d7b3dSmrg DBG(("%s: failed to enable crtc shadow\n", __FUNCTION__)); 1932428d7b3dSmrg return NULL; 1933428d7b3dSmrg } 1934428d7b3dSmrg 1935428d7b3dSmrg DBG(("%s: attaching to per-crtc pixmap %dx%d\n", 1936428d7b3dSmrg __FUNCTION__, crtc->mode.HDisplay, crtc->mode.VDisplay)); 1937428d7b3dSmrg 1938428d7b3dSmrg bo = sna_crtc->shadow_bo; 1939428d7b3dSmrg if (bo) { 1940428d7b3dSmrg if (sna_crtc->shadow_bo_width == crtc->mode.HDisplay && 1941428d7b3dSmrg sna_crtc->shadow_bo_height == crtc->mode.VDisplay) { 1942428d7b3dSmrg DBG(("%s: reusing current shadow bo handle=%d\n", 1943428d7b3dSmrg __FUNCTION__, bo->handle)); 1944428d7b3dSmrg goto out_shadow; 1945428d7b3dSmrg } 1946428d7b3dSmrg 1947428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 1948428d7b3dSmrg sna_crtc->shadow_bo = NULL; 1949428d7b3dSmrg } 1950428d7b3dSmrg 1951428d7b3dSmrg tiling = I915_TILING_X; 1952428d7b3dSmrg if (sna->kgem.gen == 071) 1953428d7b3dSmrg tiled_limit = 16 * 1024 * 8; 1954428d7b3dSmrg else if ((sna->kgem.gen >> 3) > 4) 1955428d7b3dSmrg tiled_limit = 32 * 1024 * 8; 1956428d7b3dSmrg else if ((sna->kgem.gen >> 3) == 4) 1957428d7b3dSmrg tiled_limit = 16 * 1024 * 8; 1958428d7b3dSmrg else 1959428d7b3dSmrg tiled_limit = 8 * 1024 * 8; 1960428d7b3dSmrg if ((unsigned long)crtc->mode.HDisplay * scrn->bitsPerPixel > tiled_limit) 1961428d7b3dSmrg tiling = I915_TILING_NONE; 1962428d7b3dSmrg if (sna->flags & SNA_LINEAR_FB) 1963428d7b3dSmrg tiling = I915_TILING_NONE; 1964428d7b3dSmrg 1965428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 1966428d7b3dSmrg crtc->mode.HDisplay, crtc->mode.VDisplay, 1967428d7b3dSmrg scrn->bitsPerPixel, 1968428d7b3dSmrg tiling, CREATE_SCANOUT); 1969428d7b3dSmrg if (bo == NULL) { 1970428d7b3dSmrg DBG(("%s: failed to allocate crtc scanout\n", __FUNCTION__)); 1971428d7b3dSmrg return NULL; 1972428d7b3dSmrg } 1973428d7b3dSmrg 1974428d7b3dSmrg if (!get_fb(sna, bo, crtc->mode.HDisplay, crtc->mode.VDisplay)) { 1975428d7b3dSmrg DBG(("%s: failed to bind fb for crtc scanout\n", __FUNCTION__)); 1976428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 1977428d7b3dSmrg return NULL; 1978428d7b3dSmrg } 1979428d7b3dSmrg 1980428d7b3dSmrg if (__sna_pixmap_get_bo(sna->front) && !crtc->transformPresent) { 1981428d7b3dSmrg DrawableRec tmp; 1982428d7b3dSmrg BoxRec b; 1983428d7b3dSmrg 1984428d7b3dSmrg b.x1 = crtc->x; 1985428d7b3dSmrg b.y1 = crtc->y; 1986428d7b3dSmrg b.x2 = crtc->x + crtc->mode.HDisplay; 1987428d7b3dSmrg b.y2 = crtc->y + crtc->mode.VDisplay; 1988428d7b3dSmrg 1989428d7b3dSmrg DBG(("%s: copying onto shadow CRTC: (%d, %d)x(%d, %d), handle=%d\n", 1990428d7b3dSmrg __FUNCTION__, 1991428d7b3dSmrg b.x1, b.y1, 1992428d7b3dSmrg b.x2, b.y2, 1993428d7b3dSmrg bo->handle)); 1994428d7b3dSmrg 1995428d7b3dSmrg tmp.width = crtc->mode.HDisplay; 1996428d7b3dSmrg tmp.height = crtc->mode.VDisplay; 1997428d7b3dSmrg tmp.depth = sna->front->drawable.depth; 1998428d7b3dSmrg tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel; 1999428d7b3dSmrg 2000428d7b3dSmrg (void)sna->render.copy_boxes(sna, GXcopy, 2001428d7b3dSmrg &sna->front->drawable, __sna_pixmap_get_bo(sna->front), 0, 0, 2002428d7b3dSmrg &tmp, bo, -b.x1, -b.y1, 2003428d7b3dSmrg &b, 1, 0); 2004428d7b3dSmrg } 2005428d7b3dSmrg 2006428d7b3dSmrg sna_crtc->shadow_bo_width = crtc->mode.HDisplay; 2007428d7b3dSmrg sna_crtc->shadow_bo_height = crtc->mode.VDisplay; 2008428d7b3dSmrg sna_crtc->shadow_bo = bo; 2009428d7b3dSmrgout_shadow: 2010428d7b3dSmrg sna_crtc->transform = true; 2011428d7b3dSmrg return kgem_bo_reference(bo); 2012428d7b3dSmrg } else { 2013428d7b3dSmrg if (sna_crtc->shadow_bo) { 2014428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna_crtc->shadow_bo); 2015428d7b3dSmrg sna_crtc->shadow_bo = NULL; 2016428d7b3dSmrg } 2017428d7b3dSmrg 2018428d7b3dSmrg if (sna_crtc->slave_pixmap) { 2019428d7b3dSmrg DBG(("%s: attaching to scanout pixmap\n", __FUNCTION__)); 2020428d7b3dSmrg bo = get_scanout_bo(sna, sna_crtc->slave_pixmap); 2021428d7b3dSmrg if (bo == NULL) { 2022428d7b3dSmrg DBG(("%s: failed to pin crtc scanout\n", __FUNCTION__)); 2023428d7b3dSmrg sna_crtc->fallback_shadow = true; 2024428d7b3dSmrg goto force_shadow; 2025428d7b3dSmrg } 2026428d7b3dSmrg 2027428d7b3dSmrg if (!get_fb(sna, bo, 2028428d7b3dSmrg sna_crtc->slave_pixmap->drawable.width, 2029428d7b3dSmrg sna_crtc->slave_pixmap->drawable.height)) { 2030428d7b3dSmrg DBG(("%s: failed to bind fb for crtc scanout\n", __FUNCTION__)); 2031428d7b3dSmrg sna_crtc->fallback_shadow = true; 2032428d7b3dSmrg goto force_shadow; 2033428d7b3dSmrg } 2034428d7b3dSmrg } else { 2035428d7b3dSmrg DBG(("%s: attaching to framebuffer\n", __FUNCTION__)); 2036428d7b3dSmrg bo = get_scanout_bo(sna, sna->front); 2037428d7b3dSmrg if (bo == NULL) { 2038428d7b3dSmrg DBG(("%s: failed to pin framebuffer\n", __FUNCTION__)); 2039428d7b3dSmrg sna_crtc->fallback_shadow = true; 2040428d7b3dSmrg goto force_shadow; 2041428d7b3dSmrg } 2042428d7b3dSmrg 2043428d7b3dSmrg if (!get_fb(sna, bo, scrn->virtualX, scrn->virtualY)) { 2044428d7b3dSmrg DBG(("%s: failed to bind fb for crtc scanout\n", __FUNCTION__)); 2045428d7b3dSmrg sna_crtc->fallback_shadow = true; 2046428d7b3dSmrg goto force_shadow; 2047428d7b3dSmrg } 2048428d7b3dSmrg } 2049428d7b3dSmrg 2050428d7b3dSmrg if (sna->flags & SNA_TEAR_FREE) { 2051428d7b3dSmrg assert(sna_crtc->slave_pixmap == NULL); 2052428d7b3dSmrg 2053428d7b3dSmrg DBG(("%s: enabling TearFree shadow\n", __FUNCTION__)); 2054428d7b3dSmrg if (!sna_crtc_enable_shadow(sna, sna_crtc)) { 2055428d7b3dSmrg DBG(("%s: failed to enable crtc shadow\n", __FUNCTION__)); 2056428d7b3dSmrg return NULL; 2057428d7b3dSmrg } 2058428d7b3dSmrg 2059428d7b3dSmrg if (sna->mode.shadow == NULL && !wedged(sna)) { 2060428d7b3dSmrg RegionRec region; 2061428d7b3dSmrg struct kgem_bo *shadow; 2062428d7b3dSmrg 2063428d7b3dSmrg DBG(("%s: creating TearFree shadow bo\n", __FUNCTION__)); 2064428d7b3dSmrg 2065428d7b3dSmrg region.extents.x1 = 0; 2066428d7b3dSmrg region.extents.y1 = 0; 2067428d7b3dSmrg region.extents.x2 = sna->scrn->virtualX; 2068428d7b3dSmrg region.extents.y2 = sna->scrn->virtualY; 2069428d7b3dSmrg region.data = NULL; 2070428d7b3dSmrg 2071428d7b3dSmrg shadow = kgem_create_2d(&sna->kgem, 2072428d7b3dSmrg region.extents.x2, 2073428d7b3dSmrg region.extents.y2, 2074428d7b3dSmrg scrn->bitsPerPixel, 2075428d7b3dSmrg kgem_choose_tiling(&sna->kgem, 2076428d7b3dSmrg I915_TILING_X, 2077428d7b3dSmrg region.extents.x2, 2078428d7b3dSmrg region.extents.y2, 2079428d7b3dSmrg sna->scrn->bitsPerPixel), 2080428d7b3dSmrg CREATE_SCANOUT); 2081428d7b3dSmrg if (shadow == NULL) { 2082428d7b3dSmrg DBG(("%s: failed to allocate TearFree shadow bo\n", __FUNCTION__)); 2083428d7b3dSmrg sna_crtc->fallback_shadow = true; 2084428d7b3dSmrg goto force_shadow; 2085428d7b3dSmrg } 2086428d7b3dSmrg 2087428d7b3dSmrg if (!get_fb(sna, shadow, 2088428d7b3dSmrg region.extents.x2, 2089428d7b3dSmrg region.extents.y2)) { 2090428d7b3dSmrg DBG(("%s: failed to bind fb for TearFeee shadow\n", __FUNCTION__)); 2091428d7b3dSmrg kgem_bo_destroy(&sna->kgem, shadow); 2092428d7b3dSmrg sna_crtc->fallback_shadow = true; 2093428d7b3dSmrg goto force_shadow; 2094428d7b3dSmrg } 2095428d7b3dSmrg 2096428d7b3dSmrg sna->mode.shadow = shadow; 2097428d7b3dSmrg set_shadow(sna, ®ion); 2098428d7b3dSmrg } 2099428d7b3dSmrg 2100428d7b3dSmrg sna_crtc_disable_override(sna, sna_crtc); 2101428d7b3dSmrg } else 2102428d7b3dSmrg sna_crtc_disable_shadow(sna, sna_crtc); 2103428d7b3dSmrg 2104428d7b3dSmrg sna_crtc->rotation = rotation_reduce(&sna_crtc->primary, crtc->rotation); 2105428d7b3dSmrg assert(sna_crtc->primary.rotation.supported & sna_crtc->rotation); 2106428d7b3dSmrg return kgem_bo_reference(bo); 2107428d7b3dSmrg } 2108428d7b3dSmrg} 2109428d7b3dSmrg 2110428d7b3dSmrgstatic void sna_crtc_randr(xf86CrtcPtr crtc) 2111428d7b3dSmrg{ 2112428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 2113428d7b3dSmrg struct pict_f_transform f_crtc_to_fb, f_fb_to_crtc; 2114428d7b3dSmrg PictTransform crtc_to_fb; 2115428d7b3dSmrg PictFilterPtr filter; 2116428d7b3dSmrg xFixed *params; 2117428d7b3dSmrg int nparams; 2118428d7b3dSmrg RRTransformPtr transform; 2119428d7b3dSmrg int needs_transform; 2120428d7b3dSmrg 2121428d7b3dSmrg transform = NULL; 2122428d7b3dSmrg if (crtc->transformPresent) 2123428d7b3dSmrg transform = &crtc->transform; 2124428d7b3dSmrg 2125428d7b3dSmrg needs_transform = 2126428d7b3dSmrg RRTransformCompute(crtc->x, crtc->y, 2127428d7b3dSmrg crtc->mode.HDisplay, crtc->mode.VDisplay, 2128428d7b3dSmrg crtc->rotation, transform, 2129428d7b3dSmrg &crtc_to_fb, 2130428d7b3dSmrg &f_crtc_to_fb, 2131428d7b3dSmrg &f_fb_to_crtc); 2132428d7b3dSmrg 2133428d7b3dSmrg filter = NULL; 2134428d7b3dSmrg params = NULL; 2135428d7b3dSmrg nparams = 0; 2136428d7b3dSmrg if (sna_crtc->transform) { 2137428d7b3dSmrg#ifdef RANDR_12_INTERFACE 2138428d7b3dSmrg if (transform) { 2139428d7b3dSmrg if (transform->nparams) { 2140428d7b3dSmrg params = malloc(transform->nparams * sizeof(xFixed)); 2141428d7b3dSmrg if (params) { 2142428d7b3dSmrg memcpy(params, transform->params, 2143428d7b3dSmrg transform->nparams * sizeof(xFixed)); 2144428d7b3dSmrg nparams = transform->nparams; 2145428d7b3dSmrg filter = transform->filter; 2146428d7b3dSmrg } 2147428d7b3dSmrg } else 2148428d7b3dSmrg filter = transform->filter; 2149428d7b3dSmrg } 2150428d7b3dSmrg#endif 2151428d7b3dSmrg crtc->transform_in_use = needs_transform; 2152428d7b3dSmrg } else 2153428d7b3dSmrg crtc->transform_in_use = sna_crtc->rotation != RR_Rotate_0; 2154428d7b3dSmrg 2155428d7b3dSmrg crtc->crtc_to_framebuffer = crtc_to_fb; 2156428d7b3dSmrg crtc->f_crtc_to_framebuffer = f_crtc_to_fb; 2157428d7b3dSmrg crtc->f_framebuffer_to_crtc = f_fb_to_crtc; 2158428d7b3dSmrg 2159428d7b3dSmrg free(crtc->params); 2160428d7b3dSmrg crtc->params = params; 2161428d7b3dSmrg crtc->nparams = nparams; 2162428d7b3dSmrg 2163428d7b3dSmrg crtc->filter = filter; 2164428d7b3dSmrg if (filter) { 2165428d7b3dSmrg crtc->filter_width = filter->width; 2166428d7b3dSmrg crtc->filter_height = filter->height; 2167428d7b3dSmrg } else { 2168428d7b3dSmrg crtc->filter_width = 0; 2169428d7b3dSmrg crtc->filter_height = 0; 2170428d7b3dSmrg } 2171428d7b3dSmrg 2172428d7b3dSmrg crtc->bounds.x1 = 0; 2173428d7b3dSmrg crtc->bounds.x2 = crtc->mode.HDisplay; 2174428d7b3dSmrg crtc->bounds.y1 = 0; 2175428d7b3dSmrg crtc->bounds.y2 = crtc->mode.VDisplay; 2176428d7b3dSmrg pixman_f_transform_bounds(&f_crtc_to_fb, &crtc->bounds); 2177428d7b3dSmrg 2178428d7b3dSmrg DBG(("%s: transform? %d, bounds (%d, %d), (%d, %d)\n", 2179428d7b3dSmrg __FUNCTION__, crtc->transform_in_use, 2180428d7b3dSmrg crtc->bounds.x1, crtc->bounds.y1, 2181428d7b3dSmrg crtc->bounds.x2, crtc->bounds.y2)); 2182428d7b3dSmrg} 2183428d7b3dSmrg 2184428d7b3dSmrgstatic void 2185428d7b3dSmrgsna_crtc_damage(xf86CrtcPtr crtc) 2186428d7b3dSmrg{ 2187428d7b3dSmrg ScreenPtr screen = crtc->scrn->pScreen; 2188428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 2189428d7b3dSmrg RegionRec region, *damage; 2190428d7b3dSmrg 2191428d7b3dSmrg region.extents = crtc->bounds; 2192428d7b3dSmrg region.data = NULL; 2193428d7b3dSmrg 2194428d7b3dSmrg if (region.extents.x1 < 0) 2195428d7b3dSmrg region.extents.x1 = 0; 2196428d7b3dSmrg if (region.extents.y1 < 0) 2197428d7b3dSmrg region.extents.y1 = 0; 2198428d7b3dSmrg if (region.extents.x2 > screen->width) 2199428d7b3dSmrg region.extents.x2 = screen->width; 2200428d7b3dSmrg if (region.extents.y2 > screen->height) 2201428d7b3dSmrg region.extents.y2 = screen->height; 2202428d7b3dSmrg 2203428d7b3dSmrg DBG(("%s: marking crtc %d as completely damaged (%d, %d), (%d, %d)\n", 2204428d7b3dSmrg __FUNCTION__, to_sna_crtc(crtc)->id, 2205428d7b3dSmrg region.extents.x1, region.extents.y1, 2206428d7b3dSmrg region.extents.x2, region.extents.y2)); 2207428d7b3dSmrg to_sna_crtc(crtc)->client_damage = region; 2208428d7b3dSmrg 2209428d7b3dSmrg assert(sna->mode.shadow_damage && sna->mode.shadow_active); 2210428d7b3dSmrg damage = DamageRegion(sna->mode.shadow_damage); 2211428d7b3dSmrg RegionUnion(damage, damage, ®ion); 2212428d7b3dSmrg 2213428d7b3dSmrg DBG(("%s: damage now %dx[(%d, %d), (%d, %d)]\n", 2214428d7b3dSmrg __FUNCTION__, 2215428d7b3dSmrg region_num_rects(damage), 2216428d7b3dSmrg damage->extents.x1, damage->extents.y1, 2217428d7b3dSmrg damage->extents.x2, damage->extents.y2)); 2218428d7b3dSmrg} 2219428d7b3dSmrg 2220428d7b3dSmrgstatic char *outputs_for_crtc(xf86CrtcPtr crtc, char *outputs, int max) 2221428d7b3dSmrg{ 2222428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 2223428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 2224428d7b3dSmrg int len, i; 2225428d7b3dSmrg 2226428d7b3dSmrg for (i = len = 0; i < sna->mode.num_real_output; i++) { 2227428d7b3dSmrg xf86OutputPtr output = config->output[i]; 2228428d7b3dSmrg 2229428d7b3dSmrg if (output->crtc != crtc) 2230428d7b3dSmrg continue; 2231428d7b3dSmrg 2232428d7b3dSmrg len += snprintf(outputs+len, max-len, "%s, ", output->name); 2233428d7b3dSmrg } 2234428d7b3dSmrg assert(len >= 2); 2235428d7b3dSmrg outputs[len-2] = '\0'; 2236428d7b3dSmrg 2237428d7b3dSmrg return outputs; 2238428d7b3dSmrg} 2239428d7b3dSmrg 2240428d7b3dSmrgstatic const char *rotation_to_str(Rotation rotation) 2241428d7b3dSmrg{ 2242428d7b3dSmrg switch (rotation & RR_Rotate_All) { 2243428d7b3dSmrg case 0: 2244428d7b3dSmrg case RR_Rotate_0: return "normal"; 2245428d7b3dSmrg case RR_Rotate_90: return "left"; 2246428d7b3dSmrg case RR_Rotate_180: return "inverted"; 2247428d7b3dSmrg case RR_Rotate_270: return "right"; 2248428d7b3dSmrg default: return "unknown"; 2249428d7b3dSmrg } 2250428d7b3dSmrg} 2251428d7b3dSmrg 2252428d7b3dSmrgstatic const char *reflection_to_str(Rotation rotation) 2253428d7b3dSmrg{ 2254428d7b3dSmrg switch (rotation & RR_Reflect_All) { 2255428d7b3dSmrg case 0: return "none"; 2256428d7b3dSmrg case RR_Reflect_X: return "X axis"; 2257428d7b3dSmrg case RR_Reflect_Y: return "Y axis"; 2258428d7b3dSmrg case RR_Reflect_X | RR_Reflect_Y: return "X and Y axes"; 2259428d7b3dSmrg default: return "invalid"; 2260428d7b3dSmrg } 2261428d7b3dSmrg} 2262428d7b3dSmrg 2263428d7b3dSmrgstatic Bool 2264428d7b3dSmrg__sna_crtc_set_mode(xf86CrtcPtr crtc) 2265428d7b3dSmrg{ 2266428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 2267428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 2268428d7b3dSmrg struct kgem_bo *saved_bo, *bo; 2269428d7b3dSmrg uint32_t saved_offset; 2270428d7b3dSmrg bool saved_transform; 2271428d7b3dSmrg 2272428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 2273428d7b3dSmrg 2274428d7b3dSmrg saved_bo = sna_crtc->bo; 2275428d7b3dSmrg saved_transform = sna_crtc->transform; 2276428d7b3dSmrg saved_offset = sna_crtc->offset; 2277428d7b3dSmrg 2278428d7b3dSmrg sna_crtc->fallback_shadow = false; 2279428d7b3dSmrgretry: /* Attach per-crtc pixmap or direct */ 2280428d7b3dSmrg bo = sna_crtc_attach(crtc); 2281428d7b3dSmrg if (bo == NULL) { 2282428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 2283428d7b3dSmrg "unable to attach scanout\n"); 2284428d7b3dSmrg goto error; 2285428d7b3dSmrg } 2286428d7b3dSmrg 2287428d7b3dSmrg /* Prevent recursion when enabling outputs during execbuffer */ 2288428d7b3dSmrg if (bo->exec && RQ(bo->rq)->bo == NULL) 2289428d7b3dSmrg _kgem_submit(&sna->kgem); 2290428d7b3dSmrg 2291428d7b3dSmrg sna_crtc->bo = bo; 2292428d7b3dSmrg if (!sna_crtc_apply(crtc)) { 2293428d7b3dSmrg int err = errno; 2294428d7b3dSmrg 2295428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 2296428d7b3dSmrg 2297428d7b3dSmrg if (!sna_crtc->shadow) { 2298428d7b3dSmrg sna_crtc->fallback_shadow = true; 2299428d7b3dSmrg goto retry; 2300428d7b3dSmrg } 2301428d7b3dSmrg 2302428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 2303428d7b3dSmrg "failed to set mode: %s [%d]\n", strerror(err), err); 2304428d7b3dSmrg goto error; 2305428d7b3dSmrg } 2306428d7b3dSmrg 2307428d7b3dSmrg bo->active_scanout++; 2308428d7b3dSmrg if (saved_bo) { 2309428d7b3dSmrg assert(saved_bo->active_scanout); 2310428d7b3dSmrg assert(saved_bo->refcnt >= saved_bo->active_scanout); 2311428d7b3dSmrg saved_bo->active_scanout--; 2312428d7b3dSmrg kgem_bo_destroy(&sna->kgem, saved_bo); 2313428d7b3dSmrg } 2314428d7b3dSmrg 2315428d7b3dSmrg sna_crtc_randr(crtc); 2316428d7b3dSmrg if (sna_crtc->transform) 2317428d7b3dSmrg sna_crtc_damage(crtc); 2318428d7b3dSmrg sna->mode.front_active += saved_bo == NULL; 2319428d7b3dSmrg sna->mode.dirty = true; 2320428d7b3dSmrg DBG(("%s: front_active=%d\n", __FUNCTION__, sna->mode.front_active)); 2321428d7b3dSmrg 2322428d7b3dSmrg return TRUE; 2323428d7b3dSmrg 2324428d7b3dSmrgerror: 2325428d7b3dSmrg sna_crtc->offset = saved_offset; 2326428d7b3dSmrg sna_crtc->transform = saved_transform; 2327428d7b3dSmrg sna_crtc->bo = saved_bo; 2328428d7b3dSmrg sna_mode_discover(sna); 2329428d7b3dSmrg return FALSE; 2330428d7b3dSmrg} 2331428d7b3dSmrg 2332428d7b3dSmrgstatic Bool 2333428d7b3dSmrgsna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 2334428d7b3dSmrg Rotation rotation, int x, int y) 2335428d7b3dSmrg{ 2336428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 2337428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 2338428d7b3dSmrg struct drm_mode_modeinfo saved_kmode; 2339428d7b3dSmrg char outputs[256]; 2340428d7b3dSmrg 2341428d7b3dSmrg if (mode->HDisplay == 0 || mode->VDisplay == 0) 2342428d7b3dSmrg return FALSE; 2343428d7b3dSmrg 2344428d7b3dSmrg assert(sna_crtc); 2345428d7b3dSmrg 2346428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, 2347428d7b3dSmrg "switch to mode %dx%d@%.1f on %s using pipe %d, position (%d, %d), rotation %s, reflection %s\n", 2348428d7b3dSmrg mode->HDisplay, mode->VDisplay, xf86ModeVRefresh(mode), 2349428d7b3dSmrg outputs_for_crtc(crtc, outputs, sizeof(outputs)), sna_crtc->pipe, 2350428d7b3dSmrg x, y, rotation_to_str(rotation), reflection_to_str(rotation)); 2351428d7b3dSmrg 2352428d7b3dSmrg assert(mode->HDisplay <= sna->mode.max_crtc_width && 2353428d7b3dSmrg mode->VDisplay <= sna->mode.max_crtc_height); 2354428d7b3dSmrg 2355428d7b3dSmrg#if HAS_GAMMA 2356428d7b3dSmrg drmModeCrtcSetGamma(sna->kgem.fd, sna_crtc->id, 2357428d7b3dSmrg crtc->gamma_size, 2358428d7b3dSmrg crtc->gamma_red, 2359428d7b3dSmrg crtc->gamma_green, 2360428d7b3dSmrg crtc->gamma_blue); 2361428d7b3dSmrg#endif 2362428d7b3dSmrg 2363428d7b3dSmrg saved_kmode = sna_crtc->kmode; 2364428d7b3dSmrg mode_to_kmode(&sna_crtc->kmode, mode); 2365428d7b3dSmrg if (__sna_crtc_set_mode(crtc)) 2366428d7b3dSmrg return TRUE; 2367428d7b3dSmrg 2368428d7b3dSmrg sna_crtc->kmode = saved_kmode; 2369428d7b3dSmrg return FALSE; 2370428d7b3dSmrg} 2371428d7b3dSmrg 2372428d7b3dSmrgstatic void 2373428d7b3dSmrgsna_crtc_dpms(xf86CrtcPtr crtc, int mode) 2374428d7b3dSmrg{ 2375428d7b3dSmrg struct sna_crtc *priv = to_sna_crtc(crtc); 2376428d7b3dSmrg 2377428d7b3dSmrg DBG(("%s(pipe %d, dpms mode -> %d):= active=%d\n", 2378428d7b3dSmrg __FUNCTION__, priv->pipe, mode, mode == DPMSModeOn)); 2379428d7b3dSmrg if (priv->dpms_mode == mode) 2380428d7b3dSmrg return; 2381428d7b3dSmrg 2382428d7b3dSmrg assert(priv); 2383428d7b3dSmrg priv->dpms_mode = mode; 2384428d7b3dSmrg 2385428d7b3dSmrg if (mode == DPMSModeOn && crtc->enabled && priv->bo == NULL) { 2386428d7b3dSmrg if (__sna_crtc_set_mode(crtc)) 2387428d7b3dSmrg update_flush_interval(to_sna(crtc->scrn)); 2388428d7b3dSmrg else 2389428d7b3dSmrg mode = DPMSModeOff; 2390428d7b3dSmrg } 2391428d7b3dSmrg 2392428d7b3dSmrg if (mode != DPMSModeOn) 2393428d7b3dSmrg sna_crtc_disable(crtc); 2394428d7b3dSmrg} 2395428d7b3dSmrg 2396428d7b3dSmrgvoid sna_mode_adjust_frame(struct sna *sna, int x, int y) 2397428d7b3dSmrg{ 2398428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 2399428d7b3dSmrg xf86CrtcPtr crtc; 2400428d7b3dSmrg int saved_x, saved_y; 2401428d7b3dSmrg 2402428d7b3dSmrg if ((unsigned)config->compat_output >= config->num_output) 2403428d7b3dSmrg return; 2404428d7b3dSmrg 2405428d7b3dSmrg crtc = config->output[config->compat_output]->crtc; 2406428d7b3dSmrg if (crtc == NULL || !crtc->enabled) 2407428d7b3dSmrg return; 2408428d7b3dSmrg 2409428d7b3dSmrg if (crtc->x == x && crtc->y == y) 2410428d7b3dSmrg return; 2411428d7b3dSmrg 2412428d7b3dSmrg saved_x = crtc->x; 2413428d7b3dSmrg saved_y = crtc->y; 2414428d7b3dSmrg 2415428d7b3dSmrg crtc->x = x; 2416428d7b3dSmrg crtc->y = y; 2417428d7b3dSmrg if (to_sna_crtc(crtc) && !__sna_crtc_set_mode(crtc)) { 2418428d7b3dSmrg crtc->x = saved_x; 2419428d7b3dSmrg crtc->y = saved_y; 2420428d7b3dSmrg } 2421428d7b3dSmrg} 2422428d7b3dSmrg 2423428d7b3dSmrgstatic void 2424428d7b3dSmrgsna_crtc_gamma_set(xf86CrtcPtr crtc, 2425428d7b3dSmrg CARD16 *red, CARD16 *green, CARD16 *blue, int size) 2426428d7b3dSmrg{ 2427428d7b3dSmrg assert(to_sna_crtc(crtc)); 2428428d7b3dSmrg drmModeCrtcSetGamma(to_sna(crtc->scrn)->kgem.fd, 2429428d7b3dSmrg to_sna_crtc(crtc)->id, 2430428d7b3dSmrg size, red, green, blue); 2431428d7b3dSmrg} 2432428d7b3dSmrg 2433428d7b3dSmrgstatic void 2434428d7b3dSmrgsna_crtc_destroy(xf86CrtcPtr crtc) 2435428d7b3dSmrg{ 2436428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 2437428d7b3dSmrg 2438428d7b3dSmrg if (sna_crtc == NULL) 2439428d7b3dSmrg return; 2440428d7b3dSmrg 2441428d7b3dSmrg free(sna_crtc); 2442428d7b3dSmrg crtc->driver_private = NULL; 2443428d7b3dSmrg} 2444428d7b3dSmrg 2445428d7b3dSmrg#if HAS_PIXMAP_SHARING 2446428d7b3dSmrgstatic Bool 2447428d7b3dSmrgsna_crtc_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap) 2448428d7b3dSmrg{ 2449428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 2450428d7b3dSmrg 2451428d7b3dSmrg if (sna_crtc == NULL) 2452428d7b3dSmrg return FALSE; 2453428d7b3dSmrg 2454428d7b3dSmrg if (pixmap == sna_crtc->slave_pixmap) 2455428d7b3dSmrg return TRUE; 2456428d7b3dSmrg 2457428d7b3dSmrg DBG(("%s: CRTC:%d, pipe=%d setting scanout pixmap=%ld\n", 2458428d7b3dSmrg __FUNCTION__, sna_crtc->id, sna_crtc->pipe, 2459428d7b3dSmrg pixmap ? pixmap->drawable.serialNumber : 0)); 2460428d7b3dSmrg 2461428d7b3dSmrg /* Disable first so that we can unregister the damage tracking */ 2462428d7b3dSmrg sna_crtc_disable_shadow(to_sna(crtc->scrn), sna_crtc); 2463428d7b3dSmrg 2464428d7b3dSmrg sna_crtc->slave_pixmap = pixmap; 2465428d7b3dSmrg 2466428d7b3dSmrg return TRUE; 2467428d7b3dSmrg} 2468428d7b3dSmrg#endif 2469428d7b3dSmrg 2470428d7b3dSmrgstatic const xf86CrtcFuncsRec sna_crtc_funcs = { 2471428d7b3dSmrg#if XF86_CRTC_VERSION >= 1 2472428d7b3dSmrg .dpms = sna_crtc_dpms, 2473428d7b3dSmrg#endif 2474428d7b3dSmrg .set_mode_major = sna_crtc_set_mode_major, 2475428d7b3dSmrg .gamma_set = sna_crtc_gamma_set, 2476428d7b3dSmrg .destroy = sna_crtc_destroy, 2477428d7b3dSmrg#if HAS_PIXMAP_SHARING 2478428d7b3dSmrg .set_scanout_pixmap = sna_crtc_set_scanout_pixmap, 2479428d7b3dSmrg#endif 2480428d7b3dSmrg}; 2481428d7b3dSmrg 2482428d7b3dSmrginline static bool prop_is_rotation(struct drm_mode_get_property *prop) 2483428d7b3dSmrg{ 2484428d7b3dSmrg if ((prop->flags & (1 << 5)) == 0) 2485428d7b3dSmrg return false; 2486428d7b3dSmrg 2487428d7b3dSmrg if (strcmp(prop->name, "rotation")) 2488428d7b3dSmrg return false; 2489428d7b3dSmrg 2490428d7b3dSmrg return true; 2491428d7b3dSmrg} 2492428d7b3dSmrg 2493428d7b3dSmrgstatic int plane_details(struct sna *sna, struct plane *p) 2494428d7b3dSmrg{ 2495428d7b3dSmrg struct local_mode_obj_get_properties arg; 2496428d7b3dSmrg uint64_t stack_props[24]; 2497428d7b3dSmrg uint32_t *props = (uint32_t *)stack_props; 2498428d7b3dSmrg uint64_t *values = stack_props + 8; 2499428d7b3dSmrg int i, type = DRM_PLANE_TYPE_OVERLAY; 2500428d7b3dSmrg 2501428d7b3dSmrg memset(&arg, 0, sizeof(struct local_mode_obj_get_properties)); 2502428d7b3dSmrg arg.obj_id = p->id; 2503428d7b3dSmrg arg.obj_type = LOCAL_MODE_OBJECT_PLANE; 2504428d7b3dSmrg 2505428d7b3dSmrg arg.props_ptr = (uintptr_t)props; 2506428d7b3dSmrg arg.prop_values_ptr = (uintptr_t)values; 2507428d7b3dSmrg arg.count_props = 16; 2508428d7b3dSmrg 2509428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_OBJ_GETPROPERTIES, &arg)) 2510428d7b3dSmrg return -1; 2511428d7b3dSmrg 2512428d7b3dSmrg DBG(("%s: object %d (type %x) has %d props\n", __FUNCTION__, 2513428d7b3dSmrg p->id, LOCAL_MODE_OBJECT_PLANE, arg.count_props)); 2514428d7b3dSmrg 2515428d7b3dSmrg if (arg.count_props > 16) { 2516428d7b3dSmrg props = malloc(2*sizeof(uint64_t)*arg.count_props); 2517428d7b3dSmrg if (props == NULL) 2518428d7b3dSmrg return -1; 2519428d7b3dSmrg 2520428d7b3dSmrg values = (uint64_t *)props + arg.count_props; 2521428d7b3dSmrg 2522428d7b3dSmrg arg.props_ptr = (uintptr_t)props; 2523428d7b3dSmrg arg.prop_values_ptr = (uintptr_t)values; 2524428d7b3dSmrg 2525428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_OBJ_GETPROPERTIES, &arg)) 2526428d7b3dSmrg arg.count_props = 0; 2527428d7b3dSmrg } 2528428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(arg.props_ptr, sizeof(uint32_t)*arg.count_props)); 2529428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(arg.prop_values_ptr, sizeof(uint64_t)*arg.count_props)); 2530428d7b3dSmrg 2531428d7b3dSmrg for (i = 0; i < arg.count_props; i++) { 2532428d7b3dSmrg struct drm_mode_get_property prop; 2533428d7b3dSmrg 2534428d7b3dSmrg memset(&prop, 0, sizeof(prop)); 2535428d7b3dSmrg prop.prop_id = props[i]; 2536428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) { 2537428d7b3dSmrg ERR(("%s: prop[%d].id=%d GETPROPERTY failed with errno=%d\n", 2538428d7b3dSmrg __FUNCTION__, i, props[i], errno)); 2539428d7b3dSmrg continue; 2540428d7b3dSmrg } 2541428d7b3dSmrg 2542428d7b3dSmrg DBG(("%s: prop[%d] .id=%ld, .name=%s, .flags=%x, .value=%ld\n", __FUNCTION__, i, 2543428d7b3dSmrg (long)props[i], prop.name, (unsigned)prop.flags, (long)values[i])); 2544428d7b3dSmrg 2545428d7b3dSmrg if (strcmp(prop.name, "type") == 0) { 2546428d7b3dSmrg type = values[i]; 2547428d7b3dSmrg } else if (prop_is_rotation(&prop)) { 2548428d7b3dSmrg struct drm_mode_property_enum *enums; 2549428d7b3dSmrg 2550428d7b3dSmrg p->rotation.prop = props[i]; 2551428d7b3dSmrg p->rotation.current = values[i]; 2552428d7b3dSmrg 2553428d7b3dSmrg DBG(("%s: found rotation property .id=%d, value=%ld, num_enums=%d\n", 2554428d7b3dSmrg __FUNCTION__, prop.prop_id, (long)values[i], prop.count_enum_blobs)); 2555428d7b3dSmrg enums = malloc(prop.count_enum_blobs * sizeof(struct drm_mode_property_enum)); 2556428d7b3dSmrg if (enums != NULL) { 2557428d7b3dSmrg prop.count_values = 0; 2558428d7b3dSmrg prop.enum_blob_ptr = (uintptr_t)enums; 2559428d7b3dSmrg 2560428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop) == 0) { 2561428d7b3dSmrg int j; 2562428d7b3dSmrg 2563428d7b3dSmrg /* XXX we assume that the mapping between kernel enum and 2564428d7b3dSmrg * RandR remains fixed for our lifetimes. 2565428d7b3dSmrg */ 2566428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(enums, sizeof(*enums)*prop.count_enum_blobs)); 2567428d7b3dSmrg for (j = 0; j < prop.count_enum_blobs; j++) { 2568428d7b3dSmrg DBG(("%s: rotation[%d] = %s [%lx]\n", __FUNCTION__, 2569428d7b3dSmrg j, enums[j].name, (long)enums[j].value)); 2570428d7b3dSmrg p->rotation.supported |= 1 << enums[j].value; 2571428d7b3dSmrg } 2572428d7b3dSmrg } 2573428d7b3dSmrg 2574428d7b3dSmrg free(enums); 2575428d7b3dSmrg } 2576428d7b3dSmrg } 2577428d7b3dSmrg } 2578428d7b3dSmrg 2579428d7b3dSmrg if (props != (uint32_t *)stack_props) 2580428d7b3dSmrg free(props); 2581428d7b3dSmrg 2582428d7b3dSmrg DBG(("%s: plane=%d type=%d\n", __FUNCTION__, p->id, type)); 2583428d7b3dSmrg return type; 2584428d7b3dSmrg} 2585428d7b3dSmrg 2586428d7b3dSmrgstatic void 2587428d7b3dSmrgsna_crtc_find_planes(struct sna *sna, struct sna_crtc *crtc) 2588428d7b3dSmrg{ 2589428d7b3dSmrg#define LOCAL_IOCTL_SET_CAP DRM_IOWR(0x0d, struct local_set_cap) 2590428d7b3dSmrg#define LOCAL_IOCTL_MODE_GETPLANERESOURCES DRM_IOWR(0xb5, struct local_mode_get_plane_res) 2591428d7b3dSmrg#define LOCAL_IOCTL_MODE_GETPLANE DRM_IOWR(0xb6, struct local_mode_get_plane) 2592428d7b3dSmrg struct local_set_cap { 2593428d7b3dSmrg uint64_t name; 2594428d7b3dSmrg uint64_t value; 2595428d7b3dSmrg } cap; 2596428d7b3dSmrg struct local_mode_get_plane_res { 2597428d7b3dSmrg uint64_t plane_id_ptr; 2598428d7b3dSmrg uint64_t count_planes; 2599428d7b3dSmrg } r; 2600428d7b3dSmrg uint32_t stack_planes[32]; 2601428d7b3dSmrg uint32_t *planes = stack_planes; 2602428d7b3dSmrg int i; 2603428d7b3dSmrg 2604428d7b3dSmrg VG_CLEAR(cap); 2605428d7b3dSmrg cap.name = DRM_CLIENT_CAP_UNIVERSAL_PLANES; 2606428d7b3dSmrg cap.value = 1; 2607428d7b3dSmrg (void)drmIoctl(sna->kgem.fd, LOCAL_IOCTL_SET_CAP, &cap); 2608428d7b3dSmrg 2609428d7b3dSmrg VG_CLEAR(r); 2610428d7b3dSmrg r.plane_id_ptr = (uintptr_t)planes; 2611428d7b3dSmrg r.count_planes = ARRAY_SIZE(stack_planes); 2612428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANERESOURCES, &r)) { 2613428d7b3dSmrg ERR(("%s: GETPLANERESOURCES failed with errno=%d\n", __FUNCTION__, errno)); 2614428d7b3dSmrg return; 2615428d7b3dSmrg } 2616428d7b3dSmrg 2617428d7b3dSmrg DBG(("%s: %d planes\n", __FUNCTION__, (int)r.count_planes)); 2618428d7b3dSmrg 2619428d7b3dSmrg if (r.count_planes > ARRAY_SIZE(stack_planes)) { 2620428d7b3dSmrg planes = malloc(sizeof(uint32_t)*r.count_planes); 2621428d7b3dSmrg if (planes == NULL) 2622428d7b3dSmrg return; 2623428d7b3dSmrg 2624428d7b3dSmrg r.plane_id_ptr = (uintptr_t)planes; 2625428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANERESOURCES, &r)) 2626428d7b3dSmrg r.count_planes = 0; 2627428d7b3dSmrg } 2628428d7b3dSmrg 2629428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(planes, sizeof(uint32_t)*r.count_planes)); 2630428d7b3dSmrg 2631428d7b3dSmrg for (i = 0; i < r.count_planes; i++) { 2632428d7b3dSmrg struct local_mode_get_plane { 2633428d7b3dSmrg uint32_t plane_id; 2634428d7b3dSmrg 2635428d7b3dSmrg uint32_t crtc_id; 2636428d7b3dSmrg uint32_t fb_id; 2637428d7b3dSmrg 2638428d7b3dSmrg uint32_t possible_crtcs; 2639428d7b3dSmrg uint32_t gamma_size; 2640428d7b3dSmrg 2641428d7b3dSmrg uint32_t count_format_types; 2642428d7b3dSmrg uint64_t format_type_ptr; 2643428d7b3dSmrg } p; 2644428d7b3dSmrg struct plane details; 2645428d7b3dSmrg 2646428d7b3dSmrg VG_CLEAR(p); 2647428d7b3dSmrg p.plane_id = planes[i]; 2648428d7b3dSmrg p.count_format_types = 0; 2649428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_GETPLANE, &p)) 2650428d7b3dSmrg continue; 2651428d7b3dSmrg 2652428d7b3dSmrg if ((p.possible_crtcs & (1 << crtc->pipe)) == 0) 2653428d7b3dSmrg continue; 2654428d7b3dSmrg 2655428d7b3dSmrg DBG(("%s: plane %d is attached to our pipe=%d\n", 2656428d7b3dSmrg __FUNCTION__, planes[i], crtc->pipe)); 2657428d7b3dSmrg 2658428d7b3dSmrg details.id = p.plane_id; 2659428d7b3dSmrg details.rotation.prop = 0; 2660428d7b3dSmrg details.rotation.supported = RR_Rotate_0; 2661428d7b3dSmrg details.rotation.current = RR_Rotate_0; 2662428d7b3dSmrg 2663428d7b3dSmrg switch (plane_details(sna, &details)) { 2664428d7b3dSmrg default: 2665428d7b3dSmrg break; 2666428d7b3dSmrg 2667428d7b3dSmrg case DRM_PLANE_TYPE_PRIMARY: 2668428d7b3dSmrg crtc->primary = details; 2669428d7b3dSmrg break; 2670428d7b3dSmrg 2671428d7b3dSmrg case DRM_PLANE_TYPE_CURSOR: 2672428d7b3dSmrg break; 2673428d7b3dSmrg 2674428d7b3dSmrg case DRM_PLANE_TYPE_OVERLAY: 2675428d7b3dSmrg if (crtc->sprite.id == 0) 2676428d7b3dSmrg crtc->sprite = details; 2677428d7b3dSmrg break; 2678428d7b3dSmrg } 2679428d7b3dSmrg } 2680428d7b3dSmrg 2681428d7b3dSmrg if (planes != stack_planes) 2682428d7b3dSmrg free(planes); 2683428d7b3dSmrg} 2684428d7b3dSmrg 2685428d7b3dSmrgstatic void 2686428d7b3dSmrgsna_crtc_init__rotation(struct sna *sna, struct sna_crtc *crtc) 2687428d7b3dSmrg{ 2688428d7b3dSmrg crtc->rotation = RR_Rotate_0; 2689428d7b3dSmrg crtc->primary.rotation.supported = RR_Rotate_0; 2690428d7b3dSmrg crtc->primary.rotation.current = RR_Rotate_0; 2691428d7b3dSmrg crtc->sprite.rotation = crtc->primary.rotation; 2692428d7b3dSmrg} 2693428d7b3dSmrg 2694428d7b3dSmrgstatic void 2695428d7b3dSmrgsna_crtc_init__cursor(struct sna *sna, struct sna_crtc *crtc) 2696428d7b3dSmrg{ 2697428d7b3dSmrg struct drm_mode_cursor arg; 2698428d7b3dSmrg 2699428d7b3dSmrg VG_CLEAR(arg); 2700428d7b3dSmrg arg.flags = DRM_MODE_CURSOR_BO; 2701428d7b3dSmrg arg.crtc_id = crtc->id; 2702428d7b3dSmrg arg.width = arg.height = 0; 2703428d7b3dSmrg arg.handle = 0; 2704428d7b3dSmrg 2705428d7b3dSmrg (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg); 2706428d7b3dSmrg} 2707428d7b3dSmrg 2708428d7b3dSmrgstatic bool 2709428d7b3dSmrgsna_crtc_add(ScrnInfoPtr scrn, int id) 2710428d7b3dSmrg{ 2711428d7b3dSmrg struct sna *sna = to_sna(scrn); 2712428d7b3dSmrg xf86CrtcPtr crtc; 2713428d7b3dSmrg struct sna_crtc *sna_crtc; 2714428d7b3dSmrg struct drm_i915_get_pipe_from_crtc_id get_pipe; 2715428d7b3dSmrg 2716428d7b3dSmrg DBG(("%s(%d)\n", __FUNCTION__, id)); 2717428d7b3dSmrg 2718428d7b3dSmrg sna_crtc = calloc(sizeof(struct sna_crtc), 1); 2719428d7b3dSmrg if (sna_crtc == NULL) 2720428d7b3dSmrg return false; 2721428d7b3dSmrg 2722428d7b3dSmrg sna_crtc->id = id; 2723428d7b3dSmrg sna_crtc->dpms_mode = -1; 2724428d7b3dSmrg 2725428d7b3dSmrg VG_CLEAR(get_pipe); 2726428d7b3dSmrg get_pipe.pipe = 0; 2727428d7b3dSmrg get_pipe.crtc_id = sna_crtc->id; 2728428d7b3dSmrg if (drmIoctl(sna->kgem.fd, 2729428d7b3dSmrg DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID, 2730428d7b3dSmrg &get_pipe)) { 2731428d7b3dSmrg free(sna_crtc); 2732428d7b3dSmrg return false; 2733428d7b3dSmrg } 2734428d7b3dSmrg sna_crtc->pipe = get_pipe.pipe; 2735428d7b3dSmrg 2736428d7b3dSmrg if (is_zaphod(scrn) && 2737428d7b3dSmrg scrn->confScreen->device->screen != sna_crtc->pipe) { 2738428d7b3dSmrg free(sna_crtc); 2739428d7b3dSmrg return true; 2740428d7b3dSmrg } 2741428d7b3dSmrg 2742428d7b3dSmrg sna_crtc_init__rotation(sna, sna_crtc); 2743428d7b3dSmrg 2744428d7b3dSmrg sna_crtc_find_planes(sna, sna_crtc); 2745428d7b3dSmrg 2746428d7b3dSmrg DBG(("%s: CRTC:%d [pipe=%d], primary id=%x: supported-rotations=%x, current-rotation=%x, sprite id=%x: supported-rotations=%x, current-rotation=%x\n", 2747428d7b3dSmrg __FUNCTION__, sna_crtc->id, sna_crtc->pipe, 2748428d7b3dSmrg sna_crtc->primary.id, sna_crtc->primary.rotation.supported, sna_crtc->primary.rotation.current, 2749428d7b3dSmrg sna_crtc->sprite.id, sna_crtc->sprite.rotation.supported, sna_crtc->sprite.rotation.current)); 2750428d7b3dSmrg 2751428d7b3dSmrg list_init(&sna_crtc->shadow_link); 2752428d7b3dSmrg 2753428d7b3dSmrg crtc = xf86CrtcCreate(scrn, &sna_crtc_funcs); 2754428d7b3dSmrg if (crtc == NULL) { 2755428d7b3dSmrg free(sna_crtc); 2756428d7b3dSmrg return false; 2757428d7b3dSmrg } 2758428d7b3dSmrg 2759428d7b3dSmrg sna_crtc_init__cursor(sna, sna_crtc); 2760428d7b3dSmrg 2761428d7b3dSmrg crtc->driver_private = sna_crtc; 2762428d7b3dSmrg sna_crtc->base = crtc; 2763428d7b3dSmrg DBG(("%s: attached crtc[%d] pipe=%d\n", 2764428d7b3dSmrg __FUNCTION__, id, sna_crtc->pipe)); 2765428d7b3dSmrg 2766428d7b3dSmrg return true; 2767428d7b3dSmrg} 2768428d7b3dSmrg 2769428d7b3dSmrgstatic bool 2770428d7b3dSmrgis_panel(int type) 2771428d7b3dSmrg{ 2772428d7b3dSmrg#define DRM_MODE_CONNECTOR_LVDS 7 2773428d7b3dSmrg#define DRM_MODE_CONNECTOR_eDP 14 2774428d7b3dSmrg#define DRM_MODE_CONNECTOR_DSI 16 2775428d7b3dSmrg return (type == DRM_MODE_CONNECTOR_LVDS || 2776428d7b3dSmrg type == DRM_MODE_CONNECTOR_eDP || 2777428d7b3dSmrg type == DRM_MODE_CONNECTOR_DSI); 2778428d7b3dSmrg} 2779428d7b3dSmrg 2780428d7b3dSmrgstatic int 2781428d7b3dSmrgfind_property(struct sna *sna, struct sna_output *output, const char *name) 2782428d7b3dSmrg{ 2783428d7b3dSmrg struct drm_mode_get_property prop; 2784428d7b3dSmrg int i; 2785428d7b3dSmrg 2786428d7b3dSmrg VG_CLEAR(prop); 2787428d7b3dSmrg for (i = 0; i < output->num_props; i++) { 2788428d7b3dSmrg prop.prop_id = output->prop_ids[i]; 2789428d7b3dSmrg prop.count_values = 0; 2790428d7b3dSmrg prop.count_enum_blobs = 0; 2791428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPERTY, &prop)) 2792428d7b3dSmrg continue; 2793428d7b3dSmrg 2794428d7b3dSmrg if (strcmp(prop.name, name) == 0) 2795428d7b3dSmrg return i; 2796428d7b3dSmrg } 2797428d7b3dSmrg 2798428d7b3dSmrg return -1; 2799428d7b3dSmrg} 2800428d7b3dSmrg 2801428d7b3dSmrgstatic xf86OutputStatus 2802428d7b3dSmrgsna_output_detect(xf86OutputPtr output) 2803428d7b3dSmrg{ 2804428d7b3dSmrg struct sna *sna = to_sna(output->scrn); 2805428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 2806428d7b3dSmrg union compat_mode_get_connector compat_conn; 2807428d7b3dSmrg 2808428d7b3dSmrg DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id)); 2809428d7b3dSmrg 2810428d7b3dSmrg if (!sna_output->id) { 2811428d7b3dSmrg DBG(("%s(%s) hiding due to lost connection\n", __FUNCTION__, output->name)); 2812428d7b3dSmrg return XF86OutputStatusDisconnected; 2813428d7b3dSmrg } 2814428d7b3dSmrg 2815428d7b3dSmrg VG_CLEAR(compat_conn); 2816428d7b3dSmrg compat_conn.conn.connector_id = sna_output->id; 2817428d7b3dSmrg sna_output->num_modes = compat_conn.conn.count_modes = 0; /* reprobe */ 2818428d7b3dSmrg compat_conn.conn.count_encoders = 0; 2819428d7b3dSmrg compat_conn.conn.count_props = sna_output->num_props; 2820428d7b3dSmrg compat_conn.conn.props_ptr = (uintptr_t)sna_output->prop_ids; 2821428d7b3dSmrg compat_conn.conn.prop_values_ptr = (uintptr_t)sna_output->prop_values; 2822428d7b3dSmrg 2823428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &compat_conn.conn)) 2824428d7b3dSmrg return XF86OutputStatusUnknown; 2825428d7b3dSmrg DBG(("%s(%s): num modes %d -> %d, num props %d -> %d\n", 2826428d7b3dSmrg __FUNCTION__, output->name, 2827428d7b3dSmrg sna_output->num_modes, compat_conn.conn.count_modes, 2828428d7b3dSmrg sna_output->num_props, compat_conn.conn.count_props)); 2829428d7b3dSmrg 2830428d7b3dSmrg assert(compat_conn.conn.count_props == sna_output->num_props); 2831428d7b3dSmrg 2832428d7b3dSmrg while (compat_conn.conn.count_modes && compat_conn.conn.count_modes != sna_output->num_modes) { 2833428d7b3dSmrg struct drm_mode_modeinfo *new_modes; 2834428d7b3dSmrg int old_count; 2835428d7b3dSmrg 2836428d7b3dSmrg old_count = sna_output->num_modes; 2837428d7b3dSmrg new_modes = realloc(sna_output->modes, 2838428d7b3dSmrg sizeof(*sna_output->modes)*compat_conn.conn.count_modes); 2839428d7b3dSmrg if (new_modes == NULL) 2840428d7b3dSmrg break; 2841428d7b3dSmrg 2842428d7b3dSmrg sna_output->modes = new_modes; 2843428d7b3dSmrg sna_output->num_modes = compat_conn.conn.count_modes; 2844428d7b3dSmrg compat_conn.conn.modes_ptr = (uintptr_t)sna_output->modes; 2845428d7b3dSmrg compat_conn.conn.count_encoders = 0; 2846428d7b3dSmrg compat_conn.conn.count_props = 0; 2847428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &compat_conn.conn)) { 2848428d7b3dSmrg sna_output->num_modes = min(old_count, sna_output->num_modes); 2849428d7b3dSmrg break; 2850428d7b3dSmrg } 2851428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(sna_output->modes, sizeof(*sna_output->modes)*sna_output->num_modes)); 2852428d7b3dSmrg } 2853428d7b3dSmrg 2854428d7b3dSmrg DBG(("%s(%s): found %d modes, connection status=%d\n", 2855428d7b3dSmrg __FUNCTION__, output->name, sna_output->num_modes, compat_conn.conn.connection)); 2856428d7b3dSmrg 2857428d7b3dSmrg switch (compat_conn.conn.connection) { 2858428d7b3dSmrg case DRM_MODE_CONNECTED: 2859428d7b3dSmrg return XF86OutputStatusConnected; 2860428d7b3dSmrg case DRM_MODE_DISCONNECTED: 2861428d7b3dSmrg return XF86OutputStatusDisconnected; 2862428d7b3dSmrg default: 2863428d7b3dSmrg case DRM_MODE_UNKNOWNCONNECTION: 2864428d7b3dSmrg return XF86OutputStatusUnknown; 2865428d7b3dSmrg } 2866428d7b3dSmrg} 2867428d7b3dSmrg 2868428d7b3dSmrgstatic Bool 2869428d7b3dSmrgsna_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) 2870428d7b3dSmrg{ 2871428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 2872428d7b3dSmrg struct sna *sna = to_sna(output->scrn); 2873428d7b3dSmrg 2874428d7b3dSmrg if (mode->HDisplay > sna->mode.max_crtc_width) 2875428d7b3dSmrg return MODE_VIRTUAL_X; 2876428d7b3dSmrg if (mode->VDisplay > sna->mode.max_crtc_height) 2877428d7b3dSmrg return MODE_VIRTUAL_Y; 2878428d7b3dSmrg 2879428d7b3dSmrg /* Check that we can successfully pin this into the global GTT */ 2880428d7b3dSmrg if ((kgem_can_create_2d(&sna->kgem, 2881428d7b3dSmrg mode->HDisplay, mode->VDisplay, 2882428d7b3dSmrg sna->scrn->bitsPerPixel) & KGEM_CAN_CREATE_GTT) == 0) 2883428d7b3dSmrg return MODE_MEM_VIRT; 2884428d7b3dSmrg 2885428d7b3dSmrg /* 2886428d7b3dSmrg * If the connector type is a panel, we will use the panel limit to 2887428d7b3dSmrg * verfiy whether the mode is valid. 2888428d7b3dSmrg */ 2889428d7b3dSmrg if (sna_output->has_panel_limits) { 2890428d7b3dSmrg if (mode->HDisplay > sna_output->panel_hdisplay || 2891428d7b3dSmrg mode->VDisplay > sna_output->panel_vdisplay) 2892428d7b3dSmrg return MODE_PANEL; 2893428d7b3dSmrg } 2894428d7b3dSmrg 2895428d7b3dSmrg return MODE_OK; 2896428d7b3dSmrg} 2897428d7b3dSmrg 2898428d7b3dSmrgstatic void 2899428d7b3dSmrgsna_output_attach_edid(xf86OutputPtr output) 2900428d7b3dSmrg{ 2901428d7b3dSmrg struct sna *sna = to_sna(output->scrn); 2902428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 2903428d7b3dSmrg struct drm_mode_get_blob blob; 2904428d7b3dSmrg void *old, *raw = NULL; 2905428d7b3dSmrg xf86MonPtr mon = NULL; 2906428d7b3dSmrg 2907428d7b3dSmrg if (sna_output->edid_idx == -1) 2908428d7b3dSmrg return; 2909428d7b3dSmrg 2910428d7b3dSmrg raw = sna_output->edid_raw; 2911428d7b3dSmrg blob.length = sna_output->edid_len; 2912428d7b3dSmrg 2913428d7b3dSmrg if (blob.length && output->MonInfo) { 2914428d7b3dSmrg old = alloca(blob.length); 2915428d7b3dSmrg memcpy(old, raw, blob.length); 2916428d7b3dSmrg } else 2917428d7b3dSmrg old = NULL; 2918428d7b3dSmrg 2919428d7b3dSmrg blob.blob_id = sna_output->prop_values[sna_output->edid_idx]; 2920428d7b3dSmrg DBG(("%s: attaching EDID id=%d, current=%d\n", 2921428d7b3dSmrg __FUNCTION__, blob.blob_id, sna_output->edid_blob_id)); 2922428d7b3dSmrg if (blob.blob_id == sna_output->edid_blob_id && 0) { /* sigh */ 2923428d7b3dSmrg if (output->MonInfo) { 2924428d7b3dSmrg /* XXX the property keeps on disappearing... */ 2925428d7b3dSmrg RRChangeOutputProperty(output->randr_output, 2926428d7b3dSmrg MakeAtom("EDID", strlen("EDID"), TRUE), 2927428d7b3dSmrg XA_INTEGER, 8, PropModeReplace, 2928428d7b3dSmrg sna_output->edid_len, 2929428d7b3dSmrg sna_output->edid_raw, 2930428d7b3dSmrg FALSE, FALSE); 2931428d7b3dSmrg 2932428d7b3dSmrg return; 2933428d7b3dSmrg } 2934428d7b3dSmrg 2935428d7b3dSmrg goto skip_read; 2936428d7b3dSmrg } 2937428d7b3dSmrg 2938428d7b3dSmrg blob.data = (uintptr_t)raw; 2939428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) 2940428d7b3dSmrg goto done; 2941428d7b3dSmrg 2942428d7b3dSmrg DBG(("%s: retrieving blob id=%d, length=%d\n", 2943428d7b3dSmrg __FUNCTION__, blob.blob_id, blob.length)); 2944428d7b3dSmrg 2945428d7b3dSmrg if (blob.length > sna_output->edid_len) { 2946428d7b3dSmrg raw = realloc(raw, blob.length); 2947428d7b3dSmrg if (raw == NULL) 2948428d7b3dSmrg goto done; 2949428d7b3dSmrg 2950428d7b3dSmrg VG(memset(raw, 0, blob.length)); 2951428d7b3dSmrg blob.data = (uintptr_t)raw; 2952428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) 2953428d7b3dSmrg goto done; 2954428d7b3dSmrg } 2955428d7b3dSmrg 2956428d7b3dSmrg if (old && 2957428d7b3dSmrg blob.length == sna_output->edid_len && 2958428d7b3dSmrg memcmp(old, raw, blob.length) == 0) { 2959428d7b3dSmrg assert(sna_output->edid_raw == raw); 2960428d7b3dSmrg sna_output->edid_blob_id = blob.blob_id; 2961428d7b3dSmrg RRChangeOutputProperty(output->randr_output, 2962428d7b3dSmrg MakeAtom("EDID", strlen("EDID"), TRUE), 2963428d7b3dSmrg XA_INTEGER, 8, PropModeReplace, 2964428d7b3dSmrg sna_output->edid_len, 2965428d7b3dSmrg sna_output->edid_raw, 2966428d7b3dSmrg FALSE, FALSE); 2967428d7b3dSmrg return; 2968428d7b3dSmrg } 2969428d7b3dSmrg 2970428d7b3dSmrgskip_read: 2971428d7b3dSmrg if (raw) { 2972428d7b3dSmrg mon = xf86InterpretEDID(output->scrn->scrnIndex, raw); 2973428d7b3dSmrg if (mon && blob.length > 128) 2974428d7b3dSmrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 2975428d7b3dSmrg } 2976428d7b3dSmrg 2977428d7b3dSmrgdone: 2978428d7b3dSmrg xf86OutputSetEDID(output, mon); 2979428d7b3dSmrg if (raw) { 2980428d7b3dSmrg sna_output->edid_raw = raw; 2981428d7b3dSmrg sna_output->edid_len = blob.length; 2982428d7b3dSmrg sna_output->edid_blob_id = blob.blob_id; 2983428d7b3dSmrg } 2984428d7b3dSmrg} 2985428d7b3dSmrg 2986428d7b3dSmrgstatic DisplayModePtr 2987428d7b3dSmrgdefault_modes(void) 2988428d7b3dSmrg{ 2989428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,900,0) 2990428d7b3dSmrg return xf86GetDefaultModes(); 2991428d7b3dSmrg#else 2992428d7b3dSmrg return xf86GetDefaultModes(0, 0); 2993428d7b3dSmrg#endif 2994428d7b3dSmrg} 2995428d7b3dSmrg 2996428d7b3dSmrgstatic DisplayModePtr 2997428d7b3dSmrgsna_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes) 2998428d7b3dSmrg{ 2999428d7b3dSmrg xf86MonPtr mon = output->MonInfo; 3000428d7b3dSmrg DisplayModePtr i, m, preferred = NULL; 3001428d7b3dSmrg int max_x = 0, max_y = 0; 3002428d7b3dSmrg float max_vrefresh = 0.0; 3003428d7b3dSmrg 3004428d7b3dSmrg if (mon && GTF_SUPPORTED(mon->features.msc)) 3005428d7b3dSmrg return modes; 3006428d7b3dSmrg 3007428d7b3dSmrg for (m = modes; m; m = m->next) { 3008428d7b3dSmrg if (m->type & M_T_PREFERRED) 3009428d7b3dSmrg preferred = m; 3010428d7b3dSmrg max_x = max(max_x, m->HDisplay); 3011428d7b3dSmrg max_y = max(max_y, m->VDisplay); 3012428d7b3dSmrg max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m)); 3013428d7b3dSmrg } 3014428d7b3dSmrg 3015428d7b3dSmrg max_vrefresh = max(max_vrefresh, 60.0); 3016428d7b3dSmrg max_vrefresh *= (1 + SYNC_TOLERANCE); 3017428d7b3dSmrg 3018428d7b3dSmrg m = default_modes(); 3019428d7b3dSmrg xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0); 3020428d7b3dSmrg 3021428d7b3dSmrg for (i = m; i; i = i->next) { 3022428d7b3dSmrg if (xf86ModeVRefresh(i) > max_vrefresh) 3023428d7b3dSmrg i->status = MODE_VSYNC; 3024428d7b3dSmrg if (preferred && 3025428d7b3dSmrg i->HDisplay >= preferred->HDisplay && 3026428d7b3dSmrg i->VDisplay >= preferred->VDisplay && 3027428d7b3dSmrg xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred)) 3028428d7b3dSmrg i->status = MODE_PANEL; 3029428d7b3dSmrg } 3030428d7b3dSmrg 3031428d7b3dSmrg xf86PruneInvalidModes(output->scrn, &m, FALSE); 3032428d7b3dSmrg 3033428d7b3dSmrg return xf86ModesAdd(modes, m); 3034428d7b3dSmrg} 3035428d7b3dSmrg 3036428d7b3dSmrgstatic DisplayModePtr 3037428d7b3dSmrgsna_output_get_modes(xf86OutputPtr output) 3038428d7b3dSmrg{ 3039428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 3040428d7b3dSmrg DisplayModePtr Modes = NULL, current = NULL; 3041428d7b3dSmrg int i; 3042428d7b3dSmrg 3043428d7b3dSmrg DBG(("%s(%s:%d)\n", __FUNCTION__, output->name, sna_output->id)); 3044428d7b3dSmrg assert(sna_output->id); 3045428d7b3dSmrg 3046428d7b3dSmrg sna_output_attach_edid(output); 3047428d7b3dSmrg 3048428d7b3dSmrg if (output->crtc) { 3049428d7b3dSmrg struct drm_mode_crtc mode; 3050428d7b3dSmrg 3051428d7b3dSmrg VG_CLEAR(mode); 3052428d7b3dSmrg assert(to_sna_crtc(output->crtc)); 3053428d7b3dSmrg mode.crtc_id = to_sna_crtc(output->crtc)->id; 3054428d7b3dSmrg 3055428d7b3dSmrg if (drmIoctl(to_sna(output->scrn)->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode) == 0) { 3056428d7b3dSmrg DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__, 3057428d7b3dSmrg to_sna_crtc(output->crtc)->id, 3058428d7b3dSmrg to_sna_crtc(output->crtc)->pipe, 3059428d7b3dSmrg mode.mode_valid && mode.mode.clock)); 3060428d7b3dSmrg 3061428d7b3dSmrg if (mode.mode_valid && mode.mode.clock) { 3062428d7b3dSmrg current = calloc(1, sizeof(DisplayModeRec)); 3063428d7b3dSmrg if (current) { 3064428d7b3dSmrg mode_from_kmode(output->scrn, &mode.mode, current); 3065428d7b3dSmrg current->type |= M_T_DRIVER | M_T_PREFERRED; 3066428d7b3dSmrg } 3067428d7b3dSmrg } 3068428d7b3dSmrg } 3069428d7b3dSmrg } 3070428d7b3dSmrg 3071428d7b3dSmrg DBG(("%s: adding %d probed modes\n", __FUNCTION__, sna_output->num_modes)); 3072428d7b3dSmrg 3073428d7b3dSmrg for (i = 0; i < sna_output->num_modes; i++) { 3074428d7b3dSmrg DisplayModePtr mode; 3075428d7b3dSmrg 3076428d7b3dSmrg mode = calloc(1, sizeof(DisplayModeRec)); 3077428d7b3dSmrg if (mode == NULL) 3078428d7b3dSmrg continue; 3079428d7b3dSmrg 3080428d7b3dSmrg mode = mode_from_kmode(output->scrn, 3081428d7b3dSmrg &sna_output->modes[i], 3082428d7b3dSmrg mode); 3083428d7b3dSmrg Modes = xf86ModesAdd(Modes, mode); 3084428d7b3dSmrg if (current && xf86ModesEqual(mode, current)) { 3085428d7b3dSmrg free((void*)current->name); 3086428d7b3dSmrg free(current); 3087428d7b3dSmrg current = NULL; 3088428d7b3dSmrg } 3089428d7b3dSmrg if (current && mode->type & M_T_PREFERRED) 3090428d7b3dSmrg current->type &= ~M_T_PREFERRED; 3091428d7b3dSmrg } 3092428d7b3dSmrg 3093428d7b3dSmrg if (current) 3094428d7b3dSmrg Modes = xf86ModesAdd(current, Modes); 3095428d7b3dSmrg 3096428d7b3dSmrg /* 3097428d7b3dSmrg * If the connector type is a panel, we will traverse the kernel mode to 3098428d7b3dSmrg * get the panel limit. And then add all the standard modes to fake 3099428d7b3dSmrg * the fullscreen experience. 3100428d7b3dSmrg * If it is incorrect, please fix me. 3101428d7b3dSmrg */ 3102428d7b3dSmrg sna_output->has_panel_limits = false; 3103428d7b3dSmrg if (sna_output->is_panel) { 3104428d7b3dSmrg sna_output->panel_hdisplay = sna_output->panel_vdisplay = 0; 3105428d7b3dSmrg for (i = 0; i < sna_output->num_modes; i++) { 3106428d7b3dSmrg struct drm_mode_modeinfo *m; 3107428d7b3dSmrg 3108428d7b3dSmrg m = &sna_output->modes[i]; 3109428d7b3dSmrg if (m->hdisplay > sna_output->panel_hdisplay) 3110428d7b3dSmrg sna_output->panel_hdisplay = m->hdisplay; 3111428d7b3dSmrg if (m->vdisplay > sna_output->panel_vdisplay) 3112428d7b3dSmrg sna_output->panel_vdisplay = m->vdisplay; 3113428d7b3dSmrg } 3114428d7b3dSmrg sna_output->has_panel_limits = 3115428d7b3dSmrg sna_output->panel_hdisplay && 3116428d7b3dSmrg sna_output->panel_vdisplay; 3117428d7b3dSmrg } 3118428d7b3dSmrg 3119428d7b3dSmrg if (sna_output->add_default_modes) 3120428d7b3dSmrg Modes = sna_output_panel_edid(output, Modes); 3121428d7b3dSmrg 3122428d7b3dSmrg return Modes; 3123428d7b3dSmrg} 3124428d7b3dSmrg 3125428d7b3dSmrgstatic void 3126428d7b3dSmrgsna_output_destroy(xf86OutputPtr output) 3127428d7b3dSmrg{ 3128428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 3129428d7b3dSmrg int i; 3130428d7b3dSmrg 3131428d7b3dSmrg if (sna_output == NULL) 3132428d7b3dSmrg return; 3133428d7b3dSmrg 3134428d7b3dSmrg free(sna_output->edid_raw); 3135428d7b3dSmrg for (i = 0; i < sna_output->num_props; i++) { 3136428d7b3dSmrg if (sna_output->props[i].kprop == NULL) 3137428d7b3dSmrg continue; 3138428d7b3dSmrg 3139428d7b3dSmrg if (sna_output->props[i].atoms) { 3140428d7b3dSmrg if (output->randr_output) 3141428d7b3dSmrg RRDeleteOutputProperty(output->randr_output, sna_output->props[i].atoms[0]); 3142428d7b3dSmrg free(sna_output->props[i].atoms); 3143428d7b3dSmrg } 3144428d7b3dSmrg 3145428d7b3dSmrg drmModeFreeProperty(sna_output->props[i].kprop); 3146428d7b3dSmrg } 3147428d7b3dSmrg free(sna_output->props); 3148428d7b3dSmrg free(sna_output->prop_ids); 3149428d7b3dSmrg free(sna_output->prop_values); 3150428d7b3dSmrg 3151428d7b3dSmrg backlight_close(&sna_output->backlight); 3152428d7b3dSmrg 3153428d7b3dSmrg free(sna_output); 3154428d7b3dSmrg output->driver_private = NULL; 3155428d7b3dSmrg} 3156428d7b3dSmrg 3157428d7b3dSmrgstatic void 3158428d7b3dSmrgsna_output_dpms(xf86OutputPtr output, int dpms) 3159428d7b3dSmrg{ 3160428d7b3dSmrg struct sna *sna = to_sna(output->scrn); 3161428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 3162428d7b3dSmrg int old_dpms = sna_output->dpms_mode; 3163428d7b3dSmrg 3164428d7b3dSmrg DBG(("%s(%s:%d): dpms=%d (current: %d), active? %d\n", 3165428d7b3dSmrg __FUNCTION__, output->name, sna_output->id, 3166428d7b3dSmrg dpms, sna_output->dpms_mode, 3167428d7b3dSmrg output->crtc != NULL)); 3168428d7b3dSmrg 3169428d7b3dSmrg if (!sna_output->id) 3170428d7b3dSmrg return; 3171428d7b3dSmrg 3172428d7b3dSmrg if (old_dpms == dpms) 3173428d7b3dSmrg return; 3174428d7b3dSmrg 3175428d7b3dSmrg /* Record the value of the backlight before turning 3176428d7b3dSmrg * off the display, and reset if after turning it on. 3177428d7b3dSmrg * Order is important as the kernel may record and also 3178428d7b3dSmrg * reset the backlight across DPMS. Hence we need to 3179428d7b3dSmrg * record the value before the kernel modifies it 3180428d7b3dSmrg * and reapply it afterwards. 3181428d7b3dSmrg */ 3182428d7b3dSmrg if (sna_output->backlight.iface && dpms != DPMSModeOn) { 3183428d7b3dSmrg if (old_dpms == DPMSModeOn) { 3184428d7b3dSmrg sna_output->backlight_active_level = sna_output_backlight_get(output); 3185428d7b3dSmrg DBG(("%s: saving current backlight %d\n", 3186428d7b3dSmrg __FUNCTION__, sna_output->backlight_active_level)); 3187428d7b3dSmrg } 3188428d7b3dSmrg sna_output->dpms_mode = dpms; 3189428d7b3dSmrg sna_output_backlight_off(sna_output); 3190428d7b3dSmrg } 3191428d7b3dSmrg 3192428d7b3dSmrg if (output->crtc && 3193428d7b3dSmrg drmModeConnectorSetProperty(sna->kgem.fd, 3194428d7b3dSmrg sna_output->id, 3195428d7b3dSmrg sna_output->dpms_id, 3196428d7b3dSmrg dpms)) 3197428d7b3dSmrg dpms = old_dpms; 3198428d7b3dSmrg 3199428d7b3dSmrg if (sna_output->backlight.iface && dpms == DPMSModeOn) { 3200428d7b3dSmrg DBG(("%s: restoring previous backlight %d\n", 3201428d7b3dSmrg __FUNCTION__, sna_output->backlight_active_level)); 3202428d7b3dSmrg sna_output_backlight_on(sna_output); 3203428d7b3dSmrg } 3204428d7b3dSmrg 3205428d7b3dSmrg sna_output->dpms_mode = dpms; 3206428d7b3dSmrg} 3207428d7b3dSmrg 3208428d7b3dSmrgstatic bool 3209428d7b3dSmrgsna_property_ignore(drmModePropertyPtr prop) 3210428d7b3dSmrg{ 3211428d7b3dSmrg if (!prop) 3212428d7b3dSmrg return true; 3213428d7b3dSmrg 3214428d7b3dSmrg /* ignore blob prop */ 3215428d7b3dSmrg if (prop->flags & DRM_MODE_PROP_BLOB) 3216428d7b3dSmrg return true; 3217428d7b3dSmrg 3218428d7b3dSmrg /* ignore standard property */ 3219428d7b3dSmrg if (!strcmp(prop->name, "EDID") || 3220428d7b3dSmrg !strcmp(prop->name, "DPMS")) 3221428d7b3dSmrg return true; 3222428d7b3dSmrg 3223428d7b3dSmrg return false; 3224428d7b3dSmrg} 3225428d7b3dSmrg 3226428d7b3dSmrgstatic void 3227428d7b3dSmrgsna_output_create_ranged_atom(xf86OutputPtr output, Atom *atom, 3228428d7b3dSmrg const char *name, INT32 min, INT32 max, 3229428d7b3dSmrg uint64_t value, Bool immutable) 3230428d7b3dSmrg{ 3231428d7b3dSmrg int err; 3232428d7b3dSmrg INT32 atom_range[2]; 3233428d7b3dSmrg 3234428d7b3dSmrg atom_range[0] = min; 3235428d7b3dSmrg atom_range[1] = max; 3236428d7b3dSmrg 3237428d7b3dSmrg *atom = MakeAtom(name, strlen(name), TRUE); 3238428d7b3dSmrg 3239428d7b3dSmrg err = RRConfigureOutputProperty(output->randr_output, *atom, FALSE, 3240428d7b3dSmrg TRUE, immutable, 2, atom_range); 3241428d7b3dSmrg if (err != 0) 3242428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 3243428d7b3dSmrg "RRConfigureOutputProperty error, %d\n", err); 3244428d7b3dSmrg 3245428d7b3dSmrg err = RRChangeOutputProperty(output->randr_output, *atom, XA_INTEGER, 3246428d7b3dSmrg 32, PropModeReplace, 1, &value, 3247428d7b3dSmrg FALSE, FALSE); 3248428d7b3dSmrg if (err != 0) 3249428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 3250428d7b3dSmrg "RRChangeOutputProperty error, %d\n", err); 3251428d7b3dSmrg} 3252428d7b3dSmrg 3253428d7b3dSmrgstatic void 3254428d7b3dSmrgsna_output_create_resources(xf86OutputPtr output) 3255428d7b3dSmrg{ 3256428d7b3dSmrg struct sna *sna = to_sna(output->scrn); 3257428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 3258428d7b3dSmrg int i, j, err; 3259428d7b3dSmrg 3260428d7b3dSmrg sna_output->props = calloc(sna_output->num_props, 3261428d7b3dSmrg sizeof(struct sna_property)); 3262428d7b3dSmrg if (!sna_output->props) 3263428d7b3dSmrg return; 3264428d7b3dSmrg 3265428d7b3dSmrg for (i = 0; i < sna_output->num_props; i++) { 3266428d7b3dSmrg struct sna_property *p = &sna_output->props[i]; 3267428d7b3dSmrg 3268428d7b3dSmrg p->kprop = drmModeGetProperty(sna->kgem.fd, 3269428d7b3dSmrg sna_output->prop_ids[i]); 3270428d7b3dSmrg if (sna_property_ignore(p->kprop)) { 3271428d7b3dSmrg drmModeFreeProperty(p->kprop); 3272428d7b3dSmrg p->kprop = NULL; 3273428d7b3dSmrg continue; 3274428d7b3dSmrg } 3275428d7b3dSmrg 3276428d7b3dSmrg if (p->kprop->flags & DRM_MODE_PROP_RANGE) { 3277428d7b3dSmrg p->num_atoms = 1; 3278428d7b3dSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 3279428d7b3dSmrg if (!p->atoms) 3280428d7b3dSmrg continue; 3281428d7b3dSmrg 3282428d7b3dSmrg sna_output_create_ranged_atom(output, &p->atoms[0], 3283428d7b3dSmrg p->kprop->name, 3284428d7b3dSmrg p->kprop->values[0], 3285428d7b3dSmrg p->kprop->values[1], 3286428d7b3dSmrg sna_output->prop_values[i], 3287428d7b3dSmrg p->kprop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE); 3288428d7b3dSmrg 3289428d7b3dSmrg } else if (p->kprop->flags & DRM_MODE_PROP_ENUM) { 3290428d7b3dSmrg p->num_atoms = p->kprop->count_enums + 1; 3291428d7b3dSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 3292428d7b3dSmrg if (!p->atoms) 3293428d7b3dSmrg continue; 3294428d7b3dSmrg 3295428d7b3dSmrg p->atoms[0] = MakeAtom(p->kprop->name, strlen(p->kprop->name), TRUE); 3296428d7b3dSmrg for (j = 1; j <= p->kprop->count_enums; j++) { 3297428d7b3dSmrg struct drm_mode_property_enum *e = &p->kprop->enums[j-1]; 3298428d7b3dSmrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 3299428d7b3dSmrg } 3300428d7b3dSmrg 3301428d7b3dSmrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 3302428d7b3dSmrg FALSE, FALSE, 3303428d7b3dSmrg p->kprop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 3304428d7b3dSmrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 3305428d7b3dSmrg if (err != 0) { 3306428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 3307428d7b3dSmrg "RRConfigureOutputProperty error, %d\n", err); 3308428d7b3dSmrg } 3309428d7b3dSmrg 3310428d7b3dSmrg for (j = 0; j < p->kprop->count_enums; j++) 3311428d7b3dSmrg if (p->kprop->enums[j].value == sna_output->prop_values[i]) 3312428d7b3dSmrg break; 3313428d7b3dSmrg /* there's always a matching value */ 3314428d7b3dSmrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 3315428d7b3dSmrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], 3316428d7b3dSmrg FALSE, FALSE); 3317428d7b3dSmrg if (err != 0) { 3318428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 3319428d7b3dSmrg "RRChangeOutputProperty error, %d\n", err); 3320428d7b3dSmrg } 3321428d7b3dSmrg } 3322428d7b3dSmrg } 3323428d7b3dSmrg 3324428d7b3dSmrg if (sna_output->backlight.iface) { 3325428d7b3dSmrg /* Set up the backlight property, which takes effect 3326428d7b3dSmrg * immediately and accepts values only within the 3327428d7b3dSmrg * backlight_range. 3328428d7b3dSmrg */ 3329428d7b3dSmrg sna_output_create_ranged_atom(output, &backlight_atom, 3330428d7b3dSmrg BACKLIGHT_NAME, 0, 3331428d7b3dSmrg sna_output->backlight.max, 3332428d7b3dSmrg sna_output->backlight_active_level, 3333428d7b3dSmrg FALSE); 3334428d7b3dSmrg sna_output_create_ranged_atom(output, 3335428d7b3dSmrg &backlight_deprecated_atom, 3336428d7b3dSmrg BACKLIGHT_DEPRECATED_NAME, 0, 3337428d7b3dSmrg sna_output->backlight.max, 3338428d7b3dSmrg sna_output->backlight_active_level, 3339428d7b3dSmrg FALSE); 3340428d7b3dSmrg } 3341428d7b3dSmrg} 3342428d7b3dSmrg 3343428d7b3dSmrgstatic Bool 3344428d7b3dSmrgsna_output_set_property(xf86OutputPtr output, Atom property, 3345428d7b3dSmrg RRPropertyValuePtr value) 3346428d7b3dSmrg{ 3347428d7b3dSmrg struct sna *sna = to_sna(output->scrn); 3348428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 3349428d7b3dSmrg int i; 3350428d7b3dSmrg 3351428d7b3dSmrg if (property == backlight_atom || property == backlight_deprecated_atom) { 3352428d7b3dSmrg INT32 val; 3353428d7b3dSmrg int ret = 0; 3354428d7b3dSmrg 3355428d7b3dSmrg if (value->type != XA_INTEGER || value->format != 32 || 3356428d7b3dSmrg value->size != 1) 3357428d7b3dSmrg { 3358428d7b3dSmrg return FALSE; 3359428d7b3dSmrg } 3360428d7b3dSmrg 3361428d7b3dSmrg val = *(INT32 *)value->data; 3362428d7b3dSmrg DBG(("%s: setting backlight to %d (max=%d)\n", 3363428d7b3dSmrg __FUNCTION__, (int)val, sna_output->backlight.max)); 3364428d7b3dSmrg if (val < 0 || val > sna_output->backlight.max) 3365428d7b3dSmrg return FALSE; 3366428d7b3dSmrg 3367428d7b3dSmrg sna_output->backlight_active_level = val; 3368428d7b3dSmrg if (sna_output->dpms_mode == DPMSModeOn) 3369428d7b3dSmrg ret = sna_output_backlight_set(sna_output, val); 3370428d7b3dSmrg return ret == 0; 3371428d7b3dSmrg } 3372428d7b3dSmrg 3373428d7b3dSmrg if (!sna_output->id) 3374428d7b3dSmrg return TRUE; 3375428d7b3dSmrg 3376428d7b3dSmrg for (i = 0; i < sna_output->num_props; i++) { 3377428d7b3dSmrg struct sna_property *p = &sna_output->props[i]; 3378428d7b3dSmrg 3379428d7b3dSmrg if (p->atoms == NULL || p->atoms[0] != property) 3380428d7b3dSmrg continue; 3381428d7b3dSmrg 3382428d7b3dSmrg if (p->kprop->flags & DRM_MODE_PROP_RANGE) { 3383428d7b3dSmrg uint32_t val; 3384428d7b3dSmrg 3385428d7b3dSmrg if (value->type != XA_INTEGER || value->format != 32 || 3386428d7b3dSmrg value->size != 1) 3387428d7b3dSmrg return FALSE; 3388428d7b3dSmrg val = *(uint32_t *)value->data; 3389428d7b3dSmrg 3390428d7b3dSmrg drmModeConnectorSetProperty(sna->kgem.fd, sna_output->id, 3391428d7b3dSmrg p->kprop->prop_id, (uint64_t)val); 3392428d7b3dSmrg return TRUE; 3393428d7b3dSmrg } else if (p->kprop->flags & DRM_MODE_PROP_ENUM) { 3394428d7b3dSmrg Atom atom; 3395428d7b3dSmrg const char *name; 3396428d7b3dSmrg int j; 3397428d7b3dSmrg 3398428d7b3dSmrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 3399428d7b3dSmrg return FALSE; 3400428d7b3dSmrg memcpy(&atom, value->data, 4); 3401428d7b3dSmrg name = NameForAtom(atom); 3402428d7b3dSmrg if (name == NULL) 3403428d7b3dSmrg return FALSE; 3404428d7b3dSmrg 3405428d7b3dSmrg /* search for matching name string, then set its value down */ 3406428d7b3dSmrg for (j = 0; j < p->kprop->count_enums; j++) { 3407428d7b3dSmrg if (!strcmp(p->kprop->enums[j].name, name)) { 3408428d7b3dSmrg drmModeConnectorSetProperty(sna->kgem.fd, sna_output->id, 3409428d7b3dSmrg p->kprop->prop_id, p->kprop->enums[j].value); 3410428d7b3dSmrg return TRUE; 3411428d7b3dSmrg } 3412428d7b3dSmrg } 3413428d7b3dSmrg return FALSE; 3414428d7b3dSmrg } 3415428d7b3dSmrg } 3416428d7b3dSmrg 3417428d7b3dSmrg /* We didn't recognise this property, just report success in order 3418428d7b3dSmrg * to allow the set to continue, otherwise we break setting of 3419428d7b3dSmrg * common properties like EDID. 3420428d7b3dSmrg */ 3421428d7b3dSmrg return TRUE; 3422428d7b3dSmrg} 3423428d7b3dSmrg 3424428d7b3dSmrgstatic Bool 3425428d7b3dSmrgsna_output_get_property(xf86OutputPtr output, Atom property) 3426428d7b3dSmrg{ 3427428d7b3dSmrg struct sna_output *sna_output = output->driver_private; 3428428d7b3dSmrg int err; 3429428d7b3dSmrg 3430428d7b3dSmrg if (property == backlight_atom || property == backlight_deprecated_atom) { 3431428d7b3dSmrg INT32 val; 3432428d7b3dSmrg 3433428d7b3dSmrg if (!sna_output->backlight.iface) 3434428d7b3dSmrg return FALSE; 3435428d7b3dSmrg 3436428d7b3dSmrg if (sna_output->dpms_mode == DPMSModeOn) { 3437428d7b3dSmrg val = sna_output_backlight_get(output); 3438428d7b3dSmrg if (val < 0) 3439428d7b3dSmrg return FALSE; 3440428d7b3dSmrg DBG(("%s(%s): output on, reporting actual backlight value [%d]\n", 3441428d7b3dSmrg __FUNCTION__, output->name, val)); 3442428d7b3dSmrg } else { 3443428d7b3dSmrg val = sna_output->backlight_active_level; 3444428d7b3dSmrg DBG(("%s(%s): output off, reporting cached backlight value [%d]\n", 3445428d7b3dSmrg __FUNCTION__, output->name, val)); 3446428d7b3dSmrg } 3447428d7b3dSmrg 3448428d7b3dSmrg err = RRChangeOutputProperty(output->randr_output, property, 3449428d7b3dSmrg XA_INTEGER, 32, PropModeReplace, 1, &val, 3450428d7b3dSmrg FALSE, FALSE); 3451428d7b3dSmrg if (err != 0) { 3452428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 3453428d7b3dSmrg "RRChangeOutputProperty error, %d\n", err); 3454428d7b3dSmrg return FALSE; 3455428d7b3dSmrg } 3456428d7b3dSmrg 3457428d7b3dSmrg return TRUE; 3458428d7b3dSmrg } 3459428d7b3dSmrg 3460428d7b3dSmrg return FALSE; 3461428d7b3dSmrg} 3462428d7b3dSmrg 3463428d7b3dSmrgstatic const xf86OutputFuncsRec sna_output_funcs = { 3464428d7b3dSmrg .create_resources = sna_output_create_resources, 3465428d7b3dSmrg#ifdef RANDR_12_INTERFACE 3466428d7b3dSmrg .set_property = sna_output_set_property, 3467428d7b3dSmrg .get_property = sna_output_get_property, 3468428d7b3dSmrg#endif 3469428d7b3dSmrg .dpms = sna_output_dpms, 3470428d7b3dSmrg .detect = sna_output_detect, 3471428d7b3dSmrg .mode_valid = sna_output_mode_valid, 3472428d7b3dSmrg 3473428d7b3dSmrg .get_modes = sna_output_get_modes, 3474428d7b3dSmrg .destroy = sna_output_destroy 3475428d7b3dSmrg}; 3476428d7b3dSmrg 3477428d7b3dSmrgstatic const int subpixel_conv_table[] = { 3478428d7b3dSmrg SubPixelUnknown, 3479428d7b3dSmrg SubPixelHorizontalRGB, 3480428d7b3dSmrg SubPixelHorizontalBGR, 3481428d7b3dSmrg SubPixelVerticalRGB, 3482428d7b3dSmrg SubPixelVerticalBGR, 3483428d7b3dSmrg SubPixelNone 3484428d7b3dSmrg}; 3485428d7b3dSmrg 3486428d7b3dSmrgstatic const char * const output_names[] = { 3487428d7b3dSmrg /* DRM_MODE_CONNECTOR_Unknown */ "None", 3488428d7b3dSmrg /* DRM_MODE_CONNECTOR_VGA */ "VGA", 3489428d7b3dSmrg /* DRM_MODE_CONNECTOR_DVII */ "DVI", 3490428d7b3dSmrg /* DRM_MODE_CONNECTOR_DVID */ "DVI", 3491428d7b3dSmrg /* DRM_MODE_CONNECTOR_DVIA */ "DVI", 3492428d7b3dSmrg /* DRM_MODE_CONNECTOR_Composite */ "Composite", 3493428d7b3dSmrg /* DRM_MODE_CONNECTOR_SVIDEO */ "TV", 3494428d7b3dSmrg /* DRM_MODE_CONNECTOR_LVDS */ "LVDS", 3495428d7b3dSmrg /* DRM_MODE_CONNECTOR_Component */ "CTV", 3496428d7b3dSmrg /* DRM_MODE_CONNECTOR_9PinDIN */ "DIN", 3497428d7b3dSmrg /* DRM_MODE_CONNECTOR_DisplayPort */ "DP", 3498428d7b3dSmrg /* DRM_MODE_CONNECTOR_HDMIA */ "HDMI", 3499428d7b3dSmrg /* DRM_MODE_CONNECTOR_HDMIB */ "HDMI", 3500428d7b3dSmrg /* DRM_MODE_CONNECTOR_TV */ "TV", 3501428d7b3dSmrg /* DRM_MODE_CONNECTOR_eDP */ "eDP", 3502428d7b3dSmrg /* DRM_MODE_CONNECTOR_VIRTUAL */ "Virtual", 3503428d7b3dSmrg /* DRM_MODE_CONNECTOR_DSI */ "DSI" 3504428d7b3dSmrg}; 3505428d7b3dSmrg 3506428d7b3dSmrgstatic bool 3507428d7b3dSmrgsna_zaphod_match(const char *s, const char *output) 3508428d7b3dSmrg{ 3509428d7b3dSmrg char t[20]; 3510428d7b3dSmrg unsigned int i = 0; 3511428d7b3dSmrg 3512428d7b3dSmrg do { 3513428d7b3dSmrg /* match any outputs in a comma list, stopping at whitespace */ 3514428d7b3dSmrg switch (*s) { 3515428d7b3dSmrg case '\0': 3516428d7b3dSmrg t[i] = '\0'; 3517428d7b3dSmrg return strcmp(t, output) == 0; 3518428d7b3dSmrg 3519428d7b3dSmrg case ',': 3520428d7b3dSmrg t[i] ='\0'; 3521428d7b3dSmrg if (strcmp(t, output) == 0) 3522428d7b3dSmrg return TRUE; 3523428d7b3dSmrg i = 0; 3524428d7b3dSmrg break; 3525428d7b3dSmrg 3526428d7b3dSmrg case ' ': 3527428d7b3dSmrg case '\t': 3528428d7b3dSmrg case '\n': 3529428d7b3dSmrg case '\r': 3530428d7b3dSmrg break; 3531428d7b3dSmrg 3532428d7b3dSmrg default: 3533428d7b3dSmrg t[i++] = *s; 3534428d7b3dSmrg break; 3535428d7b3dSmrg } 3536428d7b3dSmrg 3537428d7b3dSmrg s++; 3538428d7b3dSmrg } while (i < sizeof(t)); 3539428d7b3dSmrg 3540428d7b3dSmrg return false; 3541428d7b3dSmrg} 3542428d7b3dSmrg 3543428d7b3dSmrgstatic bool 3544428d7b3dSmrgoutput_ignored(ScrnInfoPtr scrn, const char *name) 3545428d7b3dSmrg{ 3546428d7b3dSmrg char monitor_name[64]; 3547428d7b3dSmrg const char *monitor; 3548428d7b3dSmrg XF86ConfMonitorPtr conf; 3549428d7b3dSmrg 3550428d7b3dSmrg snprintf(monitor_name, sizeof(monitor_name), "monitor-%s", name); 3551428d7b3dSmrg monitor = xf86findOptionValue(scrn->options, monitor_name); 3552428d7b3dSmrg if (!monitor) 3553428d7b3dSmrg monitor = name; 3554428d7b3dSmrg 3555428d7b3dSmrg conf = xf86findMonitor(monitor, 3556428d7b3dSmrg xf86configptr->conf_monitor_lst); 3557428d7b3dSmrg if (conf == NULL && XF86_CRTC_CONFIG_PTR(scrn)->num_output == 0) 3558428d7b3dSmrg conf = xf86findMonitor(scrn->monitor->id, 3559428d7b3dSmrg xf86configptr->conf_monitor_lst); 3560428d7b3dSmrg if (conf == NULL) 3561428d7b3dSmrg return false; 3562428d7b3dSmrg 3563428d7b3dSmrg return xf86CheckBoolOption(conf->mon_option_lst, "Ignore", 0); 3564428d7b3dSmrg} 3565428d7b3dSmrg 3566428d7b3dSmrgstatic bool 3567428d7b3dSmrggather_encoders(struct sna *sna, uint32_t id, int count, 3568428d7b3dSmrg struct drm_mode_get_encoder *out) 3569428d7b3dSmrg{ 3570428d7b3dSmrg union compat_mode_get_connector compat_conn; 3571428d7b3dSmrg struct drm_mode_modeinfo dummy; 3572428d7b3dSmrg struct drm_mode_get_encoder enc; 3573428d7b3dSmrg uint32_t *ids = NULL; 3574428d7b3dSmrg 3575428d7b3dSmrg VG_CLEAR(compat_conn); 3576428d7b3dSmrg memset(out, 0, sizeof(*out)); 3577428d7b3dSmrg 3578428d7b3dSmrg do { 3579428d7b3dSmrg free(ids); 3580428d7b3dSmrg ids = malloc(sizeof(*ids) * count); 3581428d7b3dSmrg if (ids == 0) 3582428d7b3dSmrg return false; 3583428d7b3dSmrg 3584428d7b3dSmrg compat_conn.conn.connector_id = id; 3585428d7b3dSmrg compat_conn.conn.count_props = 0; 3586428d7b3dSmrg compat_conn.conn.count_modes = 1; /* skip detect */ 3587428d7b3dSmrg compat_conn.conn.modes_ptr = (uintptr_t)&dummy; 3588428d7b3dSmrg compat_conn.conn.count_encoders = count; 3589428d7b3dSmrg compat_conn.conn.encoders_ptr = (uintptr_t)ids; 3590428d7b3dSmrg 3591428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &compat_conn.conn)) { 3592428d7b3dSmrg DBG(("%s: GETCONNECTOR[%d] failed, ret=%d\n", __FUNCTION__, id, errno)); 3593428d7b3dSmrg compat_conn.conn.count_encoders = count = 0; 3594428d7b3dSmrg } 3595428d7b3dSmrg 3596428d7b3dSmrg if (count == compat_conn.conn.count_encoders) 3597428d7b3dSmrg break; 3598428d7b3dSmrg 3599428d7b3dSmrg count = compat_conn.conn.count_encoders; 3600428d7b3dSmrg } while (1); 3601428d7b3dSmrg 3602428d7b3dSmrg for (count = 0; count < compat_conn.conn.count_encoders; count++) { 3603428d7b3dSmrg enc.encoder_id = ids[count]; 3604428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETENCODER, &enc)) { 3605428d7b3dSmrg DBG(("%s: GETENCODER[%d] failed, ret=%d\n", __FUNCTION__, ids[count], errno)); 3606428d7b3dSmrg count = 0; 3607428d7b3dSmrg break; 3608428d7b3dSmrg } 3609428d7b3dSmrg out->possible_crtcs |= enc.possible_crtcs; 3610428d7b3dSmrg out->possible_clones |= enc.possible_clones; 3611428d7b3dSmrg 3612428d7b3dSmrg for (id = 0; id < sna->mode.num_real_encoder; id++) { 3613428d7b3dSmrg if (enc.encoder_id == sna->mode.encoders[id]) { 3614428d7b3dSmrg out->crtc_id |= 1 << id; 3615428d7b3dSmrg break; 3616428d7b3dSmrg } 3617428d7b3dSmrg } 3618428d7b3dSmrg } 3619428d7b3dSmrg 3620428d7b3dSmrg free(ids); 3621428d7b3dSmrg return count > 0; 3622428d7b3dSmrg} 3623428d7b3dSmrg 3624428d7b3dSmrg/* We need to map from kms encoder based possible_clones mask to X output based 3625428d7b3dSmrg * possible clones masking. Note that for SDVO and on Haswell with DP/HDMI we 3626428d7b3dSmrg * can have more than one output hanging off the same encoder. 3627428d7b3dSmrg */ 3628428d7b3dSmrgstatic void 3629428d7b3dSmrgsna_mode_compute_possible_outputs(struct sna *sna) 3630428d7b3dSmrg{ 3631428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 3632428d7b3dSmrg int encoder_mask[32]; 3633428d7b3dSmrg int i, j; 3634428d7b3dSmrg 3635428d7b3dSmrg assert(sna->mode.num_real_output < 32); 3636428d7b3dSmrg assert(sna->mode.num_real_crtc < 32); 3637428d7b3dSmrg 3638428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 3639428d7b3dSmrg xf86OutputPtr output = config->output[i]; 3640428d7b3dSmrg struct sna_output *sna_output = to_sna_output(output); 3641428d7b3dSmrg 3642428d7b3dSmrg assert(sna_output); 3643428d7b3dSmrg 3644428d7b3dSmrg if (sna_output->id) { 3645428d7b3dSmrg output->possible_clones = sna_output->possible_encoders; 3646428d7b3dSmrg encoder_mask[i] = sna_output->attached_encoders; 3647428d7b3dSmrg } else { 3648428d7b3dSmrg output->possible_clones = 0; 3649428d7b3dSmrg encoder_mask[i] = 0; 3650428d7b3dSmrg } 3651428d7b3dSmrg } 3652428d7b3dSmrg 3653428d7b3dSmrg /* Convert from encoder numbering to output numbering */ 3654428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 3655428d7b3dSmrg xf86OutputPtr output = config->output[i]; 3656428d7b3dSmrg unsigned clones; 3657428d7b3dSmrg 3658428d7b3dSmrg if (output->possible_clones == 0) 3659428d7b3dSmrg continue; 3660428d7b3dSmrg 3661428d7b3dSmrg clones = 0; 3662428d7b3dSmrg for (j = 0; j < sna->mode.num_real_output; j++) 3663428d7b3dSmrg if (i != j && output->possible_clones & encoder_mask[j]) 3664428d7b3dSmrg clones |= 1 << j; 3665428d7b3dSmrg output->possible_clones = clones; 3666428d7b3dSmrg 3667428d7b3dSmrg DBG(("%s: updated output '%s' %d [%d] (possible crtc:%x, possible clones:%x)\n", 3668428d7b3dSmrg __FUNCTION__, output->name, i, to_connector_id(output), 3669428d7b3dSmrg (uint32_t)output->possible_crtcs, 3670428d7b3dSmrg (uint32_t)output->possible_clones)); 3671428d7b3dSmrg } 3672428d7b3dSmrg} 3673428d7b3dSmrg 3674428d7b3dSmrgstatic int name_from_path(struct sna *sna, 3675428d7b3dSmrg struct sna_output *sna_output, 3676428d7b3dSmrg char *name) 3677428d7b3dSmrg{ 3678428d7b3dSmrg struct drm_mode_get_blob blob; 3679428d7b3dSmrg char *path; 3680428d7b3dSmrg int id; 3681428d7b3dSmrg 3682428d7b3dSmrg id = find_property(sna, sna_output, "PATH"); 3683428d7b3dSmrg DBG(("%s: found? PATH=%d\n", __FUNCTION__, id)); 3684428d7b3dSmrg if (id == -1) 3685428d7b3dSmrg return 0; 3686428d7b3dSmrg 3687428d7b3dSmrg VG_CLEAR(blob); 3688428d7b3dSmrg blob.blob_id = sna_output->prop_values[id]; 3689428d7b3dSmrg blob.length = 0; 3690428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) 3691428d7b3dSmrg return 0; 3692428d7b3dSmrg 3693428d7b3dSmrg do { 3694428d7b3dSmrg id = blob.length; 3695428d7b3dSmrg path = alloca(id + 1); 3696428d7b3dSmrg blob.data = (uintptr_t)path; 3697428d7b3dSmrg VG(memset(path, 0, id)); 3698428d7b3dSmrg DBG(("%s: reading %d bytes for path blob\n", __FUNCTION__, id)); 3699428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETPROPBLOB, &blob)) 3700428d7b3dSmrg return 0; 3701428d7b3dSmrg } while (id != blob.length); 3702428d7b3dSmrg 3703428d7b3dSmrg path[blob.length] = '\0'; /* paranoia */ 3704428d7b3dSmrg DBG(("%s: PATH='%s'\n", __FUNCTION__, path)); 3705428d7b3dSmrg 3706428d7b3dSmrg /* we only handle MST paths for now */ 3707428d7b3dSmrg if (strncmp(path, "mst:", 4) == 0) { 3708428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 3709428d7b3dSmrg char tmp[5], *c; 3710428d7b3dSmrg int n; 3711428d7b3dSmrg 3712428d7b3dSmrg c = strchr(path + 4, '-'); 3713428d7b3dSmrg if (c == NULL) 3714428d7b3dSmrg return 0; 3715428d7b3dSmrg 3716428d7b3dSmrg id = c - (path + 4); 3717428d7b3dSmrg if (id + 1> 5) 3718428d7b3dSmrg return 0; 3719428d7b3dSmrg 3720428d7b3dSmrg memcpy(tmp, path + 4, id); 3721428d7b3dSmrg tmp[id] = '\0'; 3722428d7b3dSmrg id = strtoul(tmp, NULL, 0); 3723428d7b3dSmrg 3724428d7b3dSmrg for (n = 0; n < sna->mode.num_real_output; n++) { 3725428d7b3dSmrg if (to_sna_output(config->output[n])->id == id) 3726428d7b3dSmrg return snprintf(name, 32, "%s-%s", 3727428d7b3dSmrg config->output[n]->name, c + 1); 3728428d7b3dSmrg } 3729428d7b3dSmrg } 3730428d7b3dSmrg 3731428d7b3dSmrg return 0; 3732428d7b3dSmrg} 3733428d7b3dSmrg 3734428d7b3dSmrgstatic int 3735428d7b3dSmrgsna_output_add(struct sna *sna, unsigned id, unsigned serial) 3736428d7b3dSmrg{ 3737428d7b3dSmrg ScrnInfoPtr scrn = sna->scrn; 3738428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3739428d7b3dSmrg union compat_mode_get_connector compat_conn; 3740428d7b3dSmrg struct drm_mode_get_encoder enc; 3741428d7b3dSmrg struct drm_mode_modeinfo dummy; 3742428d7b3dSmrg struct sna_output *sna_output; 3743428d7b3dSmrg xf86OutputPtr *outputs, output; 3744428d7b3dSmrg unsigned possible_encoders, attached_encoders, possible_crtcs; 3745428d7b3dSmrg const char *output_name; 3746428d7b3dSmrg char name[32]; 3747428d7b3dSmrg int path, len, i; 3748428d7b3dSmrg 3749428d7b3dSmrg DBG(("%s(%d): serial=%d\n", __FUNCTION__, id, serial)); 3750428d7b3dSmrg 3751428d7b3dSmrg COMPILE_TIME_ASSERT(sizeof(struct drm_mode_get_connector) <= sizeof(compat_conn.pad)); 3752428d7b3dSmrg 3753428d7b3dSmrg VG_CLEAR(compat_conn); 3754428d7b3dSmrg memset(&enc, 0, sizeof(enc)); 3755428d7b3dSmrg 3756428d7b3dSmrg compat_conn.conn.connector_id = id; 3757428d7b3dSmrg compat_conn.conn.count_props = 0; 3758428d7b3dSmrg compat_conn.conn.count_modes = 1; /* skip detect */ 3759428d7b3dSmrg compat_conn.conn.modes_ptr = (uintptr_t)&dummy; 3760428d7b3dSmrg compat_conn.conn.count_encoders = 1; 3761428d7b3dSmrg compat_conn.conn.encoders_ptr = (uintptr_t)&enc.encoder_id; 3762428d7b3dSmrg 3763428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &compat_conn.conn)) { 3764428d7b3dSmrg DBG(("%s: GETCONNECTOR[%d] failed, ret=%d\n", __FUNCTION__, id, errno)); 3765428d7b3dSmrg return -1; 3766428d7b3dSmrg } 3767428d7b3dSmrg assert(compat_conn.conn.connector_id == id); 3768428d7b3dSmrg 3769428d7b3dSmrg if (compat_conn.conn.connector_type < ARRAY_SIZE(output_names)) 3770428d7b3dSmrg output_name = output_names[compat_conn.conn.connector_type]; 3771428d7b3dSmrg else 3772428d7b3dSmrg output_name = "UNKNOWN"; 3773428d7b3dSmrg len = snprintf(name, 32, "%s%d", output_name, compat_conn.conn.connector_type_id); 3774428d7b3dSmrg if (output_ignored(scrn, name)) 3775428d7b3dSmrg return 0; 3776428d7b3dSmrg 3777428d7b3dSmrg if (enc.encoder_id) { 3778428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETENCODER, &enc)) { 3779428d7b3dSmrg DBG(("%s: GETENCODER[%d] failed, ret=%d\n", __FUNCTION__, enc.encoder_id, errno)); 3780428d7b3dSmrg return 0; 3781428d7b3dSmrg } 3782428d7b3dSmrg 3783428d7b3dSmrg possible_encoders = enc.possible_clones; 3784428d7b3dSmrg attached_encoders = 0; 3785428d7b3dSmrg for (i = 0; i < sna->mode.num_real_encoder; i++) { 3786428d7b3dSmrg if (enc.encoder_id == sna->mode.encoders[i]) { 3787428d7b3dSmrg attached_encoders = 1 << i; 3788428d7b3dSmrg break; 3789428d7b3dSmrg } 3790428d7b3dSmrg } 3791428d7b3dSmrg 3792428d7b3dSmrg if (attached_encoders == 0) { 3793428d7b3dSmrg DBG(("%s: failed to find attached encoder\n", __FUNCTION__)); 3794428d7b3dSmrg return 0; 3795428d7b3dSmrg } 3796428d7b3dSmrg 3797428d7b3dSmrg possible_crtcs = enc.possible_crtcs; 3798428d7b3dSmrg assert(enc.encoder_id == compat_conn.conn.encoder_id || compat_conn.conn.encoder_id == 0); 3799428d7b3dSmrg } else { 3800428d7b3dSmrg DBG(("%s: unexpected number [%d] of encoders attached\n", 3801428d7b3dSmrg __FUNCTION__, compat_conn.conn.count_encoders)); 3802428d7b3dSmrg if (!gather_encoders(sna, id, compat_conn.conn.count_encoders, &enc)) { 3803428d7b3dSmrg DBG(("%s: gather encoders failed\n", __FUNCTION__)); 3804428d7b3dSmrg return 0; 3805428d7b3dSmrg } 3806428d7b3dSmrg possible_encoders = enc.possible_clones; 3807428d7b3dSmrg attached_encoders = enc.crtc_id; 3808428d7b3dSmrg possible_crtcs = enc.possible_crtcs; 3809428d7b3dSmrg 3810428d7b3dSmrg memset(&enc, 0, sizeof(enc)); 3811428d7b3dSmrg enc.encoder_id = compat_conn.conn.encoder_id; 3812428d7b3dSmrg (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETENCODER, &enc); 3813428d7b3dSmrg } 3814428d7b3dSmrg 3815428d7b3dSmrg if (is_zaphod(scrn)) { 3816428d7b3dSmrg const char *str; 3817428d7b3dSmrg 3818428d7b3dSmrg str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD); 3819428d7b3dSmrg if (str && !sna_zaphod_match(str, name)) { 3820428d7b3dSmrg DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name)); 3821428d7b3dSmrg return 0; 3822428d7b3dSmrg } 3823428d7b3dSmrg 3824428d7b3dSmrg if ((possible_crtcs & (1 << scrn->confScreen->device->screen)) == 0) { 3825428d7b3dSmrg if (str) { 3826428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 3827428d7b3dSmrg "%s is an invalid output for screen (pipe) %d\n", 3828428d7b3dSmrg name, scrn->confScreen->device->screen); 3829428d7b3dSmrg return -1; 3830428d7b3dSmrg } else 3831428d7b3dSmrg return 0; 3832428d7b3dSmrg } 3833428d7b3dSmrg 3834428d7b3dSmrg possible_crtcs = 1; 3835428d7b3dSmrg } 3836428d7b3dSmrg 3837428d7b3dSmrg sna_output = calloc(sizeof(struct sna_output), 1); 3838428d7b3dSmrg if (!sna_output) 3839428d7b3dSmrg return -1; 3840428d7b3dSmrg 3841428d7b3dSmrg sna_output->num_props = compat_conn.conn.count_props; 3842428d7b3dSmrg sna_output->prop_ids = malloc(sizeof(uint32_t)*compat_conn.conn.count_props); 3843428d7b3dSmrg sna_output->prop_values = malloc(sizeof(uint64_t)*compat_conn.conn.count_props); 3844428d7b3dSmrg 3845428d7b3dSmrg compat_conn.conn.count_encoders = 0; 3846428d7b3dSmrg 3847428d7b3dSmrg compat_conn.conn.count_modes = 1; 3848428d7b3dSmrg compat_conn.conn.modes_ptr = (uintptr_t)&dummy; 3849428d7b3dSmrg 3850428d7b3dSmrg compat_conn.conn.count_props = sna_output->num_props; 3851428d7b3dSmrg compat_conn.conn.props_ptr = (uintptr_t)sna_output->prop_ids; 3852428d7b3dSmrg compat_conn.conn.prop_values_ptr = (uintptr_t)sna_output->prop_values; 3853428d7b3dSmrg 3854428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCONNECTOR, &compat_conn.conn)) { 3855428d7b3dSmrg DBG(("%s: second! GETCONNECTOR failed, ret=%d\n", __FUNCTION__, errno)); 3856428d7b3dSmrg goto cleanup; 3857428d7b3dSmrg } 3858428d7b3dSmrg assert(compat_conn.conn.connector_id == id); 3859428d7b3dSmrg 3860428d7b3dSmrg /* statically constructed property list */ 3861428d7b3dSmrg assert(sna_output->num_props == compat_conn.conn.count_props); 3862428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(sna_output->prop_ids, sizeof(uint32_t)*sna_output->num_props)); 3863428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(sna_output->prop_values, sizeof(uint64_t)*sna_output->num_props)); 3864428d7b3dSmrg 3865428d7b3dSmrg /* Construct name from topology, and recheck if output is acceptable */ 3866428d7b3dSmrg path = name_from_path(sna, sna_output, name); 3867428d7b3dSmrg if (path) { 3868428d7b3dSmrg const char *str; 3869428d7b3dSmrg 3870428d7b3dSmrg if (output_ignored(scrn, name)) { 3871428d7b3dSmrg len = 0; 3872428d7b3dSmrg goto skip; 3873428d7b3dSmrg } 3874428d7b3dSmrg 3875428d7b3dSmrg str = xf86GetOptValString(sna->Options, OPTION_ZAPHOD); 3876428d7b3dSmrg if (str && !sna_zaphod_match(str, name)) { 3877428d7b3dSmrg DBG(("%s: zaphod mismatch, want %s, have %s\n", __FUNCTION__, str, name)); 3878428d7b3dSmrg len = 0; 3879428d7b3dSmrg goto skip; 3880428d7b3dSmrg } 3881428d7b3dSmrg 3882428d7b3dSmrg len = path; 3883428d7b3dSmrg } 3884428d7b3dSmrg 3885428d7b3dSmrg /* Check if we are dynamically reattaching an old connector */ 3886428d7b3dSmrg if (serial) { 3887428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 3888428d7b3dSmrg output = config->output[i]; 3889428d7b3dSmrg if (strcmp(output->name, name) == 0) { 3890428d7b3dSmrg assert(output->scrn == scrn); 3891428d7b3dSmrg assert(output->funcs == &sna_output_funcs); 3892428d7b3dSmrg assert(to_sna_output(output)->id == 0); 3893428d7b3dSmrg sna_output_destroy(output); 3894428d7b3dSmrg goto reset; 3895428d7b3dSmrg } 3896428d7b3dSmrg } 3897428d7b3dSmrg } 3898428d7b3dSmrg 3899428d7b3dSmrg output = calloc(1, sizeof(*output) + len + 1); 3900428d7b3dSmrg if (!output) 3901428d7b3dSmrg goto cleanup; 3902428d7b3dSmrg 3903428d7b3dSmrg outputs = realloc(config->output, (config->num_output + 1) * sizeof(output)); 3904428d7b3dSmrg if (outputs == NULL) { 3905428d7b3dSmrg free(output); 3906428d7b3dSmrg goto cleanup; 3907428d7b3dSmrg } 3908428d7b3dSmrg 3909428d7b3dSmrg output->scrn = scrn; 3910428d7b3dSmrg output->funcs = &sna_output_funcs; 3911428d7b3dSmrg output->name = (char *)(output + 1); 3912428d7b3dSmrg memcpy(output->name, name, len + 1); 3913428d7b3dSmrg 3914428d7b3dSmrg output->use_screen_monitor = config->num_output != 0; 3915428d7b3dSmrg xf86OutputUseScreenMonitor(output, !output->use_screen_monitor); 3916428d7b3dSmrg assert(output->options); 3917428d7b3dSmrg 3918428d7b3dSmrg DBG(("%s: inserting output #%d of %d\n", __FUNCTION__, sna->mode.num_real_output, config->num_output)); 3919428d7b3dSmrg for (i = config->num_output; i > sna->mode.num_real_output; i--) { 3920428d7b3dSmrg outputs[i] = outputs[i-1]; 3921428d7b3dSmrg assert(outputs[i]->driver_private == NULL); 3922428d7b3dSmrg outputs[i]->possible_clones <<= 1; 3923428d7b3dSmrg } 3924428d7b3dSmrg 3925428d7b3dSmrg if (xf86ReturnOptValBool(output->options, OPTION_PRIMARY, FALSE)) { 3926428d7b3dSmrg memmove(outputs + 1, outputs, sizeof(output)*config->num_output); 3927428d7b3dSmrg outputs[0] = output; 3928428d7b3dSmrg } else 3929428d7b3dSmrg outputs[i] = output; 3930428d7b3dSmrg sna->mode.num_real_output++; 3931428d7b3dSmrg config->num_output++; 3932428d7b3dSmrg config->output = outputs; 3933428d7b3dSmrg 3934428d7b3dSmrgreset: 3935428d7b3dSmrg sna_output->id = compat_conn.conn.connector_id; 3936428d7b3dSmrg sna_output->is_panel = is_panel(compat_conn.conn.connector_type); 3937428d7b3dSmrg sna_output->edid_idx = find_property(sna, sna_output, "EDID"); 3938428d7b3dSmrg if (find_property(sna, sna_output, "scaling mode") != -1) 3939428d7b3dSmrg sna_output->add_default_modes = 3940428d7b3dSmrg xf86ReturnOptValBool(output->options, OPTION_DEFAULT_MODES, TRUE); 3941428d7b3dSmrg 3942428d7b3dSmrg i = find_property(sna, sna_output, "DPMS"); 3943428d7b3dSmrg if (i != -1) { 3944428d7b3dSmrg sna_output->dpms_id = sna_output->prop_ids[i]; 3945428d7b3dSmrg sna_output->dpms_mode = sna_output->prop_values[i]; 3946428d7b3dSmrg DBG(("%s: found 'DPMS' (idx=%d, id=%d), initial value=%d\n", 3947428d7b3dSmrg __FUNCTION__, i, sna_output->dpms_id, sna_output->dpms_mode)); 3948428d7b3dSmrg } else { 3949428d7b3dSmrg sna_output->dpms_id = -1; 3950428d7b3dSmrg sna_output->dpms_mode = DPMSModeOff; 3951428d7b3dSmrg } 3952428d7b3dSmrg 3953428d7b3dSmrg sna_output->possible_encoders = possible_encoders; 3954428d7b3dSmrg sna_output->attached_encoders = attached_encoders; 3955428d7b3dSmrg 3956428d7b3dSmrg output->mm_width = compat_conn.conn.mm_width; 3957428d7b3dSmrg output->mm_height = compat_conn.conn.mm_height; 3958428d7b3dSmrg 3959428d7b3dSmrg if (compat_conn.conn.subpixel >= ARRAY_SIZE(subpixel_conv_table)) 3960428d7b3dSmrg compat_conn.conn.subpixel = 0; 3961428d7b3dSmrg output->subpixel_order = subpixel_conv_table[compat_conn.conn.subpixel]; 3962428d7b3dSmrg output->driver_private = sna_output; 3963428d7b3dSmrg sna_output->base = output; 3964428d7b3dSmrg 3965428d7b3dSmrg backlight_init(&sna_output->backlight); 3966428d7b3dSmrg if (sna_output->is_panel) 3967428d7b3dSmrg sna_output_backlight_init(output); 3968428d7b3dSmrg 3969428d7b3dSmrg output->possible_crtcs = possible_crtcs & count_to_mask(sna->mode.num_real_crtc); 3970428d7b3dSmrg output->interlaceAllowed = TRUE; 3971428d7b3dSmrg 3972428d7b3dSmrg if (serial) { 3973428d7b3dSmrg if (output->randr_output == NULL) { 3974428d7b3dSmrg output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), name, len, output); 3975428d7b3dSmrg if (output->randr_output == NULL) 3976428d7b3dSmrg goto cleanup; 3977428d7b3dSmrg } 3978428d7b3dSmrg 3979428d7b3dSmrg sna_output_create_resources(output); 3980428d7b3dSmrg RRPostPendingProperties(output->randr_output); 3981428d7b3dSmrg 3982428d7b3dSmrg sna_output->serial = serial; 3983428d7b3dSmrg } else { 3984428d7b3dSmrg /* stash the active CRTC id for our probe function */ 3985428d7b3dSmrg if (compat_conn.conn.connection != DRM_MODE_DISCONNECTED) 3986428d7b3dSmrg output->crtc = (void *)(uintptr_t)enc.crtc_id; 3987428d7b3dSmrg } 3988428d7b3dSmrg 3989428d7b3dSmrg DBG(("%s: created output '%s' %d, encoder=%d (possible crtc:%x, attached encoders:%x, possible clones:%x), serial=%d, edid=%d, dpms=%d, crtc=%lu\n", 3990428d7b3dSmrg __FUNCTION__, name, id, enc.encoder_id, 3991428d7b3dSmrg (uint32_t)output->possible_crtcs, 3992428d7b3dSmrg sna_output->attached_encoders, 3993428d7b3dSmrg sna_output->possible_encoders, 3994428d7b3dSmrg serial, sna_output->edid_idx, sna_output->dpms_id, 3995428d7b3dSmrg (unsigned long)(uintptr_t)output->crtc)); 3996428d7b3dSmrg assert(sna_output->id == id); 3997428d7b3dSmrg 3998428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 3999428d7b3dSmrg "Enabled output %s\n", 4000428d7b3dSmrg output->name); 4001428d7b3dSmrg return 1; 4002428d7b3dSmrg 4003428d7b3dSmrgcleanup: 4004428d7b3dSmrg len = -1; 4005428d7b3dSmrgskip: 4006428d7b3dSmrg free(sna_output->prop_ids); 4007428d7b3dSmrg free(sna_output->prop_values); 4008428d7b3dSmrg free(sna_output); 4009428d7b3dSmrg return len; 4010428d7b3dSmrg} 4011428d7b3dSmrg 4012428d7b3dSmrgstatic void sna_output_del(xf86OutputPtr output) 4013428d7b3dSmrg{ 4014428d7b3dSmrg ScrnInfoPtr scrn = output->scrn; 4015428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 4016428d7b3dSmrg int i; 4017428d7b3dSmrg 4018428d7b3dSmrg DBG(("%s(%s)\n", __FUNCTION__, output->name)); 4019428d7b3dSmrg assert(to_sna_output(output)); 4020428d7b3dSmrg 4021428d7b3dSmrg RROutputDestroy(output->randr_output); 4022428d7b3dSmrg sna_output_destroy(output); 4023428d7b3dSmrg 4024428d7b3dSmrg while (output->probed_modes) 4025428d7b3dSmrg xf86DeleteMode(&output->probed_modes, output->probed_modes); 4026428d7b3dSmrg 4027428d7b3dSmrg free(output); 4028428d7b3dSmrg 4029428d7b3dSmrg for (i = 0; i < config->num_output; i++) 4030428d7b3dSmrg if (config->output[i] == output) 4031428d7b3dSmrg break; 4032428d7b3dSmrg assert(i < to_sna(scrn)->mode.num_real_output); 4033428d7b3dSmrg DBG(("%s: removing output #%d of %d\n", 4034428d7b3dSmrg __FUNCTION__, i, to_sna(scrn)->mode.num_real_output)); 4035428d7b3dSmrg 4036428d7b3dSmrg for (; i < config->num_output; i++) { 4037428d7b3dSmrg config->output[i] = config->output[i+1]; 4038428d7b3dSmrg config->output[i]->possible_clones >>= 1; 4039428d7b3dSmrg } 4040428d7b3dSmrg config->num_output--; 4041428d7b3dSmrg to_sna(scrn)->mode.num_real_output--; 4042428d7b3dSmrg} 4043428d7b3dSmrg 4044428d7b3dSmrgstatic int output_rank(const void *A, const void *B) 4045428d7b3dSmrg{ 4046428d7b3dSmrg const xf86OutputPtr *a = A; 4047428d7b3dSmrg const xf86OutputPtr *b = B; 4048428d7b3dSmrg struct sna_output *sa = to_sna_output(*a); 4049428d7b3dSmrg struct sna_output *sb = to_sna_output(*b); 4050428d7b3dSmrg 4051428d7b3dSmrg if (sa->is_panel != sb->is_panel) 4052428d7b3dSmrg return sb->is_panel - sa->is_panel; 4053428d7b3dSmrg 4054428d7b3dSmrg return strcmp((*a)->name, (*b)->name); 4055428d7b3dSmrg} 4056428d7b3dSmrg 4057428d7b3dSmrgstatic void sort_config_outputs(struct sna *sna) 4058428d7b3dSmrg{ 4059428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 4060428d7b3dSmrg qsort(config->output, sna->mode.num_real_output, sizeof(*config->output), output_rank); 4061428d7b3dSmrg sna_mode_compute_possible_outputs(sna); 4062428d7b3dSmrg} 4063428d7b3dSmrg 4064428d7b3dSmrgstatic void sort_randr_outputs(struct sna *sna, ScreenPtr screen) 4065428d7b3dSmrg{ 4066428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 4067428d7b3dSmrg rrScrPriv(screen); 4068428d7b3dSmrg int i; 4069428d7b3dSmrg 4070428d7b3dSmrg assert(pScrPriv->numOutputs == config->num_output); 4071428d7b3dSmrg for (i = 0; i < config->num_output; i++) { 4072428d7b3dSmrg assert(config->output[i]->randr_output); 4073428d7b3dSmrg pScrPriv->outputs[i] = config->output[i]->randr_output; 4074428d7b3dSmrg } 4075428d7b3dSmrg} 4076428d7b3dSmrg 4077428d7b3dSmrgstatic bool disable_unused_crtc(struct sna *sna) 4078428d7b3dSmrg{ 4079428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 4080428d7b3dSmrg bool update = false; 4081428d7b3dSmrg int o, c; 4082428d7b3dSmrg 4083428d7b3dSmrg for (c = 0; c < sna->mode.num_real_crtc; c++) { 4084428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[c]; 4085428d7b3dSmrg 4086428d7b3dSmrg if (!crtc->enabled) 4087428d7b3dSmrg continue; 4088428d7b3dSmrg 4089428d7b3dSmrg for (o = 0; o < sna->mode.num_real_output; o++) { 4090428d7b3dSmrg xf86OutputPtr output = config->output[o]; 4091428d7b3dSmrg if (output->crtc == crtc) 4092428d7b3dSmrg break; 4093428d7b3dSmrg } 4094428d7b3dSmrg 4095428d7b3dSmrg if (o == sna->mode.num_real_output) { 4096428d7b3dSmrg DBG(("%s: CRTC:%d was enabled with no outputs\n", 4097428d7b3dSmrg __FUNCTION__, to_sna_crtc(crtc)->id)); 4098428d7b3dSmrg crtc->enabled = false; 4099428d7b3dSmrg update = true; 4100428d7b3dSmrg } 4101428d7b3dSmrg } 4102428d7b3dSmrg 4103428d7b3dSmrg if (update) { 4104428d7b3dSmrg DBG(("%s: disabling unused functions\n", __FUNCTION__)); 4105428d7b3dSmrg xf86DisableUnusedFunctions(sna->scrn); 4106428d7b3dSmrg } 4107428d7b3dSmrg 4108428d7b3dSmrg return update; 4109428d7b3dSmrg} 4110428d7b3dSmrg 4111428d7b3dSmrgvoid sna_mode_discover(struct sna *sna) 4112428d7b3dSmrg{ 4113428d7b3dSmrg ScreenPtr screen = xf86ScrnToScreen(sna->scrn); 4114428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 4115428d7b3dSmrg struct drm_mode_card_res res; 4116428d7b3dSmrg uint32_t connectors[32]; 4117428d7b3dSmrg unsigned changed = 0; 4118428d7b3dSmrg unsigned serial; 4119428d7b3dSmrg int i, j; 4120428d7b3dSmrg 4121428d7b3dSmrg DBG(("%s()\n", __FUNCTION__)); 4122428d7b3dSmrg VG_CLEAR(connectors); 4123428d7b3dSmrg 4124428d7b3dSmrg memset(&res, 0, sizeof(res)); 4125428d7b3dSmrg res.count_connectors = 32; 4126428d7b3dSmrg res.connector_id_ptr = (uintptr_t)connectors; 4127428d7b3dSmrg 4128428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 4129428d7b3dSmrg return; 4130428d7b3dSmrg 4131428d7b3dSmrg DBG(("%s: now %d (was %d) connectors\n", __FUNCTION__, 4132428d7b3dSmrg res.count_connectors, sna->mode.num_real_output)); 4133428d7b3dSmrg if (res.count_connectors > 32) 4134428d7b3dSmrg return; 4135428d7b3dSmrg 4136428d7b3dSmrg assert(sna->mode.num_real_crtc == res.count_crtcs || is_zaphod(sna->scrn)); 4137428d7b3dSmrg assert(sna->mode.max_crtc_width == res.max_width); 4138428d7b3dSmrg assert(sna->mode.max_crtc_height == res.max_height); 4139428d7b3dSmrg assert(sna->mode.num_real_encoder == res.count_encoders); 4140428d7b3dSmrg 4141428d7b3dSmrg serial = ++sna->mode.serial; 4142428d7b3dSmrg if (serial == 0) 4143428d7b3dSmrg serial = ++sna->mode.serial; 4144428d7b3dSmrg 4145428d7b3dSmrg for (i = 0; i < res.count_connectors; i++) { 4146428d7b3dSmrg DBG(("%s: connector[%d] = %d\n", __FUNCTION__, i, connectors[i])); 4147428d7b3dSmrg for (j = 0; j < sna->mode.num_real_output; j++) { 4148428d7b3dSmrg xf86OutputPtr output = config->output[j]; 4149428d7b3dSmrg if (to_sna_output(output)->id == connectors[i]) { 4150428d7b3dSmrg DBG(("%s: found %s (id=%d)\n", __FUNCTION__, output->name, connectors[i])); 4151428d7b3dSmrg assert(to_sna_output(output)->id); 4152428d7b3dSmrg to_sna_output(output)->serial = serial; 4153428d7b3dSmrg break; 4154428d7b3dSmrg } 4155428d7b3dSmrg } 4156428d7b3dSmrg if (j == sna->mode.num_real_output) { 4157428d7b3dSmrg DBG(("%s: adding id=%d\n", __FUNCTION__, connectors[i])); 4158428d7b3dSmrg changed |= sna_output_add(sna, connectors[i], serial) > 0; 4159428d7b3dSmrg } 4160428d7b3dSmrg } 4161428d7b3dSmrg 4162428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 4163428d7b3dSmrg xf86OutputPtr output = config->output[i]; 4164428d7b3dSmrg 4165428d7b3dSmrg if (to_sna_output(output)->id == 0) 4166428d7b3dSmrg continue; 4167428d7b3dSmrg 4168428d7b3dSmrg if (to_sna_output(output)->serial == serial) 4169428d7b3dSmrg continue; 4170428d7b3dSmrg 4171428d7b3dSmrg DBG(("%s: removing output %s (id=%d), serial=%u [now %u]\n", 4172428d7b3dSmrg __FUNCTION__, output->name, to_sna_output(output)->id, 4173428d7b3dSmrg to_sna_output(output)->serial, serial)); 4174428d7b3dSmrg 4175428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_INFO, 4176428d7b3dSmrg "%s output %s\n", 4177428d7b3dSmrg sna->flags & SNA_REMOVE_OUTPUTS ? "Removed" : "Disabled", 4178428d7b3dSmrg output->name); 4179428d7b3dSmrg if (sna->flags & SNA_REMOVE_OUTPUTS) { 4180428d7b3dSmrg sna_output_del(output); 4181428d7b3dSmrg i--; 4182428d7b3dSmrg } else { 4183428d7b3dSmrg to_sna_output(output)->id = 0; 4184428d7b3dSmrg output->crtc = NULL; 4185428d7b3dSmrg } 4186428d7b3dSmrg changed |= 2; 4187428d7b3dSmrg } 4188428d7b3dSmrg 4189428d7b3dSmrg if (changed) { 4190428d7b3dSmrg DBG(("%s: outputs changed, broadcasting\n", __FUNCTION__)); 4191428d7b3dSmrg 4192428d7b3dSmrg sna_mode_set_primary(sna); 4193428d7b3dSmrg 4194428d7b3dSmrg /* Reorder user visible listing */ 4195428d7b3dSmrg sort_config_outputs(sna); 4196428d7b3dSmrg sort_randr_outputs(sna, screen); 4197428d7b3dSmrg 4198428d7b3dSmrg if (changed & 2) 4199428d7b3dSmrg disable_unused_crtc(sna); 4200428d7b3dSmrg 4201428d7b3dSmrg xf86RandR12TellChanged(screen); 4202428d7b3dSmrg } 4203428d7b3dSmrg} 4204428d7b3dSmrg 4205428d7b3dSmrgstatic void copy_front(struct sna *sna, PixmapPtr old, PixmapPtr new) 4206428d7b3dSmrg{ 4207428d7b3dSmrg struct sna_pixmap *old_priv, *new_priv; 4208428d7b3dSmrg 4209428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 4210428d7b3dSmrg 4211428d7b3dSmrg if (wedged(sna)) 4212428d7b3dSmrg return; 4213428d7b3dSmrg 4214428d7b3dSmrg old_priv = sna_pixmap_force_to_gpu(old, MOVE_READ); 4215428d7b3dSmrg if (!old_priv) 4216428d7b3dSmrg return; 4217428d7b3dSmrg 4218428d7b3dSmrg new_priv = sna_pixmap_force_to_gpu(new, MOVE_WRITE | __MOVE_SCANOUT); 4219428d7b3dSmrg if (!new_priv) 4220428d7b3dSmrg return; 4221428d7b3dSmrg 4222428d7b3dSmrg if (old_priv->clear) { 4223428d7b3dSmrg (void)sna->render.fill_one(sna, new, new_priv->gpu_bo, 4224428d7b3dSmrg old_priv->clear_color, 4225428d7b3dSmrg 0, 0, 4226428d7b3dSmrg new->drawable.width, 4227428d7b3dSmrg new->drawable.height, 4228428d7b3dSmrg GXcopy); 4229428d7b3dSmrg new_priv->clear = true; 4230428d7b3dSmrg new_priv->clear_color = old_priv->clear_color; 4231428d7b3dSmrg } else { 4232428d7b3dSmrg BoxRec box; 4233428d7b3dSmrg int16_t sx, sy, dx, dy; 4234428d7b3dSmrg 4235428d7b3dSmrg if (new->drawable.width >= old->drawable.width && 4236428d7b3dSmrg new->drawable.height >= old->drawable.height) 4237428d7b3dSmrg { 4238428d7b3dSmrg int nx = (new->drawable.width + old->drawable.width - 1) / old->drawable.width; 4239428d7b3dSmrg int ny = (new->drawable.height + old->drawable.height - 1) / old->drawable.height; 4240428d7b3dSmrg 4241428d7b3dSmrg box.x1 = box.y1 = 0; 4242428d7b3dSmrg 4243428d7b3dSmrg dy = 0; 4244428d7b3dSmrg for (sy = 0; sy < ny; sy++) { 4245428d7b3dSmrg box.y2 = old->drawable.height; 4246428d7b3dSmrg if (box.y2 + dy > new->drawable.height) 4247428d7b3dSmrg box.y2 = new->drawable.height - dy; 4248428d7b3dSmrg 4249428d7b3dSmrg dx = 0; 4250428d7b3dSmrg for (sx = 0; sx < nx; sx++) { 4251428d7b3dSmrg box.x2 = old->drawable.width; 4252428d7b3dSmrg if (box.x2 + dx > new->drawable.width) 4253428d7b3dSmrg box.x2 = new->drawable.width - dx; 4254428d7b3dSmrg 4255428d7b3dSmrg (void)sna->render.copy_boxes(sna, GXcopy, 4256428d7b3dSmrg &old->drawable, old_priv->gpu_bo, 0, 0, 4257428d7b3dSmrg &new->drawable, new_priv->gpu_bo, dx, dy, 4258428d7b3dSmrg &box, 1, 0); 4259428d7b3dSmrg dx += old->drawable.width; 4260428d7b3dSmrg } 4261428d7b3dSmrg dy += old->drawable.height; 4262428d7b3dSmrg } 4263428d7b3dSmrg } else { 4264428d7b3dSmrg box.x1 = box.y1 = 0; 4265428d7b3dSmrg box.x2 = min(old->drawable.width, new->drawable.width); 4266428d7b3dSmrg box.y2 = min(old->drawable.height, new->drawable.height); 4267428d7b3dSmrg 4268428d7b3dSmrg sx = dx = 0; 4269428d7b3dSmrg if (box.x2 < old->drawable.width) 4270428d7b3dSmrg sx = (old->drawable.width - box.x2) / 2; 4271428d7b3dSmrg if (box.x2 < new->drawable.width) 4272428d7b3dSmrg dx = (new->drawable.width - box.x2) / 2; 4273428d7b3dSmrg 4274428d7b3dSmrg sy = dy = 0; 4275428d7b3dSmrg if (box.y2 < old->drawable.height) 4276428d7b3dSmrg sy = (old->drawable.height - box.y2) / 2; 4277428d7b3dSmrg if (box.y2 < new->drawable.height) 4278428d7b3dSmrg dy = (new->drawable.height - box.y2) / 2; 4279428d7b3dSmrg 4280428d7b3dSmrg DBG(("%s: copying box (%dx%d) from (%d, %d) to (%d, %d)\n", 4281428d7b3dSmrg __FUNCTION__, box.x2, box.y2, sx, sy, dx, dy)); 4282428d7b3dSmrg 4283428d7b3dSmrg if (box.x2 != new->drawable.width || box.y2 != new->drawable.height) { 4284428d7b3dSmrg (void)sna->render.fill_one(sna, new, new_priv->gpu_bo, 0, 4285428d7b3dSmrg 0, 0, 4286428d7b3dSmrg new->drawable.width, 4287428d7b3dSmrg new->drawable.height, 4288428d7b3dSmrg GXclear); 4289428d7b3dSmrg } 4290428d7b3dSmrg (void)sna->render.copy_boxes(sna, GXcopy, 4291428d7b3dSmrg &old->drawable, old_priv->gpu_bo, sx, sy, 4292428d7b3dSmrg &new->drawable, new_priv->gpu_bo, dx, dy, 4293428d7b3dSmrg &box, 1, 0); 4294428d7b3dSmrg } 4295428d7b3dSmrg } 4296428d7b3dSmrg 4297428d7b3dSmrg sna_damage_all(&new_priv->gpu_damage, new); 4298428d7b3dSmrg} 4299428d7b3dSmrg 4300428d7b3dSmrgstatic Bool 4301428d7b3dSmrgsna_mode_resize(ScrnInfoPtr scrn, int width, int height) 4302428d7b3dSmrg{ 4303428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 4304428d7b3dSmrg struct sna *sna = to_sna(scrn); 4305428d7b3dSmrg ScreenPtr screen = scrn->pScreen; 4306428d7b3dSmrg PixmapPtr new_front; 4307428d7b3dSmrg int i; 4308428d7b3dSmrg 4309428d7b3dSmrg DBG(("%s (%d, %d) -> (%d, %d)\n", __FUNCTION__, 4310428d7b3dSmrg scrn->virtualX, scrn->virtualY, 4311428d7b3dSmrg width, height)); 4312428d7b3dSmrg assert((sna->flags & SNA_IS_HOSTED) == 0); 4313428d7b3dSmrg 4314428d7b3dSmrg if (scrn->virtualX == width && scrn->virtualY == height) 4315428d7b3dSmrg return TRUE; 4316428d7b3dSmrg 4317428d7b3dSmrg /* Paranoid defense against rogue internal calls by Xorg */ 4318428d7b3dSmrg if (width == 0 || height == 0) 4319428d7b3dSmrg return FALSE; 4320428d7b3dSmrg 4321428d7b3dSmrg assert(sna->front); 4322428d7b3dSmrg assert(screen->GetScreenPixmap(screen) == sna->front); 4323428d7b3dSmrg 4324428d7b3dSmrg DBG(("%s: creating new framebuffer %dx%d\n", 4325428d7b3dSmrg __FUNCTION__, width, height)); 4326428d7b3dSmrg 4327428d7b3dSmrg new_front = screen->CreatePixmap(screen, 4328428d7b3dSmrg width, height, scrn->depth, 4329428d7b3dSmrg SNA_CREATE_FB); 4330428d7b3dSmrg if (!new_front) 4331428d7b3dSmrg return FALSE; 4332428d7b3dSmrg 4333428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 4334428d7b3dSmrg "resizing framebuffer to %dx%d\n", 4335428d7b3dSmrg width, height); 4336428d7b3dSmrg 4337428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) 4338428d7b3dSmrg sna_crtc_disable_shadow(sna, to_sna_crtc(config->crtc[i])); 4339428d7b3dSmrg assert(sna->mode.shadow_active == 0); 4340428d7b3dSmrg assert(sna->mode.shadow_damage == NULL); 4341428d7b3dSmrg assert(sna->mode.shadow == NULL); 4342428d7b3dSmrg 4343428d7b3dSmrg copy_front(sna, sna->front, new_front); 4344428d7b3dSmrg 4345428d7b3dSmrg screen->SetScreenPixmap(new_front); 4346428d7b3dSmrg assert(screen->GetScreenPixmap(screen) == new_front); 4347428d7b3dSmrg assert(sna->front == new_front); 4348428d7b3dSmrg screen->DestroyPixmap(new_front); /* owned by screen now */ 4349428d7b3dSmrg 4350428d7b3dSmrg scrn->virtualX = width; 4351428d7b3dSmrg scrn->virtualY = height; 4352428d7b3dSmrg scrn->displayWidth = width; 4353428d7b3dSmrg 4354428d7b3dSmrg /* Flush pending shadow updates */ 4355428d7b3dSmrg if (sna->mode.flip_active) { 4356428d7b3dSmrg DBG(("%s: waiting for %d outstanding TearFree flips\n", 4357428d7b3dSmrg __FUNCTION__, sna->mode.flip_active)); 4358428d7b3dSmrg while (sna->mode.flip_active && sna_mode_wait_for_event(sna)) 4359428d7b3dSmrg sna_mode_wakeup(sna); 4360428d7b3dSmrg } 4361428d7b3dSmrg 4362428d7b3dSmrg /* Only update the CRTCs if we are in control */ 4363428d7b3dSmrg if (!scrn->vtSema) 4364428d7b3dSmrg return TRUE; 4365428d7b3dSmrg 4366428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 4367428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 4368428d7b3dSmrg 4369428d7b3dSmrg assert(to_sna_crtc(crtc) != NULL); 4370428d7b3dSmrg if (to_sna_crtc(crtc)->bo == NULL) 4371428d7b3dSmrg continue; 4372428d7b3dSmrg 4373428d7b3dSmrg if (!__sna_crtc_set_mode(crtc)) 4374428d7b3dSmrg sna_crtc_disable(crtc); 4375428d7b3dSmrg } 4376428d7b3dSmrg 4377428d7b3dSmrg sna_mode_wakeup(sna); 4378428d7b3dSmrg kgem_clean_scanout_cache(&sna->kgem); 4379428d7b3dSmrg 4380428d7b3dSmrg return TRUE; 4381428d7b3dSmrg} 4382428d7b3dSmrg 4383428d7b3dSmrg/* cursor handling */ 4384428d7b3dSmrgstruct sna_cursor { 4385428d7b3dSmrg struct sna_cursor *next; 4386428d7b3dSmrg uint32_t *image; 4387428d7b3dSmrg Rotation rotation; 4388428d7b3dSmrg int ref; 4389428d7b3dSmrg int size; 4390428d7b3dSmrg int last_width; 4391428d7b3dSmrg int last_height; 4392428d7b3dSmrg unsigned handle; 4393428d7b3dSmrg unsigned serial; 4394428d7b3dSmrg unsigned alloc; 4395428d7b3dSmrg}; 4396428d7b3dSmrg 4397428d7b3dSmrgstatic void 4398428d7b3dSmrgrotate_coord(Rotation rotation, int size, 4399428d7b3dSmrg int x_dst, int y_dst, 4400428d7b3dSmrg int *x_src, int *y_src) 4401428d7b3dSmrg{ 4402428d7b3dSmrg int t; 4403428d7b3dSmrg 4404428d7b3dSmrg switch (rotation & 0xf) { 4405428d7b3dSmrg case RR_Rotate_0: 4406428d7b3dSmrg break; 4407428d7b3dSmrg case RR_Rotate_90: 4408428d7b3dSmrg t = x_dst; 4409428d7b3dSmrg x_dst = size - y_dst - 1; 4410428d7b3dSmrg y_dst = t; 4411428d7b3dSmrg break; 4412428d7b3dSmrg case RR_Rotate_180: 4413428d7b3dSmrg x_dst = size - x_dst - 1; 4414428d7b3dSmrg y_dst = size - y_dst - 1; 4415428d7b3dSmrg break; 4416428d7b3dSmrg case RR_Rotate_270: 4417428d7b3dSmrg t = x_dst; 4418428d7b3dSmrg x_dst = y_dst; 4419428d7b3dSmrg y_dst = size - t - 1; 4420428d7b3dSmrg break; 4421428d7b3dSmrg } 4422428d7b3dSmrg 4423428d7b3dSmrg if (rotation & RR_Reflect_X) 4424428d7b3dSmrg x_dst = size - x_dst - 1; 4425428d7b3dSmrg if (rotation & RR_Reflect_Y) 4426428d7b3dSmrg y_dst = size - y_dst - 1; 4427428d7b3dSmrg 4428428d7b3dSmrg *x_src = x_dst; 4429428d7b3dSmrg *y_src = y_dst; 4430428d7b3dSmrg} 4431428d7b3dSmrg 4432428d7b3dSmrgstatic void 4433428d7b3dSmrgrotate_coord_back(Rotation rotation, int size, int *x, int *y) 4434428d7b3dSmrg{ 4435428d7b3dSmrg int t; 4436428d7b3dSmrg 4437428d7b3dSmrg if (rotation & RR_Reflect_X) 4438428d7b3dSmrg *x = size - *x - 1; 4439428d7b3dSmrg if (rotation & RR_Reflect_Y) 4440428d7b3dSmrg *y = size - *y - 1; 4441428d7b3dSmrg 4442428d7b3dSmrg switch (rotation & 0xf) { 4443428d7b3dSmrg case RR_Rotate_0: 4444428d7b3dSmrg break; 4445428d7b3dSmrg case RR_Rotate_90: 4446428d7b3dSmrg t = *x; 4447428d7b3dSmrg *x = *y; 4448428d7b3dSmrg *y = size - t - 1; 4449428d7b3dSmrg break; 4450428d7b3dSmrg case RR_Rotate_180: 4451428d7b3dSmrg *x = size - *x - 1; 4452428d7b3dSmrg *y = size - *y - 1; 4453428d7b3dSmrg break; 4454428d7b3dSmrg case RR_Rotate_270: 4455428d7b3dSmrg t = *x; 4456428d7b3dSmrg *x = size - *y - 1; 4457428d7b3dSmrg *y = t; 4458428d7b3dSmrg break; 4459428d7b3dSmrg } 4460428d7b3dSmrg} 4461428d7b3dSmrg 4462428d7b3dSmrgstatic struct sna_cursor *__sna_create_cursor(struct sna *sna, int size) 4463428d7b3dSmrg{ 4464428d7b3dSmrg struct sna_cursor *c; 4465428d7b3dSmrg 4466428d7b3dSmrg for (c = sna->cursor.cursors; c; c = c->next) { 4467428d7b3dSmrg if (c->ref == 0 && c->alloc >= size) { 4468428d7b3dSmrg __DBG(("%s: stealing handle=%d, serial=%d, rotation=%d, alloc=%d\n", 4469428d7b3dSmrg __FUNCTION__, c->handle, c->serial, c->rotation, c->alloc)); 4470428d7b3dSmrg return c; 4471428d7b3dSmrg } 4472428d7b3dSmrg } 4473428d7b3dSmrg 4474428d7b3dSmrg __DBG(("%s(size=%d, num_stash=%d)\n", __FUNCTION__, size, sna->cursor.num_stash)); 4475428d7b3dSmrg 4476428d7b3dSmrg c = sna->cursor.stash; 4477428d7b3dSmrg assert(c); 4478428d7b3dSmrg 4479428d7b3dSmrg c->alloc = ALIGN(size, 4096); 4480428d7b3dSmrg c->handle = gem_create(sna->kgem.fd, c->alloc); 4481428d7b3dSmrg if (c->handle == 0) 4482428d7b3dSmrg return NULL; 4483428d7b3dSmrg 4484428d7b3dSmrg /* Old hardware uses physical addresses, which the kernel 4485428d7b3dSmrg * implements in an incoherent fashion requiring a pwrite. 4486428d7b3dSmrg */ 4487428d7b3dSmrg if (sna->cursor.use_gtt) { 4488428d7b3dSmrg c->image = gem_mmap(sna->kgem.fd, c->handle, c->alloc); 4489428d7b3dSmrg if (c->image == NULL) { 4490428d7b3dSmrg gem_close(sna->kgem.fd, c->handle); 4491428d7b3dSmrg return NULL; 4492428d7b3dSmrg } 4493428d7b3dSmrg } else 4494428d7b3dSmrg c->image = NULL; 4495428d7b3dSmrg 4496428d7b3dSmrg __DBG(("%s: handle=%d, allocated %d\n", __FUNCTION__, c->handle, size)); 4497428d7b3dSmrg 4498428d7b3dSmrg c->ref = 0; 4499428d7b3dSmrg c->serial = 0; 4500428d7b3dSmrg c->rotation = 0; 4501428d7b3dSmrg c->last_width = c->last_height = 0; /* all clear */ 4502428d7b3dSmrg c->size = size; 4503428d7b3dSmrg 4504428d7b3dSmrg sna->cursor.num_stash--; 4505428d7b3dSmrg sna->cursor.stash = c->next; 4506428d7b3dSmrg 4507428d7b3dSmrg c->next = sna->cursor.cursors; 4508428d7b3dSmrg sna->cursor.cursors = c; 4509428d7b3dSmrg 4510428d7b3dSmrg return c; 4511428d7b3dSmrg} 4512428d7b3dSmrg 4513428d7b3dSmrgstatic uint32_t *get_cursor_argb(CursorPtr c) 4514428d7b3dSmrg{ 4515428d7b3dSmrg#ifdef ARGB_CURSOR 4516428d7b3dSmrg return (uint32_t *)c->bits->argb; 4517428d7b3dSmrg#else 4518428d7b3dSmrg return NULL; 4519428d7b3dSmrg#endif 4520428d7b3dSmrg} 4521428d7b3dSmrg 4522428d7b3dSmrgstatic struct sna_cursor *__sna_get_cursor(struct sna *sna, xf86CrtcPtr crtc) 4523428d7b3dSmrg{ 4524428d7b3dSmrg struct sna_cursor *cursor; 4525428d7b3dSmrg const uint8_t *source, *mask; 4526428d7b3dSmrg const uint32_t *argb; 4527428d7b3dSmrg uint32_t *image; 4528428d7b3dSmrg int width, height, pitch, size, x, y; 4529428d7b3dSmrg Rotation rotation; 4530428d7b3dSmrg 4531428d7b3dSmrg assert(sna->cursor.ref); 4532428d7b3dSmrg 4533428d7b3dSmrg cursor = to_sna_crtc(crtc)->cursor; 4534428d7b3dSmrg __DBG(("%s: current cursor handle=%d, serial=%d [expected %d]\n", 4535428d7b3dSmrg __FUNCTION__, 4536428d7b3dSmrg cursor ? cursor->handle : 0, 4537428d7b3dSmrg cursor ? cursor->serial : 0, 4538428d7b3dSmrg sna->cursor.serial)); 4539428d7b3dSmrg if (cursor && cursor->serial == sna->cursor.serial) { 4540428d7b3dSmrg assert(cursor->size == sna->cursor.size); 4541428d7b3dSmrg assert(cursor->rotation == crtc->transform_in_use ? crtc->rotation : RR_Rotate_0); 4542428d7b3dSmrg assert(cursor->ref); 4543428d7b3dSmrg return cursor; 4544428d7b3dSmrg } 4545428d7b3dSmrg 4546428d7b3dSmrg __DBG(("%s: cursor=%dx%d, pitch=%d, serial=%d, argb?=%d\n", __FUNCTION__, 4547428d7b3dSmrg sna->cursor.ref->bits->width, 4548428d7b3dSmrg sna->cursor.ref->bits->height, 4549428d7b3dSmrg get_cursor_argb(sna->cursor.ref) ? 4*sna->cursor.ref->bits->width : BitmapBytePad(sna->cursor.ref->bits->width), 4550428d7b3dSmrg sna->cursor.serial, 4551428d7b3dSmrg get_cursor_argb(sna->cursor.ref) != NULL)); 4552428d7b3dSmrg 4553428d7b3dSmrg rotation = crtc->transform_in_use ? crtc->rotation : RR_Rotate_0; 4554428d7b3dSmrg 4555428d7b3dSmrg if (sna->cursor.use_gtt) { /* Don't allow phys cursor sharing */ 4556428d7b3dSmrg for (cursor = sna->cursor.cursors; cursor; cursor = cursor->next) { 4557428d7b3dSmrg if (cursor->serial == sna->cursor.serial && cursor->rotation == rotation) { 4558428d7b3dSmrg __DBG(("%s: reusing handle=%d, serial=%d, rotation=%d, size=%d\n", 4559428d7b3dSmrg __FUNCTION__, cursor->handle, cursor->serial, cursor->rotation, cursor->size)); 4560428d7b3dSmrg assert(cursor->size == sna->cursor.size); 4561428d7b3dSmrg return cursor; 4562428d7b3dSmrg } 4563428d7b3dSmrg } 4564428d7b3dSmrg 4565428d7b3dSmrg cursor = to_sna_crtc(crtc)->cursor; 4566428d7b3dSmrg } 4567428d7b3dSmrg 4568428d7b3dSmrg size = sna->cursor.size; 4569428d7b3dSmrg if (cursor && cursor->alloc < 4*size*size) 4570428d7b3dSmrg cursor = NULL; 4571428d7b3dSmrg 4572428d7b3dSmrg if (cursor == NULL) { 4573428d7b3dSmrg cursor = __sna_create_cursor(sna, 4*size*size); 4574428d7b3dSmrg if (cursor == NULL) { 4575428d7b3dSmrg DBG(("%s: failed to allocate cursor\n", __FUNCTION__)); 4576428d7b3dSmrg return NULL; 4577428d7b3dSmrg } 4578428d7b3dSmrg } 4579428d7b3dSmrg 4580428d7b3dSmrg width = sna->cursor.ref->bits->width; 4581428d7b3dSmrg height = sna->cursor.ref->bits->height; 4582428d7b3dSmrg source = sna->cursor.ref->bits->source; 4583428d7b3dSmrg mask = sna->cursor.ref->bits->mask; 4584428d7b3dSmrg argb = get_cursor_argb(sna->cursor.ref); 4585428d7b3dSmrg pitch = BitmapBytePad(width); 4586428d7b3dSmrg 4587428d7b3dSmrg image = cursor->image; 4588428d7b3dSmrg if (image == NULL) { 4589428d7b3dSmrg image = sna->cursor.scratch; 4590428d7b3dSmrg cursor->last_width = cursor->last_height = size; 4591428d7b3dSmrg } 4592428d7b3dSmrg if (size > cursor->size || 4593428d7b3dSmrg width < cursor->last_width || 4594428d7b3dSmrg height < cursor->last_height || 4595428d7b3dSmrg rotation != cursor->rotation) 4596428d7b3dSmrg memset(image, 0, 4*size*size); 4597428d7b3dSmrg if (rotation == RR_Rotate_0) { 4598428d7b3dSmrg if (argb == NULL) { 4599428d7b3dSmrg for (y = 0; y < height; y++) { 4600428d7b3dSmrg uint32_t *p = image + y*size; 4601428d7b3dSmrg for (x = 0; x < width; x++) { 4602428d7b3dSmrg int byte = x / 8; 4603428d7b3dSmrg uint8_t bit = 1 << (x & 7); 4604428d7b3dSmrg uint32_t pixel; 4605428d7b3dSmrg 4606428d7b3dSmrg if (mask[byte] & bit) { 4607428d7b3dSmrg if (source[byte] & bit) 4608428d7b3dSmrg pixel = sna->cursor.fg; 4609428d7b3dSmrg else 4610428d7b3dSmrg pixel = sna->cursor.bg; 4611428d7b3dSmrg } else 4612428d7b3dSmrg pixel = 0; 4613428d7b3dSmrg 4614428d7b3dSmrg *p++ = pixel; 4615428d7b3dSmrg } 4616428d7b3dSmrg mask += pitch; 4617428d7b3dSmrg source += pitch; 4618428d7b3dSmrg } 4619428d7b3dSmrg } else 4620428d7b3dSmrg memcpy_blt(argb, image, 32, 4621428d7b3dSmrg width * 4, size * 4, 4622428d7b3dSmrg 0, 0, 4623428d7b3dSmrg 0, 0, 4624428d7b3dSmrg width, height); 4625428d7b3dSmrg } else { 4626428d7b3dSmrg for (y = 0; y < size; y++) 4627428d7b3dSmrg for (x = 0; x < size; x++) { 4628428d7b3dSmrg uint32_t pixel; 4629428d7b3dSmrg int xin, yin; 4630428d7b3dSmrg 4631428d7b3dSmrg rotate_coord(rotation, size, x, y, &xin, &yin); 4632428d7b3dSmrg if (xin < width && yin < height) 4633428d7b3dSmrg if (argb == NULL) { 4634428d7b3dSmrg int byte = xin / 8; 4635428d7b3dSmrg int bit = xin & 7; 4636428d7b3dSmrg if (mask[yin*pitch + byte] & (1 << bit)) { 4637428d7b3dSmrg if (source[yin*pitch + byte] & (1 << bit)) 4638428d7b3dSmrg pixel = sna->cursor.fg; 4639428d7b3dSmrg else 4640428d7b3dSmrg pixel = sna->cursor.bg; 4641428d7b3dSmrg } else 4642428d7b3dSmrg pixel = 0; 4643428d7b3dSmrg } else 4644428d7b3dSmrg pixel = argb[yin * width + xin]; 4645428d7b3dSmrg else 4646428d7b3dSmrg pixel = 0; 4647428d7b3dSmrg image[y * size + x] = pixel; 4648428d7b3dSmrg } 4649428d7b3dSmrg } 4650428d7b3dSmrg 4651428d7b3dSmrg if (image != cursor->image) { 4652428d7b3dSmrg struct drm_i915_gem_pwrite pwrite; 4653428d7b3dSmrg 4654428d7b3dSmrg VG_CLEAR(pwrite); 4655428d7b3dSmrg pwrite.handle = cursor->handle; 4656428d7b3dSmrg pwrite.offset = 0; 4657428d7b3dSmrg pwrite.size = 4*size*size; 4658428d7b3dSmrg pwrite.data_ptr = (uintptr_t)image; 4659428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_PWRITE, &pwrite)) 4660428d7b3dSmrg __DBG(("%s: cursor update (pwrite) failed: %d\n", __FUNCTION__, errno)); 4661428d7b3dSmrg } 4662428d7b3dSmrg 4663428d7b3dSmrg cursor->size = size; 4664428d7b3dSmrg cursor->rotation = rotation; 4665428d7b3dSmrg cursor->serial = sna->cursor.serial; 4666428d7b3dSmrg cursor->last_width = width; 4667428d7b3dSmrg cursor->last_height = height; 4668428d7b3dSmrg return cursor; 4669428d7b3dSmrg} 4670428d7b3dSmrg 4671428d7b3dSmrgstatic unsigned char * 4672428d7b3dSmrgsna_realize_cursor(xf86CursorInfoPtr info, CursorPtr cursor) 4673428d7b3dSmrg{ 4674428d7b3dSmrg return NULL; 4675428d7b3dSmrg} 4676428d7b3dSmrg 4677428d7b3dSmrg/* XXXMRG OsBlockSIGIO() is gone gone, old one remains before porting */ 4678428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,12,99,901,0) && 0 4679428d7b3dSmrgstatic inline int sigio_block(void) 4680428d7b3dSmrg{ 4681428d7b3dSmrg OsBlockSIGIO(); 4682428d7b3dSmrg return 0; 4683428d7b3dSmrg} 4684428d7b3dSmrgstatic inline void sigio_unblock(int was_blocked) 4685428d7b3dSmrg{ 4686428d7b3dSmrg OsReleaseSIGIO(); 4687428d7b3dSmrg (void)was_blocked; 4688428d7b3dSmrg} 4689428d7b3dSmrg#else 4690428d7b3dSmrg#include <xf86_OSproc.h> 4691428d7b3dSmrgstatic inline int sigio_block(void) 4692428d7b3dSmrg{ 4693428d7b3dSmrg return xf86BlockSIGIO(); 4694428d7b3dSmrg} 4695428d7b3dSmrgstatic inline void sigio_unblock(int was_blocked) 4696428d7b3dSmrg{ 4697428d7b3dSmrg xf86UnblockSIGIO(was_blocked); 4698428d7b3dSmrg} 4699428d7b3dSmrg#endif 4700428d7b3dSmrg 4701428d7b3dSmrgstatic void 4702428d7b3dSmrgsna_show_cursors(ScrnInfoPtr scrn) 4703428d7b3dSmrg{ 4704428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 4705428d7b3dSmrg struct sna *sna = to_sna(scrn); 4706428d7b3dSmrg int sigio, c; 4707428d7b3dSmrg 4708428d7b3dSmrg DBG(("%s: cursor?=%d\n", __FUNCTION__, sna->cursor.ref != NULL)); 4709428d7b3dSmrg if (sna->cursor.ref == NULL) 4710428d7b3dSmrg return; 4711428d7b3dSmrg 4712428d7b3dSmrg sigio = sigio_block(); 4713428d7b3dSmrg for (c = 0; c < sna->mode.num_real_crtc; c++) { 4714428d7b3dSmrg xf86CrtcPtr crtc = xf86_config->crtc[c]; 4715428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 4716428d7b3dSmrg struct drm_mode_cursor arg; 4717428d7b3dSmrg struct sna_cursor *cursor; 4718428d7b3dSmrg 4719428d7b3dSmrg assert(sna_crtc != NULL); 4720428d7b3dSmrg if (sna_crtc->bo == NULL) 4721428d7b3dSmrg continue; 4722428d7b3dSmrg 4723428d7b3dSmrg if (!crtc->cursor_in_range) { 4724428d7b3dSmrg DBG(("%s: skipping cursor outside CRTC (pipe=%d)\n", 4725428d7b3dSmrg __FUNCTION__, sna_crtc->pipe)); 4726428d7b3dSmrg continue; 4727428d7b3dSmrg } 4728428d7b3dSmrg 4729428d7b3dSmrg cursor = __sna_get_cursor(sna, crtc); 4730428d7b3dSmrg if (cursor == NULL || 4731428d7b3dSmrg (sna_crtc->cursor == cursor && sna_crtc->last_cursor_size == cursor->size)) { 4732428d7b3dSmrg DBG(("%s: skipping cursor already show on CRTC (pipe=%d)\n", 4733428d7b3dSmrg __FUNCTION__, sna_crtc->pipe)); 4734428d7b3dSmrg continue; 4735428d7b3dSmrg } 4736428d7b3dSmrg 4737428d7b3dSmrg DBG(("%s: CRTC pipe=%d, handle->%d\n", __FUNCTION__, 4738428d7b3dSmrg sna_crtc->pipe, cursor->handle)); 4739428d7b3dSmrg 4740428d7b3dSmrg VG_CLEAR(arg); 4741428d7b3dSmrg arg.flags = DRM_MODE_CURSOR_BO; 4742428d7b3dSmrg arg.crtc_id = sna_crtc->id; 4743428d7b3dSmrg arg.width = arg.height = cursor->size; 4744428d7b3dSmrg arg.handle = cursor->handle; 4745428d7b3dSmrg 4746428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) { 4747428d7b3dSmrg if (sna_crtc->cursor) { 4748428d7b3dSmrg assert(sna_crtc->cursor->ref > 0); 4749428d7b3dSmrg sna_crtc->cursor->ref--; 4750428d7b3dSmrg } 4751428d7b3dSmrg cursor->ref++; 4752428d7b3dSmrg sna_crtc->cursor = cursor; 4753428d7b3dSmrg sna_crtc->last_cursor_size = cursor->size; 4754428d7b3dSmrg } 4755428d7b3dSmrg } 4756428d7b3dSmrg sigio_unblock(sigio); 4757428d7b3dSmrg sna->cursor.active = true; 4758428d7b3dSmrg} 4759428d7b3dSmrg 4760428d7b3dSmrgstatic void 4761428d7b3dSmrgsna_set_cursor_colors(ScrnInfoPtr scrn, int _bg, int _fg) 4762428d7b3dSmrg{ 4763428d7b3dSmrg struct sna *sna = to_sna(scrn); 4764428d7b3dSmrg uint32_t fg = _fg, bg = _bg; 4765428d7b3dSmrg 4766428d7b3dSmrg __DBG(("%s(bg=%08x, fg=%08x)\n", __FUNCTION__, bg, fg)); 4767428d7b3dSmrg 4768428d7b3dSmrg /* Save ARGB versions of these colors */ 4769428d7b3dSmrg fg |= 0xff000000; 4770428d7b3dSmrg bg |= 0xff000000; 4771428d7b3dSmrg if (fg == sna->cursor.fg && bg == sna->cursor.bg) 4772428d7b3dSmrg return; 4773428d7b3dSmrg 4774428d7b3dSmrg sna->cursor.fg = fg; 4775428d7b3dSmrg sna->cursor.bg = bg; 4776428d7b3dSmrg 4777428d7b3dSmrg if (sna->cursor.ref == NULL) 4778428d7b3dSmrg return; 4779428d7b3dSmrg 4780428d7b3dSmrg if (get_cursor_argb(sna->cursor.ref)) 4781428d7b3dSmrg return; 4782428d7b3dSmrg 4783428d7b3dSmrg sna->cursor.serial++; 4784428d7b3dSmrg __DBG(("%s: serial->%d\n", __FUNCTION__, sna->cursor.serial)); 4785428d7b3dSmrg 4786428d7b3dSmrg sna_show_cursors(scrn); 4787428d7b3dSmrg} 4788428d7b3dSmrg 4789428d7b3dSmrgstatic void 4790428d7b3dSmrgsna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc) 4791428d7b3dSmrg{ 4792428d7b3dSmrg struct drm_mode_cursor arg; 4793428d7b3dSmrg 4794428d7b3dSmrg if (!crtc->cursor) 4795428d7b3dSmrg return; 4796428d7b3dSmrg 4797428d7b3dSmrg DBG(("%s: CRTC:%d, handle=%d\n", __FUNCTION__, crtc->id, crtc->cursor->handle)); 4798428d7b3dSmrg assert(crtc->cursor->ref); 4799428d7b3dSmrg 4800428d7b3dSmrg VG_CLEAR(arg); 4801428d7b3dSmrg arg.flags = DRM_MODE_CURSOR_BO; 4802428d7b3dSmrg arg.crtc_id = crtc->id; 4803428d7b3dSmrg arg.width = arg.height = 0; 4804428d7b3dSmrg arg.handle = 0; 4805428d7b3dSmrg 4806428d7b3dSmrg (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg); 4807428d7b3dSmrg assert(crtc->cursor->ref > 0); 4808428d7b3dSmrg crtc->cursor->ref--; 4809428d7b3dSmrg crtc->cursor = NULL; 4810428d7b3dSmrg crtc->last_cursor_size = 0; 4811428d7b3dSmrg} 4812428d7b3dSmrg 4813428d7b3dSmrgstatic void 4814428d7b3dSmrgsna_hide_cursors(ScrnInfoPtr scrn) 4815428d7b3dSmrg{ 4816428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 4817428d7b3dSmrg struct sna *sna = to_sna(scrn); 4818428d7b3dSmrg struct sna_cursor *cursor, **prev; 4819428d7b3dSmrg int sigio, c; 4820428d7b3dSmrg 4821428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 4822428d7b3dSmrg sna->cursor.active = false; 4823428d7b3dSmrg 4824428d7b3dSmrg sigio = sigio_block(); 4825428d7b3dSmrg for (c = 0; c < sna->mode.num_real_crtc; c++) { 4826428d7b3dSmrg assert(to_sna_crtc(xf86_config->crtc[c])); 4827428d7b3dSmrg sna_crtc_disable_cursor(sna, to_sna_crtc(xf86_config->crtc[c])); 4828428d7b3dSmrg } 4829428d7b3dSmrg 4830428d7b3dSmrg for (prev = &sna->cursor.cursors; (cursor = *prev) != NULL; ) { 4831428d7b3dSmrg assert(cursor->ref == 0); 4832428d7b3dSmrg 4833428d7b3dSmrg if (cursor->serial == sna->cursor.serial) { 4834428d7b3dSmrg prev = &cursor->next; 4835428d7b3dSmrg continue; 4836428d7b3dSmrg } 4837428d7b3dSmrg 4838428d7b3dSmrg *prev = cursor->next; 4839428d7b3dSmrg if (cursor->image) 4840428d7b3dSmrg munmap(cursor->image, cursor->alloc); 4841428d7b3dSmrg gem_close(sna->kgem.fd, cursor->handle); 4842428d7b3dSmrg 4843428d7b3dSmrg cursor->next = sna->cursor.stash; 4844428d7b3dSmrg sna->cursor.stash = cursor; 4845428d7b3dSmrg sna->cursor.num_stash++; 4846428d7b3dSmrg } 4847428d7b3dSmrg 4848428d7b3dSmrg sigio_unblock(sigio); 4849428d7b3dSmrg} 4850428d7b3dSmrg 4851428d7b3dSmrgstatic void 4852428d7b3dSmrgsna_set_cursor_position(ScrnInfoPtr scrn, int x, int y) 4853428d7b3dSmrg{ 4854428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 4855428d7b3dSmrg struct sna *sna = to_sna(scrn); 4856428d7b3dSmrg int sigio, c; 4857428d7b3dSmrg 4858428d7b3dSmrg __DBG(("%s(%d, %d), cursor? %d\n", __FUNCTION__, 4859428d7b3dSmrg x, y, sna->cursor.ref!=NULL)); 4860428d7b3dSmrg if (sna->cursor.ref == NULL) 4861428d7b3dSmrg return; 4862428d7b3dSmrg 4863428d7b3dSmrg sigio = sigio_block(); 4864428d7b3dSmrg sna->cursor.last_x = x; 4865428d7b3dSmrg sna->cursor.last_y = y; 4866428d7b3dSmrg 4867428d7b3dSmrg /* undo what xf86HWCurs did to the coordinates */ 4868428d7b3dSmrg x += scrn->frameX0; 4869428d7b3dSmrg y += scrn->frameY0; 4870428d7b3dSmrg for (c = 0; c < sna->mode.num_real_crtc; c++) { 4871428d7b3dSmrg xf86CrtcPtr crtc = xf86_config->crtc[c]; 4872428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 4873428d7b3dSmrg struct sna_cursor *cursor = NULL; 4874428d7b3dSmrg struct drm_mode_cursor arg; 4875428d7b3dSmrg 4876428d7b3dSmrg assert(sna_crtc != NULL); 4877428d7b3dSmrg 4878428d7b3dSmrg VG_CLEAR(arg); 4879428d7b3dSmrg arg.flags = 0; 4880428d7b3dSmrg arg.crtc_id = sna_crtc->id; 4881428d7b3dSmrg arg.handle = 0; 4882428d7b3dSmrg 4883428d7b3dSmrg if (sna_crtc->bo == NULL) 4884428d7b3dSmrg goto disable; 4885428d7b3dSmrg 4886428d7b3dSmrg if (crtc->transform_in_use) { 4887428d7b3dSmrg int xhot = sna->cursor.ref->bits->xhot; 4888428d7b3dSmrg int yhot = sna->cursor.ref->bits->yhot; 4889428d7b3dSmrg struct pict_f_vector v; 4890428d7b3dSmrg 4891428d7b3dSmrg v.v[0] = (x + xhot) + 0.5; 4892428d7b3dSmrg v.v[1] = (y + yhot) + 0.5; 4893428d7b3dSmrg v.v[2] = 1; 4894428d7b3dSmrg pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &v); 4895428d7b3dSmrg 4896428d7b3dSmrg rotate_coord_back(crtc->rotation, sna->cursor.size, &xhot, &yhot); 4897428d7b3dSmrg 4898428d7b3dSmrg /* cursor will have 0.5 added to it already so floor is sufficent */ 4899428d7b3dSmrg arg.x = floor(v.v[0]) - xhot; 4900428d7b3dSmrg arg.y = floor(v.v[1]) - yhot; 4901428d7b3dSmrg } else { 4902428d7b3dSmrg arg.x = x - crtc->x; 4903428d7b3dSmrg arg.y = y - crtc->y; 4904428d7b3dSmrg } 4905428d7b3dSmrg 4906428d7b3dSmrg if (arg.x < crtc->mode.HDisplay && arg.x > -sna->cursor.size && 4907428d7b3dSmrg arg.y < crtc->mode.VDisplay && arg.y > -sna->cursor.size) { 4908428d7b3dSmrg cursor = __sna_get_cursor(sna, crtc); 4909428d7b3dSmrg if (cursor == NULL) 4910428d7b3dSmrg cursor = sna_crtc->cursor; 4911428d7b3dSmrg if (cursor == NULL) { 4912428d7b3dSmrg __DBG(("%s: failed to grab cursor, disabling\n", 4913428d7b3dSmrg __FUNCTION__)); 4914428d7b3dSmrg goto disable; 4915428d7b3dSmrg } 4916428d7b3dSmrg 4917428d7b3dSmrg if (sna_crtc->cursor != cursor || sna_crtc->last_cursor_size != cursor->size) { 4918428d7b3dSmrg arg.flags |= DRM_MODE_CURSOR_BO; 4919428d7b3dSmrg arg.handle = cursor->handle; 4920428d7b3dSmrg } 4921428d7b3dSmrg 4922428d7b3dSmrg arg.width = arg.height = cursor->size; 4923428d7b3dSmrg arg.flags |= DRM_MODE_CURSOR_MOVE; 4924428d7b3dSmrg crtc->cursor_in_range = true; 4925428d7b3dSmrg } else { 4926428d7b3dSmrg crtc->cursor_in_range = false; 4927428d7b3dSmrgdisable: 4928428d7b3dSmrg if (sna_crtc->cursor) { 4929428d7b3dSmrg arg.flags = DRM_MODE_CURSOR_BO; 4930428d7b3dSmrg arg.width = arg.height = 0; 4931428d7b3dSmrg } 4932428d7b3dSmrg cursor = NULL; 4933428d7b3dSmrg } 4934428d7b3dSmrg 4935428d7b3dSmrg __DBG(("%s: CRTC:%d (%d, %d), handle=%d, flags=%x (old cursor handle=%d), move? %d, update handle? %d\n", 4936428d7b3dSmrg __FUNCTION__, sna_crtc->id, arg.x, arg.y, arg.handle, arg.flags, sna_crtc->cursor ? sna_crtc->cursor->handle : 0, 4937428d7b3dSmrg arg.flags & DRM_MODE_CURSOR_MOVE, arg.flags & DRM_MODE_CURSOR_BO)); 4938428d7b3dSmrg 4939428d7b3dSmrg if (arg.flags && 4940428d7b3dSmrg drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_CURSOR, &arg) == 0) { 4941428d7b3dSmrg if (arg.flags & DRM_MODE_CURSOR_BO) { 4942428d7b3dSmrg if (sna_crtc->cursor) { 4943428d7b3dSmrg assert(sna_crtc->cursor->ref > 0); 4944428d7b3dSmrg sna_crtc->cursor->ref--; 4945428d7b3dSmrg } 4946428d7b3dSmrg sna_crtc->cursor = cursor; 4947428d7b3dSmrg if (cursor) { 4948428d7b3dSmrg sna_crtc->last_cursor_size = cursor->size; 4949428d7b3dSmrg cursor->ref++; 4950428d7b3dSmrg } else 4951428d7b3dSmrg sna_crtc->last_cursor_size = 0; 4952428d7b3dSmrg } 4953428d7b3dSmrg } 4954428d7b3dSmrg } 4955428d7b3dSmrg sigio_unblock(sigio); 4956428d7b3dSmrg} 4957428d7b3dSmrg 4958428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2) 4959428d7b3dSmrgstatic Bool 4960428d7b3dSmrgsna_load_cursor_argb2(ScrnInfoPtr scrn, CursorPtr cursor) 4961428d7b3dSmrg{ 4962428d7b3dSmrg return TRUE; 4963428d7b3dSmrg} 4964428d7b3dSmrg 4965428d7b3dSmrgstatic Bool 4966428d7b3dSmrgsna_load_cursor_image2(ScrnInfoPtr scrn, unsigned char *src) 4967428d7b3dSmrg{ 4968428d7b3dSmrg return TRUE; 4969428d7b3dSmrg} 4970428d7b3dSmrg#endif 4971428d7b3dSmrg 4972428d7b3dSmrgstatic void 4973428d7b3dSmrgsna_load_cursor_argb(ScrnInfoPtr scrn, CursorPtr cursor) 4974428d7b3dSmrg{ 4975428d7b3dSmrg} 4976428d7b3dSmrg 4977428d7b3dSmrgstatic void 4978428d7b3dSmrgsna_load_cursor_image(ScrnInfoPtr scrn, unsigned char *src) 4979428d7b3dSmrg{ 4980428d7b3dSmrg} 4981428d7b3dSmrg 4982428d7b3dSmrgstatic int __cursor_size(CursorPtr cursor) 4983428d7b3dSmrg{ 4984428d7b3dSmrg int i, size; 4985428d7b3dSmrg 4986428d7b3dSmrg i = MAX(cursor->bits->width, cursor->bits->height); 4987428d7b3dSmrg for (size = 64; size < i; size <<= 1) 4988428d7b3dSmrg ; 4989428d7b3dSmrg 4990428d7b3dSmrg return size; 4991428d7b3dSmrg} 4992428d7b3dSmrg 4993428d7b3dSmrgstatic bool 4994428d7b3dSmrgsna_cursor_preallocate(struct sna *sna) 4995428d7b3dSmrg{ 4996428d7b3dSmrg while (sna->cursor.num_stash < 0) { 4997428d7b3dSmrg struct sna_cursor *cursor = malloc(sizeof(*cursor)); 4998428d7b3dSmrg if (!cursor) 4999428d7b3dSmrg return false; 5000428d7b3dSmrg 5001428d7b3dSmrg cursor->next = sna->cursor.stash; 5002428d7b3dSmrg sna->cursor.stash = cursor; 5003428d7b3dSmrg 5004428d7b3dSmrg sna->cursor.num_stash++; 5005428d7b3dSmrg } 5006428d7b3dSmrg 5007428d7b3dSmrg return true; 5008428d7b3dSmrg} 5009428d7b3dSmrg 5010428d7b3dSmrgstatic Bool 5011428d7b3dSmrgsna_use_hw_cursor(ScreenPtr screen, CursorPtr cursor) 5012428d7b3dSmrg{ 5013428d7b3dSmrg struct sna *sna = to_sna_from_screen(screen); 5014428d7b3dSmrg 5015428d7b3dSmrg DBG(("%s (%dx%d)?\n", __FUNCTION__, 5016428d7b3dSmrg cursor->bits->width, cursor->bits->height)); 5017428d7b3dSmrg 5018428d7b3dSmrg /* cursors are invariant */ 5019428d7b3dSmrg if (cursor == sna->cursor.ref) 5020428d7b3dSmrg return TRUE; 5021428d7b3dSmrg 5022428d7b3dSmrg if (sna->cursor.ref) { 5023428d7b3dSmrg FreeCursor(sna->cursor.ref, None); 5024428d7b3dSmrg sna->cursor.ref = NULL; 5025428d7b3dSmrg } 5026428d7b3dSmrg 5027428d7b3dSmrg sna->cursor.size = __cursor_size(cursor); 5028428d7b3dSmrg if (sna->cursor.size > sna->cursor.max_size) 5029428d7b3dSmrg return FALSE; 5030428d7b3dSmrg 5031428d7b3dSmrg if (!sna_cursor_preallocate(sna)) 5032428d7b3dSmrg return FALSE; 5033428d7b3dSmrg 5034428d7b3dSmrg sna->cursor.ref = cursor; 5035428d7b3dSmrg cursor->refcnt++; 5036428d7b3dSmrg sna->cursor.serial++; 5037428d7b3dSmrg 5038428d7b3dSmrg DBG(("%s(%dx%d): ARGB?=%d, serial->%d, size->%d\n", __FUNCTION__, 5039428d7b3dSmrg cursor->bits->width, 5040428d7b3dSmrg cursor->bits->height, 5041428d7b3dSmrg get_cursor_argb(cursor) != NULL, 5042428d7b3dSmrg sna->cursor.serial, 5043428d7b3dSmrg sna->cursor.size)); 5044428d7b3dSmrg return TRUE; 5045428d7b3dSmrg} 5046428d7b3dSmrg 5047428d7b3dSmrgstatic void 5048428d7b3dSmrgsna_cursor_pre_init(struct sna *sna) 5049428d7b3dSmrg{ 5050428d7b3dSmrg struct local_get_cap { 5051428d7b3dSmrg uint64_t name; 5052428d7b3dSmrg uint64_t value; 5053428d7b3dSmrg } cap; 5054428d7b3dSmrg int v; 5055428d7b3dSmrg 5056428d7b3dSmrg if (sna->mode.num_real_crtc == 0) 5057428d7b3dSmrg return; 5058428d7b3dSmrg 5059428d7b3dSmrg#define LOCAL_IOCTL_GET_CAP DRM_IOWR(0x0c, struct local_get_cap) 5060428d7b3dSmrg#define DRM_CAP_CURSOR_WIDTH 0x8 5061428d7b3dSmrg#define DRM_CAP_CURSOR_HEIGHT 0x9 5062428d7b3dSmrg 5063428d7b3dSmrg#define I915_PARAM_HAS_COHERENT_PHYS_GTT 29 5064428d7b3dSmrg 5065428d7b3dSmrg sna->cursor.max_size = 64; 5066428d7b3dSmrg 5067428d7b3dSmrg cap.value = 0; 5068428d7b3dSmrg cap.name = DRM_CAP_CURSOR_WIDTH; 5069428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_GET_CAP, &cap) == 0) 5070428d7b3dSmrg sna->cursor.max_size = cap.value; 5071428d7b3dSmrg 5072428d7b3dSmrg cap.name = DRM_CAP_CURSOR_HEIGHT; 5073428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_GET_CAP, &cap) == 0 && 5074428d7b3dSmrg cap.value < sna->cursor.max_size) 5075428d7b3dSmrg sna->cursor.max_size = cap.value; 5076428d7b3dSmrg 5077428d7b3dSmrg v = -1; /* No param uses the sign bit, reserve it for errors */ 5078428d7b3dSmrg if (sna->kgem.gen >= 033) { 5079428d7b3dSmrg v = 1; 5080428d7b3dSmrg } else { 5081428d7b3dSmrg drm_i915_getparam_t gp = { 5082428d7b3dSmrg I915_PARAM_HAS_COHERENT_PHYS_GTT, 5083428d7b3dSmrg &v, 5084428d7b3dSmrg }; 5085428d7b3dSmrg (void)drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GETPARAM, &gp); 5086428d7b3dSmrg } 5087428d7b3dSmrg sna->cursor.use_gtt = v > 0; 5088428d7b3dSmrg DBG(("%s: cursor updates use_gtt?=%d\n", 5089428d7b3dSmrg __FUNCTION__, sna->cursor.use_gtt)); 5090428d7b3dSmrg 5091428d7b3dSmrg if (!sna->cursor.use_gtt) { 5092428d7b3dSmrg sna->cursor.scratch = malloc(sna->cursor.max_size * sna->cursor.max_size * 4); 5093428d7b3dSmrg if (!sna->cursor.scratch) 5094428d7b3dSmrg sna->cursor.max_size = 0; 5095428d7b3dSmrg } 5096428d7b3dSmrg 5097428d7b3dSmrg sna->cursor.num_stash = -sna->mode.num_real_crtc; 5098428d7b3dSmrg 5099428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_PROBED, 5100428d7b3dSmrg "Using a maximum size of %dx%d for hardware cursors\n", 5101428d7b3dSmrg sna->cursor.max_size, sna->cursor.max_size); 5102428d7b3dSmrg} 5103428d7b3dSmrg 5104428d7b3dSmrgstatic void 5105428d7b3dSmrgsna_cursor_close(struct sna *sna) 5106428d7b3dSmrg{ 5107428d7b3dSmrg sna->cursor.serial = 0; 5108428d7b3dSmrg sna_hide_cursors(sna->scrn); 5109428d7b3dSmrg 5110428d7b3dSmrg while (sna->cursor.stash) { 5111428d7b3dSmrg struct sna_cursor *cursor = sna->cursor.stash; 5112428d7b3dSmrg sna->cursor.stash = cursor->next; 5113428d7b3dSmrg free(cursor); 5114428d7b3dSmrg } 5115428d7b3dSmrg 5116428d7b3dSmrg sna->cursor.num_stash = -sna->mode.num_real_crtc; 5117428d7b3dSmrg} 5118428d7b3dSmrg 5119428d7b3dSmrgbool 5120428d7b3dSmrgsna_cursors_init(ScreenPtr screen, struct sna *sna) 5121428d7b3dSmrg{ 5122428d7b3dSmrg xf86CursorInfoPtr cursor_info; 5123428d7b3dSmrg 5124428d7b3dSmrg if (sna->cursor.max_size == 0) 5125428d7b3dSmrg return false; 5126428d7b3dSmrg 5127428d7b3dSmrg cursor_info = xf86CreateCursorInfoRec(); 5128428d7b3dSmrg if (cursor_info == NULL) 5129428d7b3dSmrg return false; 5130428d7b3dSmrg 5131428d7b3dSmrg cursor_info->MaxWidth = sna->cursor.max_size; 5132428d7b3dSmrg cursor_info->MaxHeight = sna->cursor.max_size; 5133428d7b3dSmrg cursor_info->Flags = (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 5134428d7b3dSmrg HARDWARE_CURSOR_UPDATE_UNHIDDEN | 5135428d7b3dSmrg HARDWARE_CURSOR_ARGB); 5136428d7b3dSmrg 5137428d7b3dSmrg cursor_info->RealizeCursor = sna_realize_cursor; 5138428d7b3dSmrg cursor_info->SetCursorColors = sna_set_cursor_colors; 5139428d7b3dSmrg cursor_info->SetCursorPosition = sna_set_cursor_position; 5140428d7b3dSmrg cursor_info->LoadCursorImage = sna_load_cursor_image; 5141428d7b3dSmrg cursor_info->HideCursor = sna_hide_cursors; 5142428d7b3dSmrg cursor_info->ShowCursor = sna_show_cursors; 5143428d7b3dSmrg cursor_info->UseHWCursor = sna_use_hw_cursor; 5144428d7b3dSmrg#ifdef ARGB_CURSOR 5145428d7b3dSmrg cursor_info->UseHWCursorARGB = sna_use_hw_cursor; 5146428d7b3dSmrg cursor_info->LoadCursorARGB = sna_load_cursor_argb; 5147428d7b3dSmrg#endif 5148428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,3) 5149428d7b3dSmrg cursor_info->LoadCursorImageCheck = sna_load_cursor_image2; 5150428d7b3dSmrg#ifdef ARGB_CURSOR 5151428d7b3dSmrg cursor_info->LoadCursorARGBCheck = sna_load_cursor_argb2; 5152428d7b3dSmrg#endif 5153428d7b3dSmrg#endif 5154428d7b3dSmrg 5155428d7b3dSmrg if (!xf86InitCursor(screen, cursor_info)) { 5156428d7b3dSmrg xf86DestroyCursorInfoRec(cursor_info); 5157428d7b3dSmrg return false; 5158428d7b3dSmrg } 5159428d7b3dSmrg 5160428d7b3dSmrg sna->cursor.info = cursor_info; 5161428d7b3dSmrg return true; 5162428d7b3dSmrg} 5163428d7b3dSmrg 5164428d7b3dSmrgstatic void 5165428d7b3dSmrgsna_cursors_reload(struct sna *sna) 5166428d7b3dSmrg{ 5167428d7b3dSmrg DBG(("%s: active?=%d\n", __FUNCTION__, sna->cursor.active)); 5168428d7b3dSmrg if (sna->cursor.active) 5169428d7b3dSmrg sna_set_cursor_position(sna->scrn, 5170428d7b3dSmrg sna->cursor.last_x, 5171428d7b3dSmrg sna->cursor.last_y); 5172428d7b3dSmrg} 5173428d7b3dSmrg 5174428d7b3dSmrgstatic void 5175428d7b3dSmrgsna_cursors_fini(struct sna *sna) 5176428d7b3dSmrg{ 5177428d7b3dSmrg if (sna->cursor.info) { 5178428d7b3dSmrg xf86DestroyCursorInfoRec(sna->cursor.info); 5179428d7b3dSmrg sna->cursor.info = NULL; 5180428d7b3dSmrg } 5181428d7b3dSmrg 5182428d7b3dSmrg if (sna->cursor.ref) { 5183428d7b3dSmrg FreeCursor(sna->cursor.ref, None); 5184428d7b3dSmrg sna->cursor.ref = NULL; 5185428d7b3dSmrg } 5186428d7b3dSmrg} 5187428d7b3dSmrg 5188428d7b3dSmrgstatic bool 5189428d7b3dSmrgsna_crtc_flip(struct sna *sna, struct sna_crtc *crtc, struct kgem_bo *bo, int x, int y) 5190428d7b3dSmrg{ 5191428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 5192428d7b3dSmrg struct drm_mode_crtc arg; 5193428d7b3dSmrg uint32_t output_ids[32]; 5194428d7b3dSmrg int output_count = 0; 5195428d7b3dSmrg int i; 5196428d7b3dSmrg 5197428d7b3dSmrg DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle)); 5198428d7b3dSmrg 5199428d7b3dSmrg assert(sna->mode.num_real_output < ARRAY_SIZE(output_ids)); 5200428d7b3dSmrg assert(crtc->bo); 5201428d7b3dSmrg assert(crtc->kmode.clock); 5202428d7b3dSmrg 5203428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 5204428d7b3dSmrg xf86OutputPtr output = config->output[i]; 5205428d7b3dSmrg 5206428d7b3dSmrg if (output->crtc != crtc->base) 5207428d7b3dSmrg continue; 5208428d7b3dSmrg 5209428d7b3dSmrg DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n", 5210428d7b3dSmrg __FUNCTION__, output->name, i, to_connector_id(output), 5211428d7b3dSmrg crtc->id, crtc->pipe, 5212428d7b3dSmrg (uint32_t)output->possible_crtcs, 5213428d7b3dSmrg (uint32_t)output->possible_clones)); 5214428d7b3dSmrg 5215428d7b3dSmrg assert(output->possible_crtcs & (1 << crtc->pipe) || 5216428d7b3dSmrg is_zaphod(sna->scrn)); 5217428d7b3dSmrg 5218428d7b3dSmrg output_ids[output_count] = to_connector_id(output); 5219428d7b3dSmrg if (++output_count == ARRAY_SIZE(output_ids)) 5220428d7b3dSmrg return false; 5221428d7b3dSmrg } 5222428d7b3dSmrg assert(output_count); 5223428d7b3dSmrg 5224428d7b3dSmrg VG_CLEAR(arg); 5225428d7b3dSmrg arg.crtc_id = crtc->id; 5226428d7b3dSmrg arg.fb_id = fb_id(bo); 5227428d7b3dSmrg assert(arg.fb_id); 5228428d7b3dSmrg arg.x = x; 5229428d7b3dSmrg arg.y = y; 5230428d7b3dSmrg arg.set_connectors_ptr = (uintptr_t)output_ids; 5231428d7b3dSmrg arg.count_connectors = output_count; 5232428d7b3dSmrg arg.mode = crtc->kmode; 5233428d7b3dSmrg arg.mode_valid = 1; 5234428d7b3dSmrg 5235428d7b3dSmrg DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d across %d outputs [%d...]\n", 5236428d7b3dSmrg __FUNCTION__, crtc->id, crtc->pipe, 5237428d7b3dSmrg arg.mode.hdisplay, 5238428d7b3dSmrg arg.mode.vdisplay, 5239428d7b3dSmrg arg.x, arg.y, 5240428d7b3dSmrg arg.mode.clock, 5241428d7b3dSmrg arg.fb_id, 5242428d7b3dSmrg output_count, output_count ? output_ids[0] : 0)); 5243428d7b3dSmrg 5244428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg)) 5245428d7b3dSmrg return false; 5246428d7b3dSmrg 5247428d7b3dSmrg crtc->offset = y << 16 | x; 5248428d7b3dSmrg return true; 5249428d7b3dSmrg} 5250428d7b3dSmrg 5251428d7b3dSmrgint 5252428d7b3dSmrgsna_page_flip(struct sna *sna, 5253428d7b3dSmrg struct kgem_bo *bo, 5254428d7b3dSmrg sna_flip_handler_t handler, 5255428d7b3dSmrg void *data) 5256428d7b3dSmrg{ 5257428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 5258428d7b3dSmrg const int width = sna->scrn->virtualX; 5259428d7b3dSmrg const int height = sna->scrn->virtualY; 5260428d7b3dSmrg int count = 0; 5261428d7b3dSmrg int i; 5262428d7b3dSmrg 5263428d7b3dSmrg DBG(("%s: handle %d attached\n", __FUNCTION__, bo->handle)); 5264428d7b3dSmrg assert(bo->refcnt); 5265428d7b3dSmrg 5266428d7b3dSmrg assert((sna->flags & SNA_IS_HOSTED) == 0); 5267428d7b3dSmrg assert((sna->flags & SNA_TEAR_FREE) == 0); 5268428d7b3dSmrg assert(sna->mode.flip_active == 0); 5269428d7b3dSmrg assert(sna->mode.front_active); 5270428d7b3dSmrg assert(sna->scrn->vtSema); 5271428d7b3dSmrg 5272428d7b3dSmrg if ((sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) == 0) 5273428d7b3dSmrg return 0; 5274428d7b3dSmrg 5275428d7b3dSmrg kgem_bo_submit(&sna->kgem, bo); 5276428d7b3dSmrg 5277428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 5278428d7b3dSmrg struct sna_crtc *crtc = config->crtc[i]->driver_private; 5279428d7b3dSmrg struct drm_mode_crtc_page_flip arg; 5280428d7b3dSmrg uint32_t crtc_offset; 5281428d7b3dSmrg 5282428d7b3dSmrg DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n", 5283428d7b3dSmrg __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL)); 5284428d7b3dSmrg if (crtc->bo == NULL) 5285428d7b3dSmrg continue; 5286428d7b3dSmrg assert(!crtc->transform); 5287428d7b3dSmrg assert(!crtc->slave_pixmap); 5288428d7b3dSmrg assert(crtc->bo->active_scanout); 5289428d7b3dSmrg assert(crtc->bo->refcnt >= crtc->bo->active_scanout); 5290428d7b3dSmrg assert(crtc->flip_bo == NULL); 5291428d7b3dSmrg 5292428d7b3dSmrg arg.crtc_id = crtc->id; 5293428d7b3dSmrg arg.fb_id = get_fb(sna, bo, width, height); 5294428d7b3dSmrg if (arg.fb_id == 0) { 5295428d7b3dSmrg assert(count == 0); 5296428d7b3dSmrg return 0; 5297428d7b3dSmrg } 5298428d7b3dSmrg 5299428d7b3dSmrg crtc_offset = crtc->base->y << 16 | crtc->base->x; 5300428d7b3dSmrg 5301428d7b3dSmrg if (bo->pitch != crtc->bo->pitch || crtc_offset != crtc->offset) { 5302428d7b3dSmrg DBG(("%s: changing pitch (%d == %d) or offset (%x == %x)\n", 5303428d7b3dSmrg __FUNCTION__, 5304428d7b3dSmrg bo->pitch, crtc->bo->pitch, 5305428d7b3dSmrg crtc_offset, crtc->offset)); 5306428d7b3dSmrgfixup_flip: 5307428d7b3dSmrg if (crtc->bo != bo && sna_crtc_flip(sna, crtc, bo, crtc->base->x, crtc->base->y)) { 5308428d7b3dSmrg assert(crtc->bo->active_scanout); 5309428d7b3dSmrg assert(crtc->bo->refcnt >= crtc->bo->active_scanout); 5310428d7b3dSmrg crtc->bo->active_scanout--; 5311428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->bo); 5312428d7b3dSmrg 5313428d7b3dSmrg if (crtc->shadow_bo) { 5314428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->shadow_bo); 5315428d7b3dSmrg crtc->shadow_bo = NULL; 5316428d7b3dSmrg } 5317428d7b3dSmrg 5318428d7b3dSmrg crtc->bo = kgem_bo_reference(bo); 5319428d7b3dSmrg crtc->bo->active_scanout++; 5320428d7b3dSmrg 5321428d7b3dSmrg if (data == NULL) 5322428d7b3dSmrg goto next_crtc; 5323428d7b3dSmrg 5324428d7b3dSmrg /* queue a flip in order to send the event */ 5325428d7b3dSmrg } else { 5326428d7b3dSmrg if (count && !xf86SetDesiredModes(sna->scrn)) { 5327428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 5328428d7b3dSmrg "failed to restore display configuration\n"); 5329428d7b3dSmrg for (; i < sna->mode.num_real_crtc; i++) 5330428d7b3dSmrg sna_crtc_disable(config->crtc[i]); 5331428d7b3dSmrg } 5332428d7b3dSmrg return 0; 5333428d7b3dSmrg } 5334428d7b3dSmrg } 5335428d7b3dSmrg 5336428d7b3dSmrg /* Only the reference crtc will finally deliver its page flip 5337428d7b3dSmrg * completion event. All other crtc's events will be discarded. 5338428d7b3dSmrg */ 5339428d7b3dSmrg if (data) { 5340428d7b3dSmrg arg.user_data = (uintptr_t)crtc; 5341428d7b3dSmrg arg.flags = DRM_MODE_PAGE_FLIP_EVENT; 5342428d7b3dSmrg } else { 5343428d7b3dSmrg arg.user_data = 0; 5344428d7b3dSmrg arg.flags = DRM_MODE_PAGE_FLIP_ASYNC; 5345428d7b3dSmrg } 5346428d7b3dSmrg arg.reserved = 0; 5347428d7b3dSmrg 5348428d7b3dSmrgretry_flip: 5349428d7b3dSmrg DBG(("%s: crtc %d id=%d, pipe=%d --> fb %d\n", 5350428d7b3dSmrg __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id)); 5351428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) { 5352428d7b3dSmrg ERR(("%s: pageflip failed with err=%d\n", __FUNCTION__, errno)); 5353428d7b3dSmrg 5354428d7b3dSmrg if (errno == EBUSY) { 5355428d7b3dSmrg struct drm_mode_crtc mode; 5356428d7b3dSmrg 5357428d7b3dSmrg memset(&mode, 0, sizeof(mode)); 5358428d7b3dSmrg mode.crtc_id = crtc->id; 5359428d7b3dSmrg drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode); 5360428d7b3dSmrg 5361428d7b3dSmrg DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n", 5362428d7b3dSmrg __FUNCTION__, 5363428d7b3dSmrg mode.crtc_id, mode.mode_valid, 5364428d7b3dSmrg mode.fb_id, fb_id(crtc->bo))); 5365428d7b3dSmrg 5366428d7b3dSmrg if (mode.fb_id != fb_id(crtc->bo)) 5367428d7b3dSmrg goto fixup_flip; 5368428d7b3dSmrg 5369428d7b3dSmrg if (count == 0) 5370428d7b3dSmrg return 0; 5371428d7b3dSmrg 5372428d7b3dSmrg DBG(("%s: throttling on busy flip / waiting for kernel to catch up\n", __FUNCTION__)); 5373428d7b3dSmrg drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_THROTTLE, 0); 5374428d7b3dSmrg sna->kgem.need_throttle = false; 5375428d7b3dSmrg 5376428d7b3dSmrg goto retry_flip; 5377428d7b3dSmrg } 5378428d7b3dSmrg 5379428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 5380428d7b3dSmrg "page flipping failed, on CRTC:%d (pipe=%d), disabling %s page flips\n", 5381428d7b3dSmrg crtc->id, crtc->pipe, data ? "synchronous": "asynchronous"); 5382428d7b3dSmrg sna->flags &= ~(data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP); 5383428d7b3dSmrg goto fixup_flip; 5384428d7b3dSmrg } 5385428d7b3dSmrg 5386428d7b3dSmrg if (data) { 5387428d7b3dSmrg assert(crtc->flip_bo == NULL); 5388428d7b3dSmrg crtc->flip_handler = handler; 5389428d7b3dSmrg crtc->flip_data = data; 5390428d7b3dSmrg crtc->flip_bo = kgem_bo_reference(bo); 5391428d7b3dSmrg crtc->flip_bo->active_scanout++; 5392428d7b3dSmrg crtc->flip_serial = crtc->mode_serial; 5393428d7b3dSmrg crtc->flip_pending = true; 5394428d7b3dSmrg sna->mode.flip_active++; 5395428d7b3dSmrg } 5396428d7b3dSmrg 5397428d7b3dSmrgnext_crtc: 5398428d7b3dSmrg count++; 5399428d7b3dSmrg } 5400428d7b3dSmrg 5401428d7b3dSmrg DBG(("%s: page flipped %d crtcs\n", __FUNCTION__, count)); 5402428d7b3dSmrg return count; 5403428d7b3dSmrg} 5404428d7b3dSmrg 5405428d7b3dSmrgstatic const xf86CrtcConfigFuncsRec sna_mode_funcs = { 5406428d7b3dSmrg sna_mode_resize 5407428d7b3dSmrg}; 5408428d7b3dSmrg 5409428d7b3dSmrgstatic void set_size_range(struct sna *sna) 5410428d7b3dSmrg{ 5411428d7b3dSmrg /* We lie slightly as we expect no single monitor to exceed the 5412428d7b3dSmrg * crtc limits, so if the mode exceeds the scanout restrictions, 5413428d7b3dSmrg * we will quietly convert that to per-crtc pixmaps. 5414428d7b3dSmrg */ 5415428d7b3dSmrg xf86CrtcSetSizeRange(sna->scrn, 8, 8, INT16_MAX, INT16_MAX); 5416428d7b3dSmrg} 5417428d7b3dSmrg 5418428d7b3dSmrg#if HAS_GAMMA 5419428d7b3dSmrgstatic void set_gamma(uint16_t *curve, int size, double value) 5420428d7b3dSmrg{ 5421428d7b3dSmrg int i; 5422428d7b3dSmrg 5423428d7b3dSmrg value = 1/value; 5424428d7b3dSmrg for (i = 0; i < size; i++) 5425428d7b3dSmrg curve[i] = 256*(size-1)*pow(i/(double)(size-1), value); 5426428d7b3dSmrg} 5427428d7b3dSmrg 5428428d7b3dSmrgstatic void output_set_gamma(xf86OutputPtr output, xf86CrtcPtr crtc) 5429428d7b3dSmrg{ 5430428d7b3dSmrg XF86ConfMonitorPtr mon = output->conf_monitor; 5431428d7b3dSmrg 5432428d7b3dSmrg if (!mon) 5433428d7b3dSmrg return; 5434428d7b3dSmrg 5435428d7b3dSmrg DBG(("%s: red=%f\n", __FUNCTION__, mon->mon_gamma_red)); 5436428d7b3dSmrg if (mon->mon_gamma_red >= GAMMA_MIN && 5437428d7b3dSmrg mon->mon_gamma_red <= GAMMA_MAX && 5438428d7b3dSmrg mon->mon_gamma_red != 1.0) 5439428d7b3dSmrg set_gamma(crtc->gamma_red, crtc->gamma_size, 5440428d7b3dSmrg mon->mon_gamma_red); 5441428d7b3dSmrg 5442428d7b3dSmrg DBG(("%s: green=%f\n", __FUNCTION__, mon->mon_gamma_green)); 5443428d7b3dSmrg if (mon->mon_gamma_green >= GAMMA_MIN && 5444428d7b3dSmrg mon->mon_gamma_green <= GAMMA_MAX && 5445428d7b3dSmrg mon->mon_gamma_green != 1.0) 5446428d7b3dSmrg set_gamma(crtc->gamma_green, crtc->gamma_size, 5447428d7b3dSmrg mon->mon_gamma_green); 5448428d7b3dSmrg 5449428d7b3dSmrg DBG(("%s: blue=%f\n", __FUNCTION__, mon->mon_gamma_blue)); 5450428d7b3dSmrg if (mon->mon_gamma_blue >= GAMMA_MIN && 5451428d7b3dSmrg mon->mon_gamma_blue <= GAMMA_MAX && 5452428d7b3dSmrg mon->mon_gamma_blue != 1.0) 5453428d7b3dSmrg set_gamma(crtc->gamma_blue, crtc->gamma_size, 5454428d7b3dSmrg mon->mon_gamma_blue); 5455428d7b3dSmrg} 5456428d7b3dSmrg 5457428d7b3dSmrgstatic void crtc_init_gamma(xf86CrtcPtr crtc) 5458428d7b3dSmrg{ 5459428d7b3dSmrg uint16_t *gamma; 5460428d7b3dSmrg 5461428d7b3dSmrg /* Initialize the gamma ramps */ 5462428d7b3dSmrg gamma = NULL; 5463428d7b3dSmrg if (crtc->gamma_size == 256) 5464428d7b3dSmrg gamma = crtc->gamma_red; 5465428d7b3dSmrg if (gamma == NULL) 5466428d7b3dSmrg gamma = malloc(3 * 256 * sizeof(uint16_t)); 5467428d7b3dSmrg if (gamma) { 5468428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 5469428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 5470428d7b3dSmrg struct drm_mode_crtc_lut lut; 5471428d7b3dSmrg bool gamma_set = false; 5472428d7b3dSmrg 5473428d7b3dSmrg assert(sna_crtc); 5474428d7b3dSmrg 5475428d7b3dSmrg lut.crtc_id = sna_crtc->id; 5476428d7b3dSmrg lut.gamma_size = 256; 5477428d7b3dSmrg lut.red = (uintptr_t)(gamma); 5478428d7b3dSmrg lut.green = (uintptr_t)(gamma + 256); 5479428d7b3dSmrg lut.blue = (uintptr_t)(gamma + 2 * 256); 5480428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETGAMMA, &lut) == 0) { 5481428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(gamma, 3*256*sizeof(gamma[0]))); 5482428d7b3dSmrg gamma_set = 5483428d7b3dSmrg gamma[256 - 1] && 5484428d7b3dSmrg gamma[2*256 - 1] && 5485428d7b3dSmrg gamma[3*256 - 1]; 5486428d7b3dSmrg } 5487428d7b3dSmrg 5488428d7b3dSmrg DBG(("%s: CRTC:%d, pipe=%d: gamma set?=%d\n", 5489428d7b3dSmrg __FUNCTION__, sna_crtc->id, sna_crtc->pipe, 5490428d7b3dSmrg gamma_set)); 5491428d7b3dSmrg if (!gamma_set) { 5492428d7b3dSmrg int i; 5493428d7b3dSmrg 5494428d7b3dSmrg for (i = 0; i < 256; i++) { 5495428d7b3dSmrg gamma[i] = i << 8; 5496428d7b3dSmrg gamma[256 + i] = i << 8; 5497428d7b3dSmrg gamma[2*256 + i] = i << 8; 5498428d7b3dSmrg } 5499428d7b3dSmrg } 5500428d7b3dSmrg 5501428d7b3dSmrg if (gamma != crtc->gamma_red) { 5502428d7b3dSmrg free(crtc->gamma_red); 5503428d7b3dSmrg crtc->gamma_red = gamma; 5504428d7b3dSmrg crtc->gamma_green = gamma + 256; 5505428d7b3dSmrg crtc->gamma_blue = gamma + 2*256; 5506428d7b3dSmrg } 5507428d7b3dSmrg } 5508428d7b3dSmrg} 5509428d7b3dSmrg#else 5510428d7b3dSmrgstatic void output_set_gamma(xf86OutputPtr output, xf86CrtcPtr crtc) { } 5511428d7b3dSmrgstatic void crtc_init_gamma(xf86CrtcPtr crtc) { } 5512428d7b3dSmrg#endif 5513428d7b3dSmrg 5514428d7b3dSmrgstatic const char *preferred_mode(xf86OutputPtr output) 5515428d7b3dSmrg{ 5516428d7b3dSmrg const char *mode; 5517428d7b3dSmrg 5518428d7b3dSmrg mode = xf86GetOptValString(output->options, OPTION_PREFERRED_MODE); 5519428d7b3dSmrg if (mode) 5520428d7b3dSmrg return mode; 5521428d7b3dSmrg 5522428d7b3dSmrg if (output->scrn->display->modes && *output->scrn->display->modes) 5523428d7b3dSmrg return *output->scrn->display->modes; 5524428d7b3dSmrg 5525428d7b3dSmrg return NULL; 5526428d7b3dSmrg} 5527428d7b3dSmrg 5528428d7b3dSmrgstatic bool sna_probe_initial_configuration(struct sna *sna) 5529428d7b3dSmrg{ 5530428d7b3dSmrg ScrnInfoPtr scrn = sna->scrn; 5531428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 5532428d7b3dSmrg int width, height; 5533428d7b3dSmrg int i, j; 5534428d7b3dSmrg 5535428d7b3dSmrg assert((sna->flags & SNA_IS_HOSTED) == 0); 5536428d7b3dSmrg 5537428d7b3dSmrg if ((sna->flags & SNA_IS_SLAVED) == 0) { 5538428d7b3dSmrg const int user_overrides[] = { 5539428d7b3dSmrg OPTION_POSITION, 5540428d7b3dSmrg OPTION_BELOW, 5541428d7b3dSmrg OPTION_RIGHT_OF, 5542428d7b3dSmrg OPTION_ABOVE, 5543428d7b3dSmrg OPTION_LEFT_OF, 5544428d7b3dSmrg OPTION_ROTATE, 5545428d7b3dSmrg OPTION_PANNING, 5546428d7b3dSmrg }; 5547428d7b3dSmrg if (xf86ReturnOptValBool(sna->Options, OPTION_REPROBE, FALSE)) { 5548428d7b3dSmrg DBG(("%s: user requests reprobing\n", __FUNCTION__)); 5549428d7b3dSmrg return false; 5550428d7b3dSmrg } 5551428d7b3dSmrg 5552428d7b3dSmrg /* First scan through all outputs and look for user overrides */ 5553428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 5554428d7b3dSmrg xf86OutputPtr output = config->output[i]; 5555428d7b3dSmrg 5556428d7b3dSmrg for (j = 0; j < ARRAY_SIZE(user_overrides); j++) { 5557428d7b3dSmrg if (xf86GetOptValString(output->options, user_overrides[j])) { 5558428d7b3dSmrg DBG(("%s: user placement [%d] for %s\n", 5559428d7b3dSmrg __FUNCTION__, 5560428d7b3dSmrg user_overrides[j], 5561428d7b3dSmrg output->name)); 5562428d7b3dSmrg return false; 5563428d7b3dSmrg } 5564428d7b3dSmrg } 5565428d7b3dSmrg } 5566428d7b3dSmrg } 5567428d7b3dSmrg 5568428d7b3dSmrg /* Copy the existing modes on each CRTCs */ 5569428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 5570428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 5571428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 5572428d7b3dSmrg struct drm_mode_crtc mode; 5573428d7b3dSmrg 5574428d7b3dSmrg crtc->enabled = FALSE; 5575428d7b3dSmrg crtc->desiredMode.status = MODE_NOMODE; 5576428d7b3dSmrg 5577428d7b3dSmrg crtc_init_gamma(crtc); 5578428d7b3dSmrg 5579428d7b3dSmrg /* Retrieve the current mode */ 5580428d7b3dSmrg VG_CLEAR(mode); 5581428d7b3dSmrg mode.crtc_id = sna_crtc->id; 5582428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode)) 5583428d7b3dSmrg continue; 5584428d7b3dSmrg 5585428d7b3dSmrg DBG(("%s: CRTC:%d, pipe=%d: has mode?=%d\n", __FUNCTION__, 5586428d7b3dSmrg sna_crtc->id, sna_crtc->pipe, 5587428d7b3dSmrg mode.mode_valid && mode.mode.clock)); 5588428d7b3dSmrg 5589428d7b3dSmrg if (!mode.mode_valid || mode.mode.clock == 0) 5590428d7b3dSmrg continue; 5591428d7b3dSmrg 5592428d7b3dSmrg mode_from_kmode(scrn, &mode.mode, &crtc->desiredMode); 5593428d7b3dSmrg crtc->desiredRotation = sna_crtc->primary.rotation.current; 5594428d7b3dSmrg crtc->desiredX = mode.x; 5595428d7b3dSmrg crtc->desiredY = mode.y; 5596428d7b3dSmrg crtc->desiredTransformPresent = FALSE; 5597428d7b3dSmrg } 5598428d7b3dSmrg 5599428d7b3dSmrg /* Reconstruct outputs pointing to active CRTC */ 5600428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 5601428d7b3dSmrg xf86OutputPtr output = config->output[i]; 5602428d7b3dSmrg uint32_t crtc_id; 5603428d7b3dSmrg 5604428d7b3dSmrg assert(to_sna_output(output)); 5605428d7b3dSmrg 5606428d7b3dSmrg crtc_id = (uintptr_t)output->crtc; 5607428d7b3dSmrg output->crtc = NULL; 5608428d7b3dSmrg if (sna->flags & SNA_IS_SLAVED) 5609428d7b3dSmrg continue; 5610428d7b3dSmrg 5611428d7b3dSmrg if (crtc_id == 0) { 5612428d7b3dSmrg DBG(("%s: not using output %s, disconnected\n", 5613428d7b3dSmrg __FUNCTION__, output->name)); 5614428d7b3dSmrg continue; 5615428d7b3dSmrg } 5616428d7b3dSmrg 5617428d7b3dSmrg if (xf86ReturnOptValBool(output->options, OPTION_DISABLE, 0)) { 5618428d7b3dSmrg DBG(("%s: not using output %s, manually disabled\n", 5619428d7b3dSmrg __FUNCTION__, output->name)); 5620428d7b3dSmrg continue; 5621428d7b3dSmrg } 5622428d7b3dSmrg 5623428d7b3dSmrg for (j = 0; j < sna->mode.num_real_crtc; j++) { 5624428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[j]; 5625428d7b3dSmrg 5626428d7b3dSmrg assert(to_sna_crtc(crtc)); 5627428d7b3dSmrg if (to_sna_crtc(crtc)->id != crtc_id) 5628428d7b3dSmrg continue; 5629428d7b3dSmrg 5630428d7b3dSmrg if (crtc->desiredMode.status == MODE_OK) { 5631428d7b3dSmrg DisplayModePtr M; 5632428d7b3dSmrg const char *pref; 5633428d7b3dSmrg 5634428d7b3dSmrg pref = preferred_mode(output); 5635428d7b3dSmrg if (pref && strcmp(pref, crtc->desiredMode.name)) { 5636428d7b3dSmrg DBG(("%s: output %s user requests a different preferred mode %s, found %s\n", 5637428d7b3dSmrg __FUNCTION__, output->name, pref, crtc->desiredMode.name)); 5638428d7b3dSmrg return false; 5639428d7b3dSmrg } 5640428d7b3dSmrg 5641428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_PROBED, 5642428d7b3dSmrg "Output %s using initial mode %s on pipe %d\n", 5643428d7b3dSmrg output->name, 5644428d7b3dSmrg crtc->desiredMode.name, 5645428d7b3dSmrg to_sna_crtc(crtc)->pipe); 5646428d7b3dSmrg 5647428d7b3dSmrg output->crtc = crtc; 5648428d7b3dSmrg crtc->enabled = TRUE; 5649428d7b3dSmrg 5650428d7b3dSmrg if (output->mm_width == 0 || output->mm_height == 0) { 5651428d7b3dSmrg output->mm_height = (crtc->desiredMode.VDisplay * 254) / (10*DEFAULT_DPI); 5652428d7b3dSmrg output->mm_width = (crtc->desiredMode.HDisplay * 254) / (10*DEFAULT_DPI); 5653428d7b3dSmrg } 5654428d7b3dSmrg 5655428d7b3dSmrg output_set_gamma(output, crtc); 5656428d7b3dSmrg 5657428d7b3dSmrg M = calloc(1, sizeof(DisplayModeRec)); 5658428d7b3dSmrg if (M) { 5659428d7b3dSmrg *M = crtc->desiredMode; 5660428d7b3dSmrg M->name = strdup(M->name); 5661428d7b3dSmrg output->probed_modes = 5662428d7b3dSmrg xf86ModesAdd(output->probed_modes, M); 5663428d7b3dSmrg } 5664428d7b3dSmrg } 5665428d7b3dSmrg 5666428d7b3dSmrg break; 5667428d7b3dSmrg } 5668428d7b3dSmrg 5669428d7b3dSmrg if (j == sna->mode.num_real_crtc) { 5670428d7b3dSmrg /* Can not find the earlier associated CRTC, bail */ 5671428d7b3dSmrg DBG(("%s: existing setup conflicts with output assignment (Zaphod), reprobing\n", 5672428d7b3dSmrg __FUNCTION__)); 5673428d7b3dSmrg return false; 5674428d7b3dSmrg } 5675428d7b3dSmrg } 5676428d7b3dSmrg 5677428d7b3dSmrg width = height = 0; 5678428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 5679428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 5680428d7b3dSmrg int w, h; 5681428d7b3dSmrg 5682428d7b3dSmrg if (!crtc->enabled) 5683428d7b3dSmrg continue; 5684428d7b3dSmrg 5685428d7b3dSmrg w = crtc->desiredX + crtc->desiredMode.HDisplay; 5686428d7b3dSmrg if (w > width) 5687428d7b3dSmrg width = w; 5688428d7b3dSmrg h = crtc->desiredY + crtc->desiredMode.VDisplay; 5689428d7b3dSmrg if (h > height) 5690428d7b3dSmrg height = h; 5691428d7b3dSmrg } 5692428d7b3dSmrg 5693428d7b3dSmrg /* Prefer the native panel size if any */ 5694428d7b3dSmrg if (!width || !height) { 5695428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 5696428d7b3dSmrg xf86OutputPtr output = config->output[i]; 5697428d7b3dSmrg struct sna_output *sna_output = to_sna_output(output); 5698428d7b3dSmrg 5699428d7b3dSmrg if (!sna_output->is_panel) 5700428d7b3dSmrg continue; 5701428d7b3dSmrg 5702428d7b3dSmrg DBG(("%s: querying panel '%s' for preferred unattached size\n", 5703428d7b3dSmrg __FUNCTION__, output->name)); 5704428d7b3dSmrg 5705428d7b3dSmrg if (sna_output_detect(output) != XF86OutputStatusConnected) 5706428d7b3dSmrg continue; 5707428d7b3dSmrg 5708428d7b3dSmrg if (sna_output->num_modes == 0) 5709428d7b3dSmrg continue; 5710428d7b3dSmrg 5711428d7b3dSmrg width = sna_output->modes[0].hdisplay; 5712428d7b3dSmrg height= sna_output->modes[0].vdisplay; 5713428d7b3dSmrg 5714428d7b3dSmrg DBG(("%s: panel '%s' is %dx%d\n", 5715428d7b3dSmrg __FUNCTION__, output->name, width, height)); 5716428d7b3dSmrg break; 5717428d7b3dSmrg } 5718428d7b3dSmrg } 5719428d7b3dSmrg 5720428d7b3dSmrg if (!width || !height) { 5721428d7b3dSmrg width = 1024; 5722428d7b3dSmrg height = 768; 5723428d7b3dSmrg } 5724428d7b3dSmrg 5725428d7b3dSmrg scrn->display->frameX0 = 0; 5726428d7b3dSmrg scrn->display->frameY0 = 0; 5727428d7b3dSmrg scrn->display->virtualX = width; 5728428d7b3dSmrg scrn->display->virtualY = height; 5729428d7b3dSmrg 5730428d7b3dSmrg scrn->virtualX = width; 5731428d7b3dSmrg scrn->virtualY = height; 5732428d7b3dSmrg 5733428d7b3dSmrg xf86SetScrnInfoModes(sna->scrn); 5734428d7b3dSmrg DBG(("%s: SetScrnInfoModes = %p\n", __FUNCTION__, scrn->modes)); 5735428d7b3dSmrg return scrn->modes != NULL; 5736428d7b3dSmrg} 5737428d7b3dSmrg 5738428d7b3dSmrgstatic void 5739428d7b3dSmrgsanitize_outputs(struct sna *sna) 5740428d7b3dSmrg{ 5741428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 5742428d7b3dSmrg int i; 5743428d7b3dSmrg 5744428d7b3dSmrg for (i = 0; i < config->num_output; i++) 5745428d7b3dSmrg config->output[i]->crtc = NULL; 5746428d7b3dSmrg} 5747428d7b3dSmrg 5748428d7b3dSmrgstatic bool has_flip(struct sna *sna) 5749428d7b3dSmrg{ 5750428d7b3dSmrg drm_i915_getparam_t gp; 5751428d7b3dSmrg int v; 5752428d7b3dSmrg 5753428d7b3dSmrg if (sna->flags & SNA_NO_FLIP) 5754428d7b3dSmrg return false; 5755428d7b3dSmrg 5756428d7b3dSmrg v = 0; 5757428d7b3dSmrg 5758428d7b3dSmrg VG_CLEAR(gp); 5759428d7b3dSmrg gp.param = I915_PARAM_HAS_PAGEFLIPPING; 5760428d7b3dSmrg gp.value = &v; 5761428d7b3dSmrg 5762428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GETPARAM, &gp)) 5763428d7b3dSmrg return false; 5764428d7b3dSmrg 5765428d7b3dSmrg VG(VALGRIND_MAKE_MEM_DEFINED(&v, sizeof(v))); 5766428d7b3dSmrg return v > 0; 5767428d7b3dSmrg} 5768428d7b3dSmrg 5769428d7b3dSmrgstatic bool has_flip__async(struct sna *sna) 5770428d7b3dSmrg{ 5771428d7b3dSmrg#define DRM_CAP_ASYNC_PAGE_FLIP 0x7 5772428d7b3dSmrg struct local_get_cap { 5773428d7b3dSmrg uint64_t name; 5774428d7b3dSmrg uint64_t value; 5775428d7b3dSmrg } cap = { DRM_CAP_ASYNC_PAGE_FLIP }; 5776428d7b3dSmrg 5777428d7b3dSmrg if (sna->flags & SNA_NO_FLIP) 5778428d7b3dSmrg return false; 5779428d7b3dSmrg 5780428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_GET_CAP, &cap) == 0) 5781428d7b3dSmrg return cap.value > 0; 5782428d7b3dSmrg 5783428d7b3dSmrg return false; 5784428d7b3dSmrg} 5785428d7b3dSmrg 5786428d7b3dSmrgstatic void 5787428d7b3dSmrgprobe_capabilities(struct sna *sna) 5788428d7b3dSmrg{ 5789428d7b3dSmrg sna->flags &= ~(SNA_HAS_FLIP | SNA_HAS_ASYNC_FLIP); 5790428d7b3dSmrg if (has_flip(sna)) 5791428d7b3dSmrg sna->flags |= SNA_HAS_FLIP; 5792428d7b3dSmrg if (has_flip__async(sna)) 5793428d7b3dSmrg sna->flags |= SNA_HAS_ASYNC_FLIP; 5794428d7b3dSmrg DBG(("%s: page flips? %s, async? %s\n", __FUNCTION__, 5795428d7b3dSmrg sna->flags & SNA_HAS_FLIP ? "enabled" : "disabled", 5796428d7b3dSmrg sna->flags & SNA_HAS_ASYNC_FLIP ? "enabled" : "disabled")); 5797428d7b3dSmrg} 5798428d7b3dSmrg 5799428d7b3dSmrgvoid 5800428d7b3dSmrgsna_crtc_config_notify(ScreenPtr screen) 5801428d7b3dSmrg{ 5802428d7b3dSmrg struct sna *sna = to_sna_from_screen(screen); 5803428d7b3dSmrg 5804428d7b3dSmrg DBG(("%s(dirty?=%d)\n", __FUNCTION__, sna->mode.dirty)); 5805428d7b3dSmrg if (!sna->mode.dirty) 5806428d7b3dSmrg return; 5807428d7b3dSmrg 5808428d7b3dSmrg if (disable_unused_crtc(sna)) { 5809428d7b3dSmrg /* This will have recursed, so simply bail at this point */ 5810428d7b3dSmrg assert(sna->mode.dirty == false); 5811428d7b3dSmrg#ifdef RANDR_12_INTERFACE 5812428d7b3dSmrg xf86RandR12TellChanged(screen); 5813428d7b3dSmrg#endif 5814428d7b3dSmrg return; 5815428d7b3dSmrg } 5816428d7b3dSmrg 5817428d7b3dSmrg update_flush_interval(sna); 5818428d7b3dSmrg sna_cursors_reload(sna); 5819428d7b3dSmrg 5820428d7b3dSmrg probe_capabilities(sna); 5821428d7b3dSmrg sna_present_update(sna); 5822428d7b3dSmrg 5823428d7b3dSmrg sna->mode.dirty = false; 5824428d7b3dSmrg} 5825428d7b3dSmrg 5826428d7b3dSmrg#if HAS_PIXMAP_SHARING 5827428d7b3dSmrg#define sna_setup_provider(scrn) xf86ProviderSetup(scrn, NULL, "Intel") 5828428d7b3dSmrg#else 5829428d7b3dSmrg#define sna_setup_provider(scrn) 5830428d7b3dSmrg#endif 5831428d7b3dSmrg 5832428d7b3dSmrgbool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna) 5833428d7b3dSmrg{ 5834428d7b3dSmrg drmModeResPtr res; 5835428d7b3dSmrg int num_fake = 0; 5836428d7b3dSmrg int i; 5837428d7b3dSmrg 5838428d7b3dSmrg if (sna->flags & SNA_IS_HOSTED) { 5839428d7b3dSmrg sna_setup_provider(scrn); 5840428d7b3dSmrg return true; 5841428d7b3dSmrg } 5842428d7b3dSmrg 5843428d7b3dSmrg probe_capabilities(sna); 5844428d7b3dSmrg 5845428d7b3dSmrg if (!xf86GetOptValInteger(sna->Options, OPTION_VIRTUAL, &num_fake)) 5846428d7b3dSmrg num_fake = 1; 5847428d7b3dSmrg 5848428d7b3dSmrg res = drmModeGetResources(sna->kgem.fd); 5849428d7b3dSmrg if (res && 5850428d7b3dSmrg (res->count_crtcs == 0 || 5851428d7b3dSmrg res->count_encoders == 0 || 5852428d7b3dSmrg res->count_connectors == 0)) { 5853428d7b3dSmrg drmModeFreeResources(res); 5854428d7b3dSmrg res = NULL; 5855428d7b3dSmrg } 5856428d7b3dSmrg if (res) { 5857428d7b3dSmrg xf86CrtcConfigPtr xf86_config; 5858428d7b3dSmrg 5859428d7b3dSmrg assert(res->count_crtcs); 5860428d7b3dSmrg assert(res->count_connectors); 5861428d7b3dSmrg 5862428d7b3dSmrg xf86CrtcConfigInit(scrn, &sna_mode_funcs); 5863428d7b3dSmrg 5864428d7b3dSmrg xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 5865428d7b3dSmrg xf86_config->xf86_crtc_notify = sna_crtc_config_notify; 5866428d7b3dSmrg 5867428d7b3dSmrg for (i = 0; i < res->count_crtcs; i++) 5868428d7b3dSmrg if (!sna_crtc_add(scrn, res->crtcs[i])) 5869428d7b3dSmrg return false; 5870428d7b3dSmrg 5871428d7b3dSmrg sna->mode.num_real_crtc = xf86_config->num_crtc; 5872428d7b3dSmrg 5873428d7b3dSmrg sna->mode.num_real_encoder = res->count_encoders; 5874428d7b3dSmrg sna->mode.encoders = res->encoders; 5875428d7b3dSmrg res->encoders = NULL; 5876428d7b3dSmrg 5877428d7b3dSmrg for (i = 0; i < res->count_connectors; i++) 5878428d7b3dSmrg if (sna_output_add(sna, res->connectors[i], 0) < 0) 5879428d7b3dSmrg return false; 5880428d7b3dSmrg 5881428d7b3dSmrg sna->mode.num_real_output = xf86_config->num_output; 5882428d7b3dSmrg 5883428d7b3dSmrg sna->mode.max_crtc_width = res->max_width; 5884428d7b3dSmrg sna->mode.max_crtc_height = res->max_height; 5885428d7b3dSmrg 5886428d7b3dSmrg RegionEmpty(&sna->mode.shadow_region); 5887428d7b3dSmrg RegionEmpty(&sna->mode.shadow_cancel); 5888428d7b3dSmrg list_init(&sna->mode.shadow_crtc); 5889428d7b3dSmrg 5890428d7b3dSmrg drmModeFreeResources(res); 5891428d7b3dSmrg 5892428d7b3dSmrg sna_cursor_pre_init(sna); 5893428d7b3dSmrg sna_backlight_pre_init(sna); 5894428d7b3dSmrg 5895428d7b3dSmrg set_size_range(sna); 5896428d7b3dSmrg } else { 5897428d7b3dSmrg if (num_fake == 0) 5898428d7b3dSmrg num_fake = 1; 5899428d7b3dSmrg } 5900428d7b3dSmrg 5901428d7b3dSmrg if (!sna_mode_fake_init(sna, num_fake)) 5902428d7b3dSmrg return false; 5903428d7b3dSmrg 5904428d7b3dSmrg if (!sna_probe_initial_configuration(sna)) { 5905428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 5906428d7b3dSmrg 5907428d7b3dSmrg sanitize_outputs(sna); 5908428d7b3dSmrg if (config->num_crtc && config->num_output) { 5909428d7b3dSmrg if (!xf86ReturnOptValBool(config->output[0]->options, 5910428d7b3dSmrg OPTION_PRIMARY, FALSE)) 5911428d7b3dSmrg sort_config_outputs(sna); 5912428d7b3dSmrg xf86InitialConfiguration(scrn, TRUE); 5913428d7b3dSmrg } 5914428d7b3dSmrg } 5915428d7b3dSmrg sort_config_outputs(sna); 5916428d7b3dSmrg 5917428d7b3dSmrg sna_setup_provider(scrn); 5918428d7b3dSmrg return scrn->modes != NULL; 5919428d7b3dSmrg} 5920428d7b3dSmrg 5921428d7b3dSmrgbool 5922428d7b3dSmrgsna_mode_wants_tear_free(struct sna *sna) 5923428d7b3dSmrg{ 5924428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 5925428d7b3dSmrg int i; 5926428d7b3dSmrg 5927428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 5928428d7b3dSmrg struct sna_output *output = to_sna_output(config->output[i]); 5929428d7b3dSmrg int id = find_property(sna, output, "Panel Self-Refresh"); 5930428d7b3dSmrg if (id !=-1 && output->prop_values[id] != -1) { 5931428d7b3dSmrg DBG(("%s: Panel Self-Refresh detected on %s\n", 5932428d7b3dSmrg __FUNCTION__, config->output[i]->name)); 5933428d7b3dSmrg return true; 5934428d7b3dSmrg } 5935428d7b3dSmrg } 5936428d7b3dSmrg 5937428d7b3dSmrg return false; 5938428d7b3dSmrg} 5939428d7b3dSmrg 5940428d7b3dSmrgvoid 5941428d7b3dSmrgsna_mode_set_primary(struct sna *sna) 5942428d7b3dSmrg{ 5943428d7b3dSmrg#ifdef RANDR_12_INTERFACE 5944428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 5945428d7b3dSmrg rrScrPrivPtr rr = rrGetScrPriv(xf86ScrnToScreen(sna->scrn)); 5946428d7b3dSmrg int i; 5947428d7b3dSmrg 5948428d7b3dSmrg if (rr == NULL || rr->primaryOutput) 5949428d7b3dSmrg return; 5950428d7b3dSmrg 5951428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 5952428d7b3dSmrg xf86OutputPtr output = config->output[i]; 5953428d7b3dSmrg 5954428d7b3dSmrg if (!xf86ReturnOptValBool(output->options, OPTION_PRIMARY, FALSE)) 5955428d7b3dSmrg continue; 5956428d7b3dSmrg 5957428d7b3dSmrg DBG(("%s: setting PrimaryOutput %s\n", __FUNCTION__, output->name)); 5958428d7b3dSmrg rr->primaryOutput = output->randr_output; 5959428d7b3dSmrg RROutputChanged(rr->primaryOutput, 0); 5960428d7b3dSmrg rr->layoutChanged = TRUE; 5961428d7b3dSmrg break; 5962428d7b3dSmrg } 5963428d7b3dSmrg#endif 5964428d7b3dSmrg} 5965428d7b3dSmrg 5966428d7b3dSmrgbool 5967428d7b3dSmrgsna_mode_disable(struct sna *sna) 5968428d7b3dSmrg{ 5969428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 5970428d7b3dSmrg int i; 5971428d7b3dSmrg 5972428d7b3dSmrg if (sna->flags & SNA_IS_HOSTED) 5973428d7b3dSmrg return false; 5974428d7b3dSmrg 5975428d7b3dSmrg if (!sna->scrn->vtSema) 5976428d7b3dSmrg return false; 5977428d7b3dSmrg 5978428d7b3dSmrg /* XXX we will cause previously hidden cursors to be reshown, but 5979428d7b3dSmrg * this should be a rare fixup case for severe fragmentation. 5980428d7b3dSmrg */ 5981428d7b3dSmrg sna_hide_cursors(sna->scrn); 5982428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) 5983428d7b3dSmrg sna_crtc_disable(config->crtc[i]); 5984428d7b3dSmrg assert(sna->mode.front_active == 0); 5985428d7b3dSmrg 5986428d7b3dSmrg sna_mode_wakeup(sna); 5987428d7b3dSmrg kgem_clean_scanout_cache(&sna->kgem); 5988428d7b3dSmrg return true; 5989428d7b3dSmrg} 5990428d7b3dSmrg 5991428d7b3dSmrgvoid 5992428d7b3dSmrgsna_mode_enable(struct sna *sna) 5993428d7b3dSmrg{ 5994428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 5995428d7b3dSmrg int i; 5996428d7b3dSmrg 5997428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 5998428d7b3dSmrg 5999428d7b3dSmrg if (sna->flags & SNA_IS_HOSTED) 6000428d7b3dSmrg return; 6001428d7b3dSmrg 6002428d7b3dSmrg if (!sna->scrn->vtSema) 6003428d7b3dSmrg return; 6004428d7b3dSmrg 6005428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 6006428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 6007428d7b3dSmrg 6008428d7b3dSmrg DBG(("%s: crtc[%d].enabled?=%d\n", __FUNCTION__, i, crtc->enabled)); 6009428d7b3dSmrg assert(to_sna_crtc(crtc) != NULL); 6010428d7b3dSmrg if (!crtc->enabled) 6011428d7b3dSmrg continue; 6012428d7b3dSmrg 6013428d7b3dSmrg if (crtc->mode.Clock == 0) 6014428d7b3dSmrg continue; 6015428d7b3dSmrg 6016428d7b3dSmrg __sna_crtc_set_mode(crtc); 6017428d7b3dSmrg } 6018428d7b3dSmrg 6019428d7b3dSmrg update_flush_interval(sna); 6020428d7b3dSmrg sna_show_cursors(sna->scrn); 6021428d7b3dSmrg sna->mode.dirty = false; 6022428d7b3dSmrg} 6023428d7b3dSmrg 6024428d7b3dSmrgvoid 6025428d7b3dSmrgsna_mode_close(struct sna *sna) 6026428d7b3dSmrg{ 6027428d7b3dSmrg sna_mode_wakeup(sna); 6028428d7b3dSmrg 6029428d7b3dSmrg if (sna->flags & SNA_IS_HOSTED) 6030428d7b3dSmrg return; 6031428d7b3dSmrg 6032428d7b3dSmrg sna_mode_reset(sna); 6033428d7b3dSmrg 6034428d7b3dSmrg sna_cursor_close(sna); 6035428d7b3dSmrg sna_cursors_fini(sna); 6036428d7b3dSmrg 6037428d7b3dSmrg sna_backlight_close(sna); 6038428d7b3dSmrg sna->mode.dirty = false; 6039428d7b3dSmrg} 6040428d7b3dSmrg 6041428d7b3dSmrgvoid 6042428d7b3dSmrgsna_mode_fini(struct sna *sna) 6043428d7b3dSmrg{ 6044428d7b3dSmrg free(sna->mode.encoders); 6045428d7b3dSmrg} 6046428d7b3dSmrg 6047428d7b3dSmrgstatic bool sna_box_intersect(BoxPtr r, const BoxRec *a, const BoxRec *b) 6048428d7b3dSmrg{ 6049428d7b3dSmrg r->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 6050428d7b3dSmrg r->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 6051428d7b3dSmrg if (r->x1 >= r->x2) 6052428d7b3dSmrg return false; 6053428d7b3dSmrg 6054428d7b3dSmrg r->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 6055428d7b3dSmrg r->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 6056428d7b3dSmrg DBG(("%s: (%d, %d), (%d, %d) intersect (%d, %d), (%d, %d) = (%d, %d), (%d, %d)\n", 6057428d7b3dSmrg __FUNCTION__, 6058428d7b3dSmrg a->x1, a->y1, a->x2, a->y2, 6059428d7b3dSmrg b->x1, b->y1, b->x2, b->y2, 6060428d7b3dSmrg r->x1, r->y1, r->x2, r->y2)); 6061428d7b3dSmrg if (r->y1 >= r->y2) 6062428d7b3dSmrg return false; 6063428d7b3dSmrg 6064428d7b3dSmrg return true; 6065428d7b3dSmrg} 6066428d7b3dSmrg 6067428d7b3dSmrgstatic int sna_box_area(const BoxRec *box) 6068428d7b3dSmrg{ 6069428d7b3dSmrg return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1); 6070428d7b3dSmrg} 6071428d7b3dSmrg 6072428d7b3dSmrg/* 6073428d7b3dSmrg * Return the crtc covering 'box'. If two crtcs cover a portion of 6074428d7b3dSmrg * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 6075428d7b3dSmrg * with greater coverage 6076428d7b3dSmrg */ 6077428d7b3dSmrgxf86CrtcPtr 6078428d7b3dSmrgsna_covering_crtc(struct sna *sna, const BoxRec *box, xf86CrtcPtr desired) 6079428d7b3dSmrg{ 6080428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 6081428d7b3dSmrg xf86CrtcPtr best_crtc; 6082428d7b3dSmrg int best_coverage, c; 6083428d7b3dSmrg 6084428d7b3dSmrg if (sna->flags & SNA_IS_HOSTED) 6085428d7b3dSmrg return NULL; 6086428d7b3dSmrg 6087428d7b3dSmrg /* If we do not own the VT, we do not own the CRTC either */ 6088428d7b3dSmrg if (!sna->scrn->vtSema) 6089428d7b3dSmrg return NULL; 6090428d7b3dSmrg 6091428d7b3dSmrg DBG(("%s for box=(%d, %d), (%d, %d)\n", 6092428d7b3dSmrg __FUNCTION__, box->x1, box->y1, box->x2, box->y2)); 6093428d7b3dSmrg 6094428d7b3dSmrg if (desired == NULL) { 6095428d7b3dSmrg rrScrPrivPtr rr = rrGetScrPriv(xf86ScrnToScreen(sna->scrn)); 6096428d7b3dSmrg if (rr && rr->primaryOutput) { 6097428d7b3dSmrg xf86OutputPtr output = rr->primaryOutput->devPrivate; 6098428d7b3dSmrg DBG(("%s: have PrimaryOutput? %d marking as desired\n", __FUNCTION__, output->crtc != NULL)); 6099428d7b3dSmrg desired = output->crtc; 6100428d7b3dSmrg } 6101428d7b3dSmrg } 6102428d7b3dSmrg if (desired && to_sna_crtc(desired) && to_sna_crtc(desired)->bo) { 6103428d7b3dSmrg BoxRec cover_box; 6104428d7b3dSmrg if (sna_box_intersect(&cover_box, &desired->bounds, box)) { 6105428d7b3dSmrg DBG(("%s: box overlaps desired crtc: (%d, %d), (%d, %d)\n", 6106428d7b3dSmrg __FUNCTION__, 6107428d7b3dSmrg cover_box.x1, cover_box.y1, 6108428d7b3dSmrg cover_box.x2, cover_box.y2)); 6109428d7b3dSmrg return desired; 6110428d7b3dSmrg } 6111428d7b3dSmrg } 6112428d7b3dSmrg 6113428d7b3dSmrg best_crtc = NULL; 6114428d7b3dSmrg best_coverage = 0; 6115428d7b3dSmrg for (c = 0; c < sna->mode.num_real_crtc; c++) { 6116428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[c]; 6117428d7b3dSmrg BoxRec cover_box; 6118428d7b3dSmrg int coverage; 6119428d7b3dSmrg 6120428d7b3dSmrg assert(to_sna_crtc(crtc)); 6121428d7b3dSmrg 6122428d7b3dSmrg /* If the CRTC is off, treat it as not covering */ 6123428d7b3dSmrg if (to_sna_crtc(crtc)->bo == NULL) { 6124428d7b3dSmrg DBG(("%s: crtc %d off, skipping\n", __FUNCTION__, c)); 6125428d7b3dSmrg continue; 6126428d7b3dSmrg } 6127428d7b3dSmrg 6128428d7b3dSmrg DBG(("%s: crtc %d: (%d, %d), (%d, %d)\n", 6129428d7b3dSmrg __FUNCTION__, c, 6130428d7b3dSmrg crtc->bounds.x1, crtc->bounds.y1, 6131428d7b3dSmrg crtc->bounds.x2, crtc->bounds.y2)); 6132428d7b3dSmrg if (*(const uint64_t *)box == *(uint64_t *)&crtc->bounds) { 6133428d7b3dSmrg DBG(("%s: box exactly matches crtc [%d]\n", 6134428d7b3dSmrg __FUNCTION__, c)); 6135428d7b3dSmrg return crtc; 6136428d7b3dSmrg } 6137428d7b3dSmrg 6138428d7b3dSmrg if (!sna_box_intersect(&cover_box, &crtc->bounds, box)) 6139428d7b3dSmrg continue; 6140428d7b3dSmrg 6141428d7b3dSmrg DBG(("%s: box instersects (%d, %d), (%d, %d) of crtc %d\n", 6142428d7b3dSmrg __FUNCTION__, 6143428d7b3dSmrg cover_box.x1, cover_box.y1, 6144428d7b3dSmrg cover_box.x2, cover_box.y2, 6145428d7b3dSmrg c)); 6146428d7b3dSmrg 6147428d7b3dSmrg coverage = sna_box_area(&cover_box); 6148428d7b3dSmrg DBG(("%s: box covers %d of crtc %d\n", 6149428d7b3dSmrg __FUNCTION__, coverage, c)); 6150428d7b3dSmrg if (coverage > best_coverage) { 6151428d7b3dSmrg best_crtc = crtc; 6152428d7b3dSmrg best_coverage = coverage; 6153428d7b3dSmrg } 6154428d7b3dSmrg } 6155428d7b3dSmrg DBG(("%s: best crtc = %p, coverage = %d\n", 6156428d7b3dSmrg __FUNCTION__, best_crtc, best_coverage)); 6157428d7b3dSmrg return best_crtc; 6158428d7b3dSmrg} 6159428d7b3dSmrg 6160428d7b3dSmrg#define MI_LOAD_REGISTER_IMM (0x22<<23) 6161428d7b3dSmrg 6162428d7b3dSmrgstatic bool sna_emit_wait_for_scanline_hsw(struct sna *sna, 6163428d7b3dSmrg xf86CrtcPtr crtc, 6164428d7b3dSmrg int pipe, int y1, int y2, 6165428d7b3dSmrg bool full_height) 6166428d7b3dSmrg{ 6167428d7b3dSmrg uint32_t event; 6168428d7b3dSmrg uint32_t *b; 6169428d7b3dSmrg 6170428d7b3dSmrg if (!sna->kgem.has_secure_batches) 6171428d7b3dSmrg return false; 6172428d7b3dSmrg 6173428d7b3dSmrg b = kgem_get_batch(&sna->kgem); 6174428d7b3dSmrg sna->kgem.nbatch += 17; 6175428d7b3dSmrg 6176428d7b3dSmrg switch (pipe) { 6177428d7b3dSmrg default: assert(0); 6178428d7b3dSmrg case 0: event = 1 << 0; break; 6179428d7b3dSmrg case 1: event = 1 << 8; break; 6180428d7b3dSmrg case 2: event = 1 << 14; break; 6181428d7b3dSmrg } 6182428d7b3dSmrg 6183428d7b3dSmrg b[0] = MI_LOAD_REGISTER_IMM | 1; 6184428d7b3dSmrg b[1] = 0x44050; /* DERRMR */ 6185428d7b3dSmrg b[2] = ~event; 6186428d7b3dSmrg b[3] = MI_LOAD_REGISTER_IMM | 1; 6187428d7b3dSmrg b[4] = 0xa188; /* FORCEWAKE_MT */ 6188428d7b3dSmrg b[5] = 2 << 16 | 2; 6189428d7b3dSmrg 6190428d7b3dSmrg /* The documentation says that the LOAD_SCAN_LINES command 6191428d7b3dSmrg * always comes in pairs. Don't ask me why. */ 6192428d7b3dSmrg switch (pipe) { 6193428d7b3dSmrg default: assert(0); 6194428d7b3dSmrg case 0: event = 0 << 19; break; 6195428d7b3dSmrg case 1: event = 1 << 19; break; 6196428d7b3dSmrg case 2: event = 4 << 19; break; 6197428d7b3dSmrg } 6198428d7b3dSmrg b[8] = b[6] = MI_LOAD_SCAN_LINES_INCL | event; 6199428d7b3dSmrg b[9] = b[7] = (y1 << 16) | (y2-1); 6200428d7b3dSmrg 6201428d7b3dSmrg switch (pipe) { 6202428d7b3dSmrg default: assert(0); 6203428d7b3dSmrg case 0: event = 1 << 0; break; 6204428d7b3dSmrg case 1: event = 1 << 8; break; 6205428d7b3dSmrg case 2: event = 1 << 14; break; 6206428d7b3dSmrg } 6207428d7b3dSmrg b[10] = MI_WAIT_FOR_EVENT | event; 6208428d7b3dSmrg 6209428d7b3dSmrg b[11] = MI_LOAD_REGISTER_IMM | 1; 6210428d7b3dSmrg b[12] = 0xa188; /* FORCEWAKE_MT */ 6211428d7b3dSmrg b[13] = 2 << 16; 6212428d7b3dSmrg b[14] = MI_LOAD_REGISTER_IMM | 1; 6213428d7b3dSmrg b[15] = 0x44050; /* DERRMR */ 6214428d7b3dSmrg b[16] = ~0; 6215428d7b3dSmrg 6216428d7b3dSmrg sna->kgem.batch_flags |= I915_EXEC_SECURE; 6217428d7b3dSmrg return true; 6218428d7b3dSmrg} 6219428d7b3dSmrg 6220428d7b3dSmrgstatic bool sna_emit_wait_for_scanline_ivb(struct sna *sna, 6221428d7b3dSmrg xf86CrtcPtr crtc, 6222428d7b3dSmrg int pipe, int y1, int y2, 6223428d7b3dSmrg bool full_height) 6224428d7b3dSmrg{ 6225428d7b3dSmrg uint32_t event, *b; 6226428d7b3dSmrg 6227428d7b3dSmrg if (!sna->kgem.has_secure_batches) 6228428d7b3dSmrg return false; 6229428d7b3dSmrg 6230428d7b3dSmrg assert(y1 >= 0); 6231428d7b3dSmrg assert(y2 > y1); 6232428d7b3dSmrg assert(sna->kgem.mode); 6233428d7b3dSmrg 6234428d7b3dSmrg /* Always program one less than the desired value */ 6235428d7b3dSmrg if (--y1 < 0) 6236428d7b3dSmrg y1 = crtc->bounds.y2; 6237428d7b3dSmrg y2--; 6238428d7b3dSmrg 6239428d7b3dSmrg switch (pipe) { 6240428d7b3dSmrg default: 6241428d7b3dSmrg assert(0); 6242428d7b3dSmrg case 0: 6243428d7b3dSmrg event = 1 << (full_height ? 3 : 0); 6244428d7b3dSmrg break; 6245428d7b3dSmrg case 1: 6246428d7b3dSmrg event = 1 << (full_height ? 11 : 8); 6247428d7b3dSmrg break; 6248428d7b3dSmrg case 2: 6249428d7b3dSmrg event = 1 << (full_height ? 21 : 14); 6250428d7b3dSmrg break; 6251428d7b3dSmrg } 6252428d7b3dSmrg 6253428d7b3dSmrg b = kgem_get_batch(&sna->kgem); 6254428d7b3dSmrg 6255428d7b3dSmrg /* Both the LRI and WAIT_FOR_EVENT must be in the same cacheline */ 6256428d7b3dSmrg if (((sna->kgem.nbatch + 6) >> 4) != (sna->kgem.nbatch + 10) >> 4) { 6257428d7b3dSmrg int dw = sna->kgem.nbatch + 6; 6258428d7b3dSmrg dw = ALIGN(dw, 16) - dw; 6259428d7b3dSmrg while (dw--) 6260428d7b3dSmrg *b++ = MI_NOOP; 6261428d7b3dSmrg } 6262428d7b3dSmrg 6263428d7b3dSmrg b[0] = MI_LOAD_REGISTER_IMM | 1; 6264428d7b3dSmrg b[1] = 0x44050; /* DERRMR */ 6265428d7b3dSmrg b[2] = ~event; 6266428d7b3dSmrg b[3] = MI_LOAD_REGISTER_IMM | 1; 6267428d7b3dSmrg b[4] = 0xa188; /* FORCEWAKE_MT */ 6268428d7b3dSmrg b[5] = 2 << 16 | 2; 6269428d7b3dSmrg b[6] = MI_LOAD_REGISTER_IMM | 1; 6270428d7b3dSmrg b[7] = 0x70068 + 0x1000 * pipe; 6271428d7b3dSmrg b[8] = (1 << 31) | (1 << 30) | (y1 << 16) | y2; 6272428d7b3dSmrg b[9] = MI_WAIT_FOR_EVENT | event; 6273428d7b3dSmrg b[10] = MI_LOAD_REGISTER_IMM | 1; 6274428d7b3dSmrg b[11] = 0xa188; /* FORCEWAKE_MT */ 6275428d7b3dSmrg b[12] = 2 << 16; 6276428d7b3dSmrg b[13] = MI_LOAD_REGISTER_IMM | 1; 6277428d7b3dSmrg b[14] = 0x44050; /* DERRMR */ 6278428d7b3dSmrg b[15] = ~0; 6279428d7b3dSmrg 6280428d7b3dSmrg sna->kgem.nbatch = b - sna->kgem.batch + 16; 6281428d7b3dSmrg 6282428d7b3dSmrg sna->kgem.batch_flags |= I915_EXEC_SECURE; 6283428d7b3dSmrg return true; 6284428d7b3dSmrg} 6285428d7b3dSmrg 6286428d7b3dSmrgstatic bool sna_emit_wait_for_scanline_gen6(struct sna *sna, 6287428d7b3dSmrg xf86CrtcPtr crtc, 6288428d7b3dSmrg int pipe, int y1, int y2, 6289428d7b3dSmrg bool full_height) 6290428d7b3dSmrg{ 6291428d7b3dSmrg uint32_t *b; 6292428d7b3dSmrg uint32_t event; 6293428d7b3dSmrg 6294428d7b3dSmrg if (!sna->kgem.has_secure_batches) 6295428d7b3dSmrg return false; 6296428d7b3dSmrg 6297428d7b3dSmrg assert(y1 >= 0); 6298428d7b3dSmrg assert(y2 > y1); 6299428d7b3dSmrg assert(sna->kgem.mode == KGEM_RENDER); 6300428d7b3dSmrg 6301428d7b3dSmrg /* Always program one less than the desired value */ 6302428d7b3dSmrg if (--y1 < 0) 6303428d7b3dSmrg y1 = crtc->bounds.y2; 6304428d7b3dSmrg y2--; 6305428d7b3dSmrg 6306428d7b3dSmrg /* The scanline granularity is 3 bits */ 6307428d7b3dSmrg y1 &= ~7; 6308428d7b3dSmrg y2 &= ~7; 6309428d7b3dSmrg if (y2 == y1) 6310428d7b3dSmrg return false; 6311428d7b3dSmrg 6312428d7b3dSmrg event = 1 << (3*full_height + pipe*8); 6313428d7b3dSmrg 6314428d7b3dSmrg b = kgem_get_batch(&sna->kgem); 6315428d7b3dSmrg sna->kgem.nbatch += 16; 6316428d7b3dSmrg 6317428d7b3dSmrg b[0] = MI_LOAD_REGISTER_IMM | 1; 6318428d7b3dSmrg b[1] = 0x44050; /* DERRMR */ 6319428d7b3dSmrg b[2] = ~event; 6320428d7b3dSmrg b[3] = MI_LOAD_REGISTER_IMM | 1; 6321428d7b3dSmrg b[4] = 0x4f100; /* magic */ 6322428d7b3dSmrg b[5] = (1 << 31) | (1 << 30) | pipe << 29 | (y1 << 16) | y2; 6323428d7b3dSmrg b[6] = MI_LOAD_REGISTER_IMM | 1; 6324428d7b3dSmrg b[7] = 0x2050; /* PSMI_CTL(rcs) */ 6325428d7b3dSmrg b[8] = 1 << 16 | 1; 6326428d7b3dSmrg b[9] = MI_WAIT_FOR_EVENT | event; 6327428d7b3dSmrg b[10] = MI_LOAD_REGISTER_IMM | 1; 6328428d7b3dSmrg b[11] = 0x2050; /* PSMI_CTL(rcs) */ 6329428d7b3dSmrg b[12] = 1 << 16; 6330428d7b3dSmrg b[13] = MI_LOAD_REGISTER_IMM | 1; 6331428d7b3dSmrg b[14] = 0x44050; /* DERRMR */ 6332428d7b3dSmrg b[15] = ~0; 6333428d7b3dSmrg 6334428d7b3dSmrg sna->kgem.batch_flags |= I915_EXEC_SECURE; 6335428d7b3dSmrg return true; 6336428d7b3dSmrg} 6337428d7b3dSmrg 6338428d7b3dSmrgstatic bool sna_emit_wait_for_scanline_gen4(struct sna *sna, 6339428d7b3dSmrg xf86CrtcPtr crtc, 6340428d7b3dSmrg int pipe, int y1, int y2, 6341428d7b3dSmrg bool full_height) 6342428d7b3dSmrg{ 6343428d7b3dSmrg uint32_t event; 6344428d7b3dSmrg uint32_t *b; 6345428d7b3dSmrg 6346428d7b3dSmrg if (pipe == 0) { 6347428d7b3dSmrg if (full_height) 6348428d7b3dSmrg event = MI_WAIT_FOR_PIPEA_SVBLANK; 6349428d7b3dSmrg else 6350428d7b3dSmrg event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW; 6351428d7b3dSmrg } else { 6352428d7b3dSmrg if (full_height) 6353428d7b3dSmrg event = MI_WAIT_FOR_PIPEB_SVBLANK; 6354428d7b3dSmrg else 6355428d7b3dSmrg event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW; 6356428d7b3dSmrg } 6357428d7b3dSmrg 6358428d7b3dSmrg b = kgem_get_batch(&sna->kgem); 6359428d7b3dSmrg sna->kgem.nbatch += 5; 6360428d7b3dSmrg 6361428d7b3dSmrg /* The documentation says that the LOAD_SCAN_LINES command 6362428d7b3dSmrg * always comes in pairs. Don't ask me why. */ 6363428d7b3dSmrg b[2] = b[0] = MI_LOAD_SCAN_LINES_INCL | pipe << 20; 6364428d7b3dSmrg b[3] = b[1] = (y1 << 16) | (y2-1); 6365428d7b3dSmrg b[4] = MI_WAIT_FOR_EVENT | event; 6366428d7b3dSmrg 6367428d7b3dSmrg return true; 6368428d7b3dSmrg} 6369428d7b3dSmrg 6370428d7b3dSmrgstatic bool sna_emit_wait_for_scanline_gen2(struct sna *sna, 6371428d7b3dSmrg xf86CrtcPtr crtc, 6372428d7b3dSmrg int pipe, int y1, int y2, 6373428d7b3dSmrg bool full_height) 6374428d7b3dSmrg{ 6375428d7b3dSmrg uint32_t *b; 6376428d7b3dSmrg 6377428d7b3dSmrg /* 6378428d7b3dSmrg * Pre-965 doesn't have SVBLANK, so we need a bit 6379428d7b3dSmrg * of extra time for the blitter to start up and 6380428d7b3dSmrg * do its job for a full height blit 6381428d7b3dSmrg */ 6382428d7b3dSmrg if (full_height) 6383428d7b3dSmrg y2 -= 2; 6384428d7b3dSmrg 6385428d7b3dSmrg b = kgem_get_batch(&sna->kgem); 6386428d7b3dSmrg sna->kgem.nbatch += 5; 6387428d7b3dSmrg 6388428d7b3dSmrg /* The documentation says that the LOAD_SCAN_LINES command 6389428d7b3dSmrg * always comes in pairs. Don't ask me why. */ 6390428d7b3dSmrg b[2] = b[0] = MI_LOAD_SCAN_LINES_INCL | pipe << 20; 6391428d7b3dSmrg b[3] = b[1] = (y1 << 16) | (y2-1); 6392428d7b3dSmrg b[4] = MI_WAIT_FOR_EVENT | 1 << (1 + 4*pipe); 6393428d7b3dSmrg 6394428d7b3dSmrg return true; 6395428d7b3dSmrg} 6396428d7b3dSmrg 6397428d7b3dSmrgbool 6398428d7b3dSmrgsna_wait_for_scanline(struct sna *sna, 6399428d7b3dSmrg PixmapPtr pixmap, 6400428d7b3dSmrg xf86CrtcPtr crtc, 6401428d7b3dSmrg const BoxRec *clip) 6402428d7b3dSmrg{ 6403428d7b3dSmrg bool full_height; 6404428d7b3dSmrg int y1, y2, pipe; 6405428d7b3dSmrg bool ret; 6406428d7b3dSmrg 6407428d7b3dSmrg assert(crtc != NULL); 6408428d7b3dSmrg assert(to_sna_crtc(crtc) != NULL); 6409428d7b3dSmrg assert(to_sna_crtc(crtc)->bo != NULL); 6410428d7b3dSmrg assert(pixmap == sna->front); 6411428d7b3dSmrg 6412428d7b3dSmrg if (sna->flags & SNA_NO_VSYNC) 6413428d7b3dSmrg return false; 6414428d7b3dSmrg 6415428d7b3dSmrg /* 6416428d7b3dSmrg * Make sure we don't wait for a scanline that will 6417428d7b3dSmrg * never occur 6418428d7b3dSmrg */ 6419428d7b3dSmrg y1 = clip->y1 - crtc->bounds.y1; 6420428d7b3dSmrg if (y1 < 0) 6421428d7b3dSmrg y1 = 0; 6422428d7b3dSmrg y2 = clip->y2 - crtc->bounds.y1; 6423428d7b3dSmrg if (y2 > crtc->bounds.y2 - crtc->bounds.y1) 6424428d7b3dSmrg y2 = crtc->bounds.y2 - crtc->bounds.y1; 6425428d7b3dSmrg DBG(("%s: clipped range = %d, %d\n", __FUNCTION__, y1, y2)); 6426428d7b3dSmrg if (y2 <= y1 + 4) 6427428d7b3dSmrg return false; 6428428d7b3dSmrg 6429428d7b3dSmrg full_height = y1 == 0 && y2 == crtc->bounds.y2 - crtc->bounds.y1; 6430428d7b3dSmrg 6431428d7b3dSmrg if (crtc->mode.Flags & V_INTERLACE) { 6432428d7b3dSmrg /* DSL count field lines */ 6433428d7b3dSmrg y1 /= 2; 6434428d7b3dSmrg y2 /= 2; 6435428d7b3dSmrg } 6436428d7b3dSmrg 6437428d7b3dSmrg pipe = sna_crtc_to_pipe(crtc); 6438428d7b3dSmrg DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n", 6439428d7b3dSmrg __FUNCTION__, pipe, y1, y2, full_height)); 6440428d7b3dSmrg 6441428d7b3dSmrg if (sna->kgem.gen >= 0110) 6442428d7b3dSmrg ret = false; 6443428d7b3dSmrg else if (sna->kgem.gen == 0101) 6444428d7b3dSmrg ret = false; /* chv, vsync method unknown */ 6445428d7b3dSmrg else if (sna->kgem.gen >= 075) 6446428d7b3dSmrg ret = sna_emit_wait_for_scanline_hsw(sna, crtc, pipe, y1, y2, full_height); 6447428d7b3dSmrg else if (sna->kgem.gen == 071) 6448428d7b3dSmrg ret = false; /* vlv, vsync method unknown */ 6449428d7b3dSmrg else if (sna->kgem.gen >= 070) 6450428d7b3dSmrg ret = sna_emit_wait_for_scanline_ivb(sna, crtc, pipe, y1, y2, full_height); 6451428d7b3dSmrg else if (sna->kgem.gen >= 060) 6452428d7b3dSmrg ret =sna_emit_wait_for_scanline_gen6(sna, crtc, pipe, y1, y2, full_height); 6453428d7b3dSmrg else if (sna->kgem.gen >= 040) 6454428d7b3dSmrg ret = sna_emit_wait_for_scanline_gen4(sna, crtc, pipe, y1, y2, full_height); 6455428d7b3dSmrg else 6456428d7b3dSmrg ret = sna_emit_wait_for_scanline_gen2(sna, crtc, pipe, y1, y2, full_height); 6457428d7b3dSmrg 6458428d7b3dSmrg return ret; 6459428d7b3dSmrg} 6460428d7b3dSmrg 6461428d7b3dSmrgvoid sna_mode_check(struct sna *sna) 6462428d7b3dSmrg{ 6463428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 6464428d7b3dSmrg int i; 6465428d7b3dSmrg 6466428d7b3dSmrg if (sna->flags & SNA_IS_HOSTED) 6467428d7b3dSmrg return; 6468428d7b3dSmrg 6469428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 6470428d7b3dSmrg 6471428d7b3dSmrg /* Validate CRTC attachments and force consistency upon the kernel */ 6472428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 6473428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 6474428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 6475428d7b3dSmrg struct drm_mode_crtc mode; 6476428d7b3dSmrg uint32_t expected[2]; 6477428d7b3dSmrg 6478428d7b3dSmrg assert(sna_crtc); 6479428d7b3dSmrg 6480428d7b3dSmrg#if XF86_CRTC_VERSION >= 3 6481428d7b3dSmrg assert(sna_crtc->bo == NULL || crtc->active); 6482428d7b3dSmrg#endif 6483428d7b3dSmrg expected[0] = sna_crtc->bo ? fb_id(sna_crtc->bo) : 0; 6484428d7b3dSmrg expected[1] = sna_crtc->flip_bo ? fb_id(sna_crtc->flip_bo) : -1; 6485428d7b3dSmrg 6486428d7b3dSmrg VG_CLEAR(mode); 6487428d7b3dSmrg mode.crtc_id = sna_crtc->id; 6488428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode)) 6489428d7b3dSmrg continue; 6490428d7b3dSmrg 6491428d7b3dSmrg DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=(%d or %d)\n", 6492428d7b3dSmrg __FUNCTION__, 6493428d7b3dSmrg mode.crtc_id, mode.mode_valid, 6494428d7b3dSmrg mode.fb_id, expected[0], expected[1])); 6495428d7b3dSmrg 6496428d7b3dSmrg if (mode.fb_id != expected[0] && mode.fb_id != expected[1]) { 6497428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 6498428d7b3dSmrg "%s: invalid state found on pipe %d, disabling CRTC:%d\n", 6499428d7b3dSmrg __FUNCTION__, sna_crtc->pipe, sna_crtc->id); 6500428d7b3dSmrg sna_crtc_disable(crtc); 6501428d7b3dSmrg } 6502428d7b3dSmrg } 6503428d7b3dSmrg 6504428d7b3dSmrg for (i = 0; i < config->num_output; i++) { 6505428d7b3dSmrg xf86OutputPtr output = config->output[i]; 6506428d7b3dSmrg struct sna_output *sna_output; 6507428d7b3dSmrg 6508428d7b3dSmrg if (output->crtc) 6509428d7b3dSmrg continue; 6510428d7b3dSmrg 6511428d7b3dSmrg sna_output = to_sna_output(output); 6512428d7b3dSmrg if (sna_output == NULL) 6513428d7b3dSmrg continue; 6514428d7b3dSmrg 6515428d7b3dSmrg sna_output->dpms_mode = DPMSModeOff; 6516428d7b3dSmrg } 6517428d7b3dSmrg 6518428d7b3dSmrg update_flush_interval(sna); 6519428d7b3dSmrg} 6520428d7b3dSmrg 6521428d7b3dSmrgstatic bool 6522428d7b3dSmrgsna_crtc_hide_planes(struct sna *sna, struct sna_crtc *crtc) 6523428d7b3dSmrg{ 6524428d7b3dSmrg#define LOCAL_IOCTL_MODE_SETPLANE DRM_IOWR(0xB7, struct local_mode_set_plane) 6525428d7b3dSmrg struct local_mode_set_plane { 6526428d7b3dSmrg uint32_t plane_id; 6527428d7b3dSmrg uint32_t crtc_id; 6528428d7b3dSmrg uint32_t fb_id; /* fb object contains surface format type */ 6529428d7b3dSmrg uint32_t flags; 6530428d7b3dSmrg 6531428d7b3dSmrg /* Signed dest location allows it to be partially off screen */ 6532428d7b3dSmrg int32_t crtc_x, crtc_y; 6533428d7b3dSmrg uint32_t crtc_w, crtc_h; 6534428d7b3dSmrg 6535428d7b3dSmrg /* Source values are 16.16 fixed point */ 6536428d7b3dSmrg uint32_t src_x, src_y; 6537428d7b3dSmrg uint32_t src_h, src_w; 6538428d7b3dSmrg } s; 6539428d7b3dSmrg 6540428d7b3dSmrg if (crtc->primary.id == 0) 6541428d7b3dSmrg return false; 6542428d7b3dSmrg 6543428d7b3dSmrg memset(&s, 0, sizeof(s)); 6544428d7b3dSmrg s.plane_id = crtc->primary.id; 6545428d7b3dSmrg if (drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s)) 6546428d7b3dSmrg return false; 6547428d7b3dSmrg 6548428d7b3dSmrg s.plane_id = crtc->sprite.id; 6549428d7b3dSmrg (void)drmIoctl(sna->kgem.fd, LOCAL_IOCTL_MODE_SETPLANE, &s); 6550428d7b3dSmrg 6551428d7b3dSmrg __sna_crtc_disable(sna, crtc); 6552428d7b3dSmrg return true; 6553428d7b3dSmrg} 6554428d7b3dSmrg 6555428d7b3dSmrgvoid sna_mode_reset(struct sna *sna) 6556428d7b3dSmrg{ 6557428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 6558428d7b3dSmrg int i; 6559428d7b3dSmrg 6560428d7b3dSmrg if (sna->flags & SNA_IS_HOSTED) 6561428d7b3dSmrg return; 6562428d7b3dSmrg 6563428d7b3dSmrg DBG(("%s\n", __FUNCTION__)); 6564428d7b3dSmrg 6565428d7b3dSmrg sna_hide_cursors(sna->scrn); 6566428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) 6567428d7b3dSmrg if (!sna_crtc_hide_planes(sna, to_sna_crtc(config->crtc[i]))) 6568428d7b3dSmrg sna_crtc_disable(config->crtc[i]); 6569428d7b3dSmrg assert(sna->mode.front_active == 0); 6570428d7b3dSmrg 6571428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 6572428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(config->crtc[i]); 6573428d7b3dSmrg 6574428d7b3dSmrg assert(sna_crtc != NULL); 6575428d7b3dSmrg sna_crtc->dpms_mode = -1; 6576428d7b3dSmrg 6577428d7b3dSmrg /* Force the rotation property to be reset on next use */ 6578428d7b3dSmrg rotation_reset(&sna_crtc->primary); 6579428d7b3dSmrg rotation_reset(&sna_crtc->sprite); 6580428d7b3dSmrg } 6581428d7b3dSmrg 6582428d7b3dSmrg /* VT switching, likely to be fbcon so make the backlight usable */ 6583428d7b3dSmrg for (i = 0; i < sna->mode.num_real_output; i++) { 6584428d7b3dSmrg struct sna_output *sna_output = to_sna_output(config->output[i]); 6585428d7b3dSmrg 6586428d7b3dSmrg assert(sna_output != NULL); 6587428d7b3dSmrg if (sna_output->dpms_mode != DPMSModeOff) 6588428d7b3dSmrg continue; 6589428d7b3dSmrg 6590428d7b3dSmrg if (!sna_output->backlight.iface) 6591428d7b3dSmrg continue; 6592428d7b3dSmrg 6593428d7b3dSmrg sna_output_backlight_set(sna_output, 6594428d7b3dSmrg sna_output->backlight_active_level); 6595428d7b3dSmrg } 6596428d7b3dSmrg 6597428d7b3dSmrg /* drain the event queue */ 6598428d7b3dSmrg sna_mode_wakeup(sna); 6599428d7b3dSmrg} 6600428d7b3dSmrg 6601428d7b3dSmrgstatic void transformed_box(BoxRec *box, xf86CrtcPtr crtc) 6602428d7b3dSmrg{ 6603428d7b3dSmrg box->x1 -= crtc->filter_width >> 1; 6604428d7b3dSmrg box->x2 += crtc->filter_width >> 1; 6605428d7b3dSmrg box->y1 -= crtc->filter_height >> 1; 6606428d7b3dSmrg box->y2 += crtc->filter_height >> 1; 6607428d7b3dSmrg 6608428d7b3dSmrg pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, box); 6609428d7b3dSmrg 6610428d7b3dSmrg if (box->x1 < 0) 6611428d7b3dSmrg box->x1 = 0; 6612428d7b3dSmrg if (box->y1 < 0) 6613428d7b3dSmrg box->y1 = 0; 6614428d7b3dSmrg if (box->x2 > crtc->mode.HDisplay) 6615428d7b3dSmrg box->x2 = crtc->mode.HDisplay; 6616428d7b3dSmrg if (box->y2 > crtc->mode.VDisplay) 6617428d7b3dSmrg box->y2 = crtc->mode.VDisplay; 6618428d7b3dSmrg} 6619428d7b3dSmrg 6620428d7b3dSmrginline static DrawablePtr crtc_source(xf86CrtcPtr crtc, int16_t *sx, int16_t *sy) 6621428d7b3dSmrg{ 6622428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 6623428d7b3dSmrg if (sna_crtc->slave_pixmap) { 6624428d7b3dSmrg DBG(("%s: using slave pixmap=%ld, offset (%d, %d)\n", 6625428d7b3dSmrg __FUNCTION__, 6626428d7b3dSmrg sna_crtc->slave_pixmap->drawable.serialNumber, 6627428d7b3dSmrg -crtc->x, -crtc->y)); 6628428d7b3dSmrg *sx = -crtc->x; 6629428d7b3dSmrg *sy = -crtc->y; 6630428d7b3dSmrg return &sna_crtc->slave_pixmap->drawable; 6631428d7b3dSmrg } else { 6632428d7b3dSmrg DBG(("%s: using Screen pixmap=%ld\n", 6633428d7b3dSmrg __FUNCTION__, 6634428d7b3dSmrg to_sna(crtc->scrn)->front->drawable.serialNumber)); 6635428d7b3dSmrg *sx = *sy = 0; 6636428d7b3dSmrg return &to_sna(crtc->scrn)->front->drawable; 6637428d7b3dSmrg } 6638428d7b3dSmrg} 6639428d7b3dSmrg 6640428d7b3dSmrgstatic void 6641428d7b3dSmrgsna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo) 6642428d7b3dSmrg{ 6643428d7b3dSmrg int16_t sx, sy; 6644428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 6645428d7b3dSmrg ScreenPtr screen = sna->scrn->pScreen; 6646428d7b3dSmrg DrawablePtr draw = crtc_source(crtc, &sx, &sy); 6647428d7b3dSmrg PictFormatPtr format; 6648428d7b3dSmrg PicturePtr src, dst; 6649428d7b3dSmrg PixmapPtr pixmap; 6650428d7b3dSmrg int depth, error; 6651428d7b3dSmrg void *ptr; 6652428d7b3dSmrg 6653428d7b3dSmrg DBG(("%s: compositing transformed damage boxes, target handle=%d\n", __FUNCTION__, bo->handle)); 6654428d7b3dSmrg 6655428d7b3dSmrg error = sna_render_format_for_depth(draw->depth); 6656428d7b3dSmrg depth = PIXMAN_FORMAT_DEPTH(error); 6657428d7b3dSmrg format = PictureMatchFormat(screen, depth, error); 6658428d7b3dSmrg if (format == NULL) { 6659428d7b3dSmrg DBG(("%s: can't find format for depth=%d [%08x]\n", 6660428d7b3dSmrg __FUNCTION__, depth, error)); 6661428d7b3dSmrg return; 6662428d7b3dSmrg } 6663428d7b3dSmrg 6664428d7b3dSmrg DBG(("%s: dst format=%08x, depth=%d, bpp=%d, pitch=%d, size=%dx%d\n", 6665428d7b3dSmrg __FUNCTION__, format->format, depth, draw->bitsPerPixel, 6666428d7b3dSmrg bo->pitch, crtc->mode.HDisplay, crtc->mode.VDisplay)); 6667428d7b3dSmrg 6668428d7b3dSmrg ptr = kgem_bo_map__gtt(&sna->kgem, bo); 6669428d7b3dSmrg if (ptr == NULL) 6670428d7b3dSmrg return; 6671428d7b3dSmrg 6672428d7b3dSmrg pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 6673428d7b3dSmrg if (pixmap == NullPixmap) 6674428d7b3dSmrg return; 6675428d7b3dSmrg 6676428d7b3dSmrg if (!screen->ModifyPixmapHeader(pixmap, 6677428d7b3dSmrg crtc->mode.HDisplay, crtc->mode.VDisplay, 6678428d7b3dSmrg depth, draw->bitsPerPixel, 6679428d7b3dSmrg bo->pitch, ptr)) 6680428d7b3dSmrg goto free_pixmap; 6681428d7b3dSmrg 6682428d7b3dSmrg src = CreatePicture(None, draw, format, 6683428d7b3dSmrg 0, NULL, serverClient, &error); 6684428d7b3dSmrg if (!src) 6685428d7b3dSmrg goto free_pixmap; 6686428d7b3dSmrg 6687428d7b3dSmrg error = SetPictureTransform(src, &crtc->crtc_to_framebuffer); 6688428d7b3dSmrg if (error) 6689428d7b3dSmrg goto free_src; 6690428d7b3dSmrg 6691428d7b3dSmrg if (crtc->filter && crtc->transform_in_use) 6692428d7b3dSmrg SetPicturePictFilter(src, crtc->filter, 6693428d7b3dSmrg crtc->params, crtc->nparams); 6694428d7b3dSmrg 6695428d7b3dSmrg dst = CreatePicture(None, &pixmap->drawable, format, 6696428d7b3dSmrg 0, NULL, serverClient, &error); 6697428d7b3dSmrg if (!dst) 6698428d7b3dSmrg goto free_src; 6699428d7b3dSmrg 6700428d7b3dSmrg kgem_bo_sync__gtt(&sna->kgem, bo); 6701428d7b3dSmrg 6702428d7b3dSmrg if (sigtrap_get() == 0) { /* paranoia */ 6703428d7b3dSmrg const BoxRec *b = region_rects(region); 6704428d7b3dSmrg int n = region_num_rects(region); 6705428d7b3dSmrg do { 6706428d7b3dSmrg BoxRec box; 6707428d7b3dSmrg 6708428d7b3dSmrg box = *b++; 6709428d7b3dSmrg transformed_box(&box, crtc); 6710428d7b3dSmrg 6711428d7b3dSmrg DBG(("%s: (%d, %d)x(%d, %d) -> (%d, %d), (%d, %d)\n", 6712428d7b3dSmrg __FUNCTION__, 6713428d7b3dSmrg b[-1].x1, b[-1].y1, b[-1].x2-b[-1].x1, b[-1].y2-b[-1].y1, 6714428d7b3dSmrg box.x1, box.y1, box.x2, box.y2)); 6715428d7b3dSmrg 6716428d7b3dSmrg fbComposite(PictOpSrc, src, NULL, dst, 6717428d7b3dSmrg box.x1 + sx, box.y1 + sy, 6718428d7b3dSmrg 0, 0, 6719428d7b3dSmrg box.x1, box.y1, 6720428d7b3dSmrg box.x2 - box.x1, box.y2 - box.y1); 6721428d7b3dSmrg } while (--n); 6722428d7b3dSmrg sigtrap_put(); 6723428d7b3dSmrg } 6724428d7b3dSmrg 6725428d7b3dSmrg FreePicture(dst, None); 6726428d7b3dSmrgfree_src: 6727428d7b3dSmrg FreePicture(src, None); 6728428d7b3dSmrgfree_pixmap: 6729428d7b3dSmrg screen->DestroyPixmap(pixmap); 6730428d7b3dSmrg} 6731428d7b3dSmrg 6732428d7b3dSmrgstatic void 6733428d7b3dSmrgsna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo) 6734428d7b3dSmrg{ 6735428d7b3dSmrg int16_t sx, sy; 6736428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 6737428d7b3dSmrg ScreenPtr screen = crtc->scrn->pScreen; 6738428d7b3dSmrg DrawablePtr draw = crtc_source(crtc, &sx, &sy); 6739428d7b3dSmrg struct sna_composite_op tmp; 6740428d7b3dSmrg PictFormatPtr format; 6741428d7b3dSmrg PicturePtr src, dst; 6742428d7b3dSmrg PixmapPtr pixmap; 6743428d7b3dSmrg const BoxRec *b; 6744428d7b3dSmrg int n, depth, error; 6745428d7b3dSmrg 6746428d7b3dSmrg DBG(("%s: compositing transformed damage boxes\n", __FUNCTION__)); 6747428d7b3dSmrg 6748428d7b3dSmrg error = sna_render_format_for_depth(draw->depth); 6749428d7b3dSmrg depth = PIXMAN_FORMAT_DEPTH(error); 6750428d7b3dSmrg format = PictureMatchFormat(screen, depth, error); 6751428d7b3dSmrg if (format == NULL) { 6752428d7b3dSmrg DBG(("%s: can't find format for depth=%d [%08x]\n", 6753428d7b3dSmrg __FUNCTION__, depth, error)); 6754428d7b3dSmrg return; 6755428d7b3dSmrg } 6756428d7b3dSmrg 6757428d7b3dSmrg DBG(("%s: dst format=%08x, depth=%d, bpp=%d, pitch=%d, size=%dx%d\n", 6758428d7b3dSmrg __FUNCTION__, format->format, depth, draw->bitsPerPixel, 6759428d7b3dSmrg bo->pitch, crtc->mode.HDisplay, crtc->mode.VDisplay)); 6760428d7b3dSmrg 6761428d7b3dSmrg pixmap = sna_pixmap_create_unattached(screen, 0, 0, depth); 6762428d7b3dSmrg if (pixmap == NullPixmap) 6763428d7b3dSmrg return; 6764428d7b3dSmrg 6765428d7b3dSmrg if (!screen->ModifyPixmapHeader(pixmap, 6766428d7b3dSmrg crtc->mode.HDisplay, crtc->mode.VDisplay, 6767428d7b3dSmrg depth, draw->bitsPerPixel, 6768428d7b3dSmrg bo->pitch, NULL)) 6769428d7b3dSmrg goto free_pixmap; 6770428d7b3dSmrg 6771428d7b3dSmrg if (!sna_pixmap_attach_to_bo(pixmap, kgem_bo_reference(bo))) { 6772428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 6773428d7b3dSmrg goto free_pixmap; 6774428d7b3dSmrg } 6775428d7b3dSmrg 6776428d7b3dSmrg src = CreatePicture(None, draw, format, 6777428d7b3dSmrg 0, NULL, serverClient, &error); 6778428d7b3dSmrg if (!src) 6779428d7b3dSmrg goto free_pixmap; 6780428d7b3dSmrg 6781428d7b3dSmrg error = SetPictureTransform(src, &crtc->crtc_to_framebuffer); 6782428d7b3dSmrg if (error) 6783428d7b3dSmrg goto free_src; 6784428d7b3dSmrg 6785428d7b3dSmrg if (crtc->filter && crtc->transform_in_use) 6786428d7b3dSmrg SetPicturePictFilter(src, crtc->filter, 6787428d7b3dSmrg crtc->params, crtc->nparams); 6788428d7b3dSmrg 6789428d7b3dSmrg dst = CreatePicture(None, &pixmap->drawable, format, 6790428d7b3dSmrg 0, NULL, serverClient, &error); 6791428d7b3dSmrg if (!dst) 6792428d7b3dSmrg goto free_src; 6793428d7b3dSmrg 6794428d7b3dSmrg ValidatePicture(src); 6795428d7b3dSmrg ValidatePicture(dst); 6796428d7b3dSmrg 6797428d7b3dSmrg if (!sna->render.composite(sna, 6798428d7b3dSmrg PictOpSrc, src, NULL, dst, 6799428d7b3dSmrg sx, sy, 6800428d7b3dSmrg 0, 0, 6801428d7b3dSmrg 0, 0, 6802428d7b3dSmrg crtc->mode.HDisplay, crtc->mode.VDisplay, 6803428d7b3dSmrg COMPOSITE_PARTIAL, memset(&tmp, 0, sizeof(tmp)))) { 6804428d7b3dSmrg DBG(("%s: unsupported operation!\n", __FUNCTION__)); 6805428d7b3dSmrg sna_crtc_redisplay__fallback(crtc, region, bo); 6806428d7b3dSmrg goto free_dst; 6807428d7b3dSmrg } 6808428d7b3dSmrg 6809428d7b3dSmrg n = region_num_rects(region); 6810428d7b3dSmrg b = region_rects(region); 6811428d7b3dSmrg do { 6812428d7b3dSmrg BoxRec box; 6813428d7b3dSmrg 6814428d7b3dSmrg box = *b++; 6815428d7b3dSmrg transformed_box(&box, crtc); 6816428d7b3dSmrg 6817428d7b3dSmrg DBG(("%s: (%d, %d)x(%d, %d) -> (%d, %d), (%d, %d)\n", 6818428d7b3dSmrg __FUNCTION__, 6819428d7b3dSmrg b[-1].x1, b[-1].y1, b[-1].x2-b[-1].x1, b[-1].y2-b[-1].y1, 6820428d7b3dSmrg box.x1, box.y1, box.x2, box.y2)); 6821428d7b3dSmrg 6822428d7b3dSmrg tmp.box(sna, &tmp, &box); 6823428d7b3dSmrg } while (--n); 6824428d7b3dSmrg tmp.done(sna, &tmp); 6825428d7b3dSmrg 6826428d7b3dSmrgfree_dst: 6827428d7b3dSmrg FreePicture(dst, None); 6828428d7b3dSmrgfree_src: 6829428d7b3dSmrg FreePicture(src, None); 6830428d7b3dSmrgfree_pixmap: 6831428d7b3dSmrg screen->DestroyPixmap(pixmap); 6832428d7b3dSmrg} 6833428d7b3dSmrg 6834428d7b3dSmrgstatic void 6835428d7b3dSmrgsna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo) 6836428d7b3dSmrg{ 6837428d7b3dSmrg int16_t tx, ty, sx, sy; 6838428d7b3dSmrg struct sna *sna = to_sna(crtc->scrn); 6839428d7b3dSmrg DrawablePtr draw = crtc_source(crtc, &sx, &sy); 6840428d7b3dSmrg struct sna_pixmap *priv = sna_pixmap((PixmapPtr)draw); 6841428d7b3dSmrg 6842428d7b3dSmrg DBG(("%s: crtc %d [pipe=%d], damage (%d, %d), (%d, %d) x %d\n", 6843428d7b3dSmrg __FUNCTION__, to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe, 6844428d7b3dSmrg region->extents.x1, region->extents.y1, 6845428d7b3dSmrg region->extents.x2, region->extents.y2, 6846428d7b3dSmrg region_num_rects(region))); 6847428d7b3dSmrg 6848428d7b3dSmrg assert(!wedged(sna)); 6849428d7b3dSmrg 6850428d7b3dSmrg if (priv->clear) { 6851428d7b3dSmrg RegionRec whole; 6852428d7b3dSmrg 6853428d7b3dSmrg DBG(("%s: clear damage boxes\n", __FUNCTION__)); 6854428d7b3dSmrg 6855428d7b3dSmrg if (sna_transform_is_integer_translation(&crtc->crtc_to_framebuffer, 6856428d7b3dSmrg &tx, &ty)) { 6857428d7b3dSmrg RegionTranslate(region, -tx, -ty); 6858428d7b3dSmrg } else { 6859428d7b3dSmrg whole.extents = region->extents; 6860428d7b3dSmrg whole.data = NULL; 6861428d7b3dSmrg transformed_box(&whole.extents, crtc); 6862428d7b3dSmrg region = &whole; 6863428d7b3dSmrg } 6864428d7b3dSmrg if (sna_blt_fill_boxes(sna, GXcopy, 6865428d7b3dSmrg bo, draw->bitsPerPixel, 6866428d7b3dSmrg priv->clear_color, 6867428d7b3dSmrg region_rects(region), 6868428d7b3dSmrg region_num_rects(region))) 6869428d7b3dSmrg return; 6870428d7b3dSmrg } 6871428d7b3dSmrg 6872428d7b3dSmrg if (crtc->filter == NULL && 6873428d7b3dSmrg priv->gpu_bo && 6874428d7b3dSmrg priv->cpu_damage == NULL && 6875428d7b3dSmrg sna_transform_is_integer_translation(&crtc->crtc_to_framebuffer, 6876428d7b3dSmrg &tx, &ty)) { 6877428d7b3dSmrg DrawableRec tmp; 6878428d7b3dSmrg 6879428d7b3dSmrg DBG(("%s: copy damage boxes\n", __FUNCTION__)); 6880428d7b3dSmrg 6881428d7b3dSmrg tmp.width = crtc->mode.HDisplay; 6882428d7b3dSmrg tmp.height = crtc->mode.VDisplay; 6883428d7b3dSmrg tmp.depth = sna->front->drawable.depth; 6884428d7b3dSmrg tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel; 6885428d7b3dSmrg 6886428d7b3dSmrg if (sna->render.copy_boxes(sna, GXcopy, 6887428d7b3dSmrg draw, priv->gpu_bo, sx, sy, 6888428d7b3dSmrg &tmp, bo, -tx, -ty, 6889428d7b3dSmrg region_rects(region), region_num_rects(region), 0)) 6890428d7b3dSmrg return; 6891428d7b3dSmrg } 6892428d7b3dSmrg 6893428d7b3dSmrg if (can_render(sna)) 6894428d7b3dSmrg sna_crtc_redisplay__composite(crtc, region, bo); 6895428d7b3dSmrg else 6896428d7b3dSmrg sna_crtc_redisplay__fallback(crtc, region, bo); 6897428d7b3dSmrg} 6898428d7b3dSmrg 6899428d7b3dSmrgstatic void shadow_flip_handler(struct drm_event_vblank *e, 6900428d7b3dSmrg void *data) 6901428d7b3dSmrg{ 6902428d7b3dSmrg sna_mode_redisplay(data); 6903428d7b3dSmrg} 6904428d7b3dSmrg 6905428d7b3dSmrgvoid sna_shadow_set_crtc(struct sna *sna, 6906428d7b3dSmrg xf86CrtcPtr crtc, 6907428d7b3dSmrg struct kgem_bo *bo) 6908428d7b3dSmrg{ 6909428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 6910428d7b3dSmrg struct sna_pixmap *priv; 6911428d7b3dSmrg 6912428d7b3dSmrg DBG(("%s: setting shadow override for CRTC:%d to handle=%d\n", 6913428d7b3dSmrg __FUNCTION__, sna_crtc->id, bo->handle)); 6914428d7b3dSmrg 6915428d7b3dSmrg assert(sna->flags & SNA_TEAR_FREE); 6916428d7b3dSmrg assert(sna_crtc); 6917428d7b3dSmrg assert(!sna_crtc->transform); 6918428d7b3dSmrg 6919428d7b3dSmrg if (sna_crtc->client_bo != bo) { 6920428d7b3dSmrg if (sna_crtc->client_bo) 6921428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo); 6922428d7b3dSmrg 6923428d7b3dSmrg sna_crtc->client_bo = kgem_bo_reference(bo); 6924428d7b3dSmrg sna_crtc_damage(crtc); 6925428d7b3dSmrg } 6926428d7b3dSmrg 6927428d7b3dSmrg list_move(&sna_crtc->shadow_link, &sna->mode.shadow_crtc); 6928428d7b3dSmrg sna->mode.shadow_dirty = true; 6929428d7b3dSmrg 6930428d7b3dSmrg priv = sna_pixmap(sna->front); 6931428d7b3dSmrg assert(priv->gpu_bo); 6932428d7b3dSmrg priv->move_to_gpu = wait_for_shadow; 6933428d7b3dSmrg priv->move_to_gpu_data = sna; 6934428d7b3dSmrg} 6935428d7b3dSmrg 6936428d7b3dSmrgvoid sna_shadow_steal_crtcs(struct sna *sna, struct list *list) 6937428d7b3dSmrg{ 6938428d7b3dSmrg list_init(list); 6939428d7b3dSmrg while (!list_is_empty(&sna->mode.shadow_crtc)) { 6940428d7b3dSmrg RegionRec sub, *damage; 6941428d7b3dSmrg struct sna_crtc *crtc = 6942428d7b3dSmrg list_first_entry(&sna->mode.shadow_crtc, 6943428d7b3dSmrg struct sna_crtc, 6944428d7b3dSmrg shadow_link); 6945428d7b3dSmrg 6946428d7b3dSmrg damage = DamageRegion(sna->mode.shadow_damage); 6947428d7b3dSmrg sub.extents = crtc->base->bounds; 6948428d7b3dSmrg sub.data = NULL; 6949428d7b3dSmrg RegionSubtract(damage, damage, &sub); 6950428d7b3dSmrg 6951428d7b3dSmrg list_move(&crtc->shadow_link, list); 6952428d7b3dSmrg } 6953428d7b3dSmrg} 6954428d7b3dSmrg 6955428d7b3dSmrgvoid sna_shadow_unsteal_crtcs(struct sna *sna, struct list *list) 6956428d7b3dSmrg{ 6957428d7b3dSmrg while (!list_is_empty(list)) { 6958428d7b3dSmrg struct sna_crtc *crtc = 6959428d7b3dSmrg list_first_entry(list, 6960428d7b3dSmrg struct sna_crtc, 6961428d7b3dSmrg shadow_link); 6962428d7b3dSmrg assert(crtc->client_bo); 6963428d7b3dSmrg sna_shadow_set_crtc(sna, crtc->base, crtc->client_bo); 6964428d7b3dSmrg } 6965428d7b3dSmrg} 6966428d7b3dSmrg 6967428d7b3dSmrgvoid sna_shadow_unset_crtc(struct sna *sna, 6968428d7b3dSmrg xf86CrtcPtr crtc) 6969428d7b3dSmrg{ 6970428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 6971428d7b3dSmrg 6972428d7b3dSmrg DBG(("%s: clearin shadow override for CRTC:%d\n", 6973428d7b3dSmrg __FUNCTION__, sna_crtc->id)); 6974428d7b3dSmrg 6975428d7b3dSmrg if (sna_crtc->client_bo == NULL) 6976428d7b3dSmrg return; 6977428d7b3dSmrg 6978428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna_crtc->client_bo); 6979428d7b3dSmrg sna_crtc->client_bo = NULL; 6980428d7b3dSmrg list_del(&sna_crtc->shadow_link); 6981428d7b3dSmrg sna->mode.shadow_dirty = true; 6982428d7b3dSmrg 6983428d7b3dSmrg sna_crtc_damage(crtc); 6984428d7b3dSmrg} 6985428d7b3dSmrg 6986428d7b3dSmrgvoid sna_mode_redisplay(struct sna *sna) 6987428d7b3dSmrg{ 6988428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); 6989428d7b3dSmrg RegionPtr region; 6990428d7b3dSmrg int i; 6991428d7b3dSmrg 6992428d7b3dSmrg if (!sna->mode.shadow_damage) 6993428d7b3dSmrg return; 6994428d7b3dSmrg 6995428d7b3dSmrg DBG(("%s: posting shadow damage? %d (flips pending? %d, mode reconfiguration pending? %d)\n", 6996428d7b3dSmrg __FUNCTION__, 6997428d7b3dSmrg !RegionNil(DamageRegion(sna->mode.shadow_damage)), 6998428d7b3dSmrg sna->mode.flip_active, 6999428d7b3dSmrg sna->mode.dirty)); 7000428d7b3dSmrg assert((sna->flags & SNA_IS_HOSTED) == 0); 7001428d7b3dSmrg assert(sna->mode.shadow_active); 7002428d7b3dSmrg 7003428d7b3dSmrg if (sna->mode.dirty) 7004428d7b3dSmrg return; 7005428d7b3dSmrg 7006428d7b3dSmrg region = DamageRegion(sna->mode.shadow_damage); 7007428d7b3dSmrg if (RegionNil(region)) 7008428d7b3dSmrg return; 7009428d7b3dSmrg 7010428d7b3dSmrg DBG(("%s: damage: %dx(%d, %d), (%d, %d)\n", 7011428d7b3dSmrg __FUNCTION__, region_num_rects(region), 7012428d7b3dSmrg region->extents.x1, region->extents.y1, 7013428d7b3dSmrg region->extents.x2, region->extents.y2)); 7014428d7b3dSmrg 7015428d7b3dSmrg if (sna->mode.flip_active) { 7016428d7b3dSmrg DamagePtr damage; 7017428d7b3dSmrg 7018428d7b3dSmrg damage = sna->mode.shadow_damage; 7019428d7b3dSmrg sna->mode.shadow_damage = NULL; 7020428d7b3dSmrg 7021428d7b3dSmrg while (sna->mode.flip_active && sna_mode_wakeup(sna)) 7022428d7b3dSmrg ; 7023428d7b3dSmrg 7024428d7b3dSmrg sna->mode.shadow_damage = damage; 7025428d7b3dSmrg } 7026428d7b3dSmrg 7027428d7b3dSmrg if (sna->mode.flip_active) 7028428d7b3dSmrg return; 7029428d7b3dSmrg 7030428d7b3dSmrg if (wedged(sna) || !sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) { 7031428d7b3dSmrg DBG(("%s: forcing scanout update using the CPU\n", __FUNCTION__)); 7032428d7b3dSmrg if (!sna_pixmap_move_to_cpu(sna->front, MOVE_READ)) 7033428d7b3dSmrg return; 7034428d7b3dSmrg 7035428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 7036428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 7037428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 7038428d7b3dSmrg RegionRec damage; 7039428d7b3dSmrg 7040428d7b3dSmrg assert(sna_crtc != NULL); 7041428d7b3dSmrg if (!sna_crtc->shadow) 7042428d7b3dSmrg continue; 7043428d7b3dSmrg 7044428d7b3dSmrg assert(crtc->enabled); 7045428d7b3dSmrg assert(sna_crtc->transform || sna->flags & SNA_TEAR_FREE); 7046428d7b3dSmrg 7047428d7b3dSmrg damage.extents = crtc->bounds; 7048428d7b3dSmrg damage.data = NULL; 7049428d7b3dSmrg RegionIntersect(&damage, &damage, region); 7050428d7b3dSmrg if (!box_empty(&damage.extents)) { 7051428d7b3dSmrg struct kgem_bo *bo = NULL; 7052428d7b3dSmrg 7053428d7b3dSmrg DBG(("%s: fallback intersects pipe=%d [(%d, %d), (%d, %d)]\n", 7054428d7b3dSmrg __FUNCTION__, sna_crtc->pipe, 7055428d7b3dSmrg damage.extents.x1, damage.extents.y1, 7056428d7b3dSmrg damage.extents.x2, damage.extents.y2)); 7057428d7b3dSmrg 7058428d7b3dSmrg if (sna->flags & SNA_TEAR_FREE) { 7059428d7b3dSmrg RegionRec new_damage; 7060428d7b3dSmrg 7061428d7b3dSmrg RegionNull(&new_damage); 7062428d7b3dSmrg RegionCopy(&new_damage, &damage); 7063428d7b3dSmrg 7064428d7b3dSmrg bo = sna_crtc->client_bo; 7065428d7b3dSmrg if (bo == NULL) { 7066428d7b3dSmrg damage.extents = crtc->bounds; 7067428d7b3dSmrg damage.data = NULL; 7068428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 7069428d7b3dSmrg crtc->mode.HDisplay, 7070428d7b3dSmrg crtc->mode.VDisplay, 7071428d7b3dSmrg crtc->scrn->bitsPerPixel, 7072428d7b3dSmrg sna_crtc->bo->tiling, 7073428d7b3dSmrg CREATE_SCANOUT); 7074428d7b3dSmrg } else 7075428d7b3dSmrg RegionUnion(&damage, &damage, &sna_crtc->client_damage); 7076428d7b3dSmrg 7077428d7b3dSmrg DBG(("%s: TearFree fallback, shadow handle=%d, crtc handle=%d\n", __FUNCTION__, bo->handle, sna_crtc->bo->handle)); 7078428d7b3dSmrg 7079428d7b3dSmrg sna_crtc->client_damage = new_damage; 7080428d7b3dSmrg } 7081428d7b3dSmrg 7082428d7b3dSmrg if (bo == NULL) 7083428d7b3dSmrg bo = sna_crtc->bo; 7084428d7b3dSmrg sna_crtc_redisplay__fallback(crtc, &damage, bo); 7085428d7b3dSmrg 7086428d7b3dSmrg if (bo != sna_crtc->bo) { 7087428d7b3dSmrg struct drm_mode_crtc_page_flip arg; 7088428d7b3dSmrg 7089428d7b3dSmrg arg.crtc_id = sna_crtc->id; 7090428d7b3dSmrg arg.fb_id = get_fb(sna, bo, 7091428d7b3dSmrg crtc->mode.HDisplay, 7092428d7b3dSmrg crtc->mode.VDisplay); 7093428d7b3dSmrg 7094428d7b3dSmrg arg.user_data = (uintptr_t)sna_crtc; 7095428d7b3dSmrg arg.flags = DRM_MODE_PAGE_FLIP_EVENT; 7096428d7b3dSmrg arg.reserved = 0; 7097428d7b3dSmrg 7098428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) { 7099428d7b3dSmrg if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) { 7100428d7b3dSmrg assert(sna_crtc->bo->active_scanout); 7101428d7b3dSmrg assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout); 7102428d7b3dSmrg sna_crtc->bo->active_scanout--; 7103428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna_crtc->bo); 7104428d7b3dSmrg 7105428d7b3dSmrg sna_crtc->bo = bo; 7106428d7b3dSmrg sna_crtc->bo->active_scanout++; 7107428d7b3dSmrg sna_crtc->client_bo = NULL; 7108428d7b3dSmrg } else { 7109428d7b3dSmrg DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n", 7110428d7b3dSmrg __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno)); 7111428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 7112428d7b3dSmrg "Page flipping failed, disabling TearFree\n"); 7113428d7b3dSmrg sna->flags &= ~SNA_TEAR_FREE; 7114428d7b3dSmrg 7115428d7b3dSmrg damage.extents = crtc->bounds; 7116428d7b3dSmrg damage.data = NULL; 7117428d7b3dSmrg sna_crtc_redisplay__fallback(crtc, &damage, sna_crtc->bo); 7118428d7b3dSmrg 7119428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 7120428d7b3dSmrg sna_crtc->client_bo = NULL; 7121428d7b3dSmrg } 7122428d7b3dSmrg } else { 7123428d7b3dSmrg sna->mode.flip_active++; 7124428d7b3dSmrg 7125428d7b3dSmrg assert(sna_crtc->flip_bo == NULL); 7126428d7b3dSmrg sna_crtc->flip_handler = shadow_flip_handler; 7127428d7b3dSmrg sna_crtc->flip_data = sna; 7128428d7b3dSmrg sna_crtc->flip_bo = bo; 7129428d7b3dSmrg sna_crtc->flip_bo->active_scanout++; 7130428d7b3dSmrg sna_crtc->flip_serial = sna_crtc->mode_serial; 7131428d7b3dSmrg 7132428d7b3dSmrg sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo); 7133428d7b3dSmrg } 7134428d7b3dSmrg } 7135428d7b3dSmrg } 7136428d7b3dSmrg RegionUninit(&damage); 7137428d7b3dSmrg 7138428d7b3dSmrg if (sna_crtc->slave_damage) 7139428d7b3dSmrg DamageEmpty(sna_crtc->slave_damage); 7140428d7b3dSmrg } 7141428d7b3dSmrg 7142428d7b3dSmrg RegionEmpty(region); 7143428d7b3dSmrg return; 7144428d7b3dSmrg } 7145428d7b3dSmrg 7146428d7b3dSmrg { 7147428d7b3dSmrg struct sna_pixmap *priv; 7148428d7b3dSmrg 7149428d7b3dSmrg priv = sna_pixmap(sna->front); 7150428d7b3dSmrg assert(priv != NULL); 7151428d7b3dSmrg 7152428d7b3dSmrg if (priv->move_to_gpu) { 7153428d7b3dSmrg if (priv->move_to_gpu == wait_for_shadow && 7154428d7b3dSmrg !sna->mode.shadow_dirty) { 7155428d7b3dSmrg /* No damage written to new scanout 7156428d7b3dSmrg * (backbuffer), ignore redisplay request 7157428d7b3dSmrg * and continue with the current intact 7158428d7b3dSmrg * scanout (frontbuffer). 7159428d7b3dSmrg */ 7160428d7b3dSmrg DBG(("%s: shadow idle, skipping update\n", __FUNCTION__)); 7161428d7b3dSmrg RegionEmpty(region); 7162428d7b3dSmrg return; 7163428d7b3dSmrg } 7164428d7b3dSmrg 7165428d7b3dSmrg (void)priv->move_to_gpu(sna, priv, 0); 7166428d7b3dSmrg } 7167428d7b3dSmrg 7168428d7b3dSmrg assert(priv->move_to_gpu == NULL); 7169428d7b3dSmrg } 7170428d7b3dSmrg 7171428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 7172428d7b3dSmrg xf86CrtcPtr crtc = config->crtc[i]; 7173428d7b3dSmrg struct sna_crtc *sna_crtc = to_sna_crtc(crtc); 7174428d7b3dSmrg RegionRec damage; 7175428d7b3dSmrg 7176428d7b3dSmrg assert(sna_crtc != NULL); 7177428d7b3dSmrg DBG(("%s: crtc[%d] transformed? %d\n", 7178428d7b3dSmrg __FUNCTION__, i, sna_crtc->transform)); 7179428d7b3dSmrg 7180428d7b3dSmrg if (!sna_crtc->transform) 7181428d7b3dSmrg continue; 7182428d7b3dSmrg 7183428d7b3dSmrg assert(crtc->enabled); 7184428d7b3dSmrg assert(sna_crtc->bo); 7185428d7b3dSmrg 7186428d7b3dSmrg damage.extents = crtc->bounds; 7187428d7b3dSmrg damage.data = NULL; 7188428d7b3dSmrg 7189428d7b3dSmrg RegionIntersect(&damage, &damage, region); 7190428d7b3dSmrg DBG(("%s: crtc[%d] damage? %d[%d]: %dx[(%d, %d), (%d, %d)]\n", 7191428d7b3dSmrg __FUNCTION__, i, 7192428d7b3dSmrg !box_empty(&damage.extents), RegionNotEmpty(&damage), 7193428d7b3dSmrg region_num_rects(&damage), 7194428d7b3dSmrg damage.extents.x1, damage.extents.y1, 7195428d7b3dSmrg damage.extents.x2, damage.extents.y2)); 7196428d7b3dSmrg if (!box_empty(&damage.extents)) { 7197428d7b3dSmrg if (sna->flags & SNA_TEAR_FREE) { 7198428d7b3dSmrg struct drm_mode_crtc_page_flip arg; 7199428d7b3dSmrg struct kgem_bo *bo; 7200428d7b3dSmrg 7201428d7b3dSmrg RegionUninit(&damage); 7202428d7b3dSmrg damage.extents = crtc->bounds; 7203428d7b3dSmrg damage.data = NULL; 7204428d7b3dSmrg 7205428d7b3dSmrg bo = sna_crtc->client_bo; 7206428d7b3dSmrg if (bo == NULL) 7207428d7b3dSmrg bo = kgem_create_2d(&sna->kgem, 7208428d7b3dSmrg crtc->mode.HDisplay, 7209428d7b3dSmrg crtc->mode.VDisplay, 7210428d7b3dSmrg crtc->scrn->bitsPerPixel, 7211428d7b3dSmrg sna_crtc->bo->tiling, 7212428d7b3dSmrg CREATE_SCANOUT); 7213428d7b3dSmrg if (bo == NULL) 7214428d7b3dSmrg goto disable1; 7215428d7b3dSmrg 7216428d7b3dSmrg sna_crtc_redisplay(crtc, &damage, bo); 7217428d7b3dSmrg kgem_bo_submit(&sna->kgem, bo); 7218428d7b3dSmrg 7219428d7b3dSmrg arg.crtc_id = sna_crtc->id; 7220428d7b3dSmrg arg.fb_id = get_fb(sna, bo, 7221428d7b3dSmrg crtc->mode.HDisplay, 7222428d7b3dSmrg crtc->mode.VDisplay); 7223428d7b3dSmrg if (arg.fb_id == 0) 7224428d7b3dSmrg goto disable1; 7225428d7b3dSmrg 7226428d7b3dSmrg arg.user_data = (uintptr_t)sna_crtc; 7227428d7b3dSmrg arg.flags = DRM_MODE_PAGE_FLIP_EVENT; 7228428d7b3dSmrg arg.reserved = 0; 7229428d7b3dSmrg 7230428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) { 7231428d7b3dSmrg if (sna_crtc_flip(sna, sna_crtc, bo, 0, 0)) { 7232428d7b3dSmrg assert(sna_crtc->bo->active_scanout); 7233428d7b3dSmrg assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout); 7234428d7b3dSmrg sna_crtc->bo->active_scanout--; 7235428d7b3dSmrg kgem_bo_destroy(&sna->kgem, sna_crtc->bo); 7236428d7b3dSmrg 7237428d7b3dSmrg sna_crtc->bo = kgem_bo_reference(bo); 7238428d7b3dSmrg sna_crtc->bo->active_scanout++; 7239428d7b3dSmrg sna_crtc->client_bo = kgem_bo_reference(bo); 7240428d7b3dSmrg } else { 7241428d7b3dSmrg BoxRec box; 7242428d7b3dSmrg DrawableRec tmp; 7243428d7b3dSmrg 7244428d7b3dSmrg DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n", 7245428d7b3dSmrg __FUNCTION__, arg.fb_id, i, sna_crtc->id, sna_crtc->pipe, errno)); 7246428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 7247428d7b3dSmrg "Page flipping failed, disabling TearFree\n"); 7248428d7b3dSmrg sna->flags &= ~SNA_TEAR_FREE; 7249428d7b3dSmrg 7250428d7b3dSmrgdisable1: 7251428d7b3dSmrg box.x1 = 0; 7252428d7b3dSmrg box.y1 = 0; 7253428d7b3dSmrg tmp.width = box.x2 = crtc->mode.HDisplay; 7254428d7b3dSmrg tmp.height = box.y2 = crtc->mode.VDisplay; 7255428d7b3dSmrg tmp.depth = sna->front->drawable.depth; 7256428d7b3dSmrg tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel; 7257428d7b3dSmrg 7258428d7b3dSmrg if (!sna->render.copy_boxes(sna, GXcopy, 7259428d7b3dSmrg &sna->front->drawable, bo, 0, 0, 7260428d7b3dSmrg &tmp, sna_crtc->bo, 0, 0, 7261428d7b3dSmrg &box, 1, COPY_LAST)) { 7262428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 7263428d7b3dSmrg "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n", 7264428d7b3dSmrg __FUNCTION__, sna_crtc->id, sna_crtc->pipe); 7265428d7b3dSmrg sna_crtc_disable(crtc); 7266428d7b3dSmrg } 7267428d7b3dSmrg 7268428d7b3dSmrg kgem_bo_destroy(&sna->kgem, bo); 7269428d7b3dSmrg sna_crtc->client_bo = NULL; 7270428d7b3dSmrg } 7271428d7b3dSmrg continue; 7272428d7b3dSmrg } 7273428d7b3dSmrg sna->mode.flip_active++; 7274428d7b3dSmrg 7275428d7b3dSmrg assert(sna_crtc->flip_bo == NULL); 7276428d7b3dSmrg sna_crtc->flip_handler = shadow_flip_handler; 7277428d7b3dSmrg sna_crtc->flip_data = sna; 7278428d7b3dSmrg sna_crtc->flip_bo = bo; 7279428d7b3dSmrg sna_crtc->flip_bo->active_scanout++; 7280428d7b3dSmrg sna_crtc->flip_serial = sna_crtc->mode_serial; 7281428d7b3dSmrg sna_crtc->flip_pending = true; 7282428d7b3dSmrg 7283428d7b3dSmrg sna_crtc->client_bo = kgem_bo_reference(sna_crtc->bo); 7284428d7b3dSmrg } else { 7285428d7b3dSmrg sna_crtc_redisplay(crtc, &damage, sna_crtc->bo); 7286428d7b3dSmrg kgem_scanout_flush(&sna->kgem, sna_crtc->bo); 7287428d7b3dSmrg } 7288428d7b3dSmrg } 7289428d7b3dSmrg RegionUninit(&damage); 7290428d7b3dSmrg 7291428d7b3dSmrg if (sna_crtc->slave_damage) 7292428d7b3dSmrg DamageEmpty(sna_crtc->slave_damage); 7293428d7b3dSmrg } 7294428d7b3dSmrg 7295428d7b3dSmrg if (sna->mode.shadow) { 7296428d7b3dSmrg struct kgem_bo *new = __sna_pixmap_get_bo(sna->front); 7297428d7b3dSmrg struct kgem_bo *old = sna->mode.shadow; 7298428d7b3dSmrg struct drm_mode_crtc_page_flip arg; 7299428d7b3dSmrg uint32_t fb = 0; 7300428d7b3dSmrg 7301428d7b3dSmrg DBG(("%s: flipping TearFree outputs, current scanout handle=%d [active?=%d], new handle=%d [active=%d]\n", 7302428d7b3dSmrg __FUNCTION__, old->handle, old->active_scanout, new->handle, new->active_scanout)); 7303428d7b3dSmrg 7304428d7b3dSmrg assert(new != old); 7305428d7b3dSmrg assert(new->refcnt); 7306428d7b3dSmrg 7307428d7b3dSmrg arg.flags = DRM_MODE_PAGE_FLIP_EVENT; 7308428d7b3dSmrg arg.reserved = 0; 7309428d7b3dSmrg 7310428d7b3dSmrg kgem_bo_submit(&sna->kgem, new); 7311428d7b3dSmrg 7312428d7b3dSmrg for (i = 0; i < sna->mode.num_real_crtc; i++) { 7313428d7b3dSmrg struct sna_crtc *crtc = config->crtc[i]->driver_private; 7314428d7b3dSmrg struct kgem_bo *flip_bo; 7315428d7b3dSmrg int x, y; 7316428d7b3dSmrg 7317428d7b3dSmrg assert(crtc != NULL); 7318428d7b3dSmrg DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n", 7319428d7b3dSmrg __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo ? crtc->bo->handle : 0, crtc->transform)); 7320428d7b3dSmrg if (crtc->bo == NULL || crtc->transform) 7321428d7b3dSmrg continue; 7322428d7b3dSmrg 7323428d7b3dSmrg assert(config->crtc[i]->enabled); 7324428d7b3dSmrg assert(crtc->dpms_mode <= DPMSModeOn); 7325428d7b3dSmrg assert(crtc->flip_bo == NULL); 7326428d7b3dSmrg 7327428d7b3dSmrg arg.crtc_id = crtc->id; 7328428d7b3dSmrg arg.user_data = (uintptr_t)crtc; 7329428d7b3dSmrg 7330428d7b3dSmrg if (crtc->client_bo) { 7331428d7b3dSmrg DBG(("%s: apply shadow override bo for CRTC:%d on pipe=%d, handle=%d\n", 7332428d7b3dSmrg __FUNCTION__, crtc->id, crtc->pipe, crtc->client_bo->handle)); 7333428d7b3dSmrg arg.fb_id = get_fb(sna, crtc->client_bo, 7334428d7b3dSmrg crtc->base->mode.HDisplay, 7335428d7b3dSmrg crtc->base->mode.VDisplay); 7336428d7b3dSmrg assert(arg.fb_id != fb); 7337428d7b3dSmrg flip_bo = crtc->client_bo; 7338428d7b3dSmrg x = y = 0; 7339428d7b3dSmrg } else { 7340428d7b3dSmrg if (fb == 0) 7341428d7b3dSmrg fb = get_fb(sna, new, sna->scrn->virtualX, sna->scrn->virtualY); 7342428d7b3dSmrg if (fb == 0) { 7343428d7b3dSmrgfixup_shadow: 7344428d7b3dSmrg if (sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT)) { 7345428d7b3dSmrg BoxRec box; 7346428d7b3dSmrg 7347428d7b3dSmrg box.x1 = 0; 7348428d7b3dSmrg box.y1 = 0; 7349428d7b3dSmrg box.x2 = sna->scrn->virtualX; 7350428d7b3dSmrg box.y2 = sna->scrn->virtualY; 7351428d7b3dSmrg if (sna->render.copy_boxes(sna, GXcopy, 7352428d7b3dSmrg &sna->front->drawable, __sna_pixmap_get_bo(sna->front), 0, 0, 7353428d7b3dSmrg &sna->front->drawable, old, 0, 0, 7354428d7b3dSmrg &box, 1, COPY_LAST)) { 7355428d7b3dSmrg kgem_submit(&sna->kgem); 7356428d7b3dSmrg RegionEmpty(region); 7357428d7b3dSmrg } 7358428d7b3dSmrg } 7359428d7b3dSmrg 7360428d7b3dSmrg return; 7361428d7b3dSmrg } 7362428d7b3dSmrg 7363428d7b3dSmrg arg.fb_id = fb; 7364428d7b3dSmrg flip_bo = new; 7365428d7b3dSmrg x = crtc->base->x; 7366428d7b3dSmrg y = crtc->base->y; 7367428d7b3dSmrg } 7368428d7b3dSmrg 7369428d7b3dSmrg if (crtc->bo == flip_bo) 7370428d7b3dSmrg continue; 7371428d7b3dSmrg 7372428d7b3dSmrg if (flip_bo->pitch != crtc->bo->pitch || (y << 16 | x) != crtc->offset) { 7373428d7b3dSmrg DBG(("%s: changing pitch (new %d =?= old %d) or offset (new %x =?= old %x)\n", 7374428d7b3dSmrg __FUNCTION__, 7375428d7b3dSmrg flip_bo->pitch, crtc->bo->pitch, 7376428d7b3dSmrg y << 16 | x, crtc->offset)); 7377428d7b3dSmrgfixup_flip: 7378428d7b3dSmrg if (sna_crtc_flip(sna, crtc, flip_bo, x, y)) { 7379428d7b3dSmrg assert(flip_bo != crtc->bo); 7380428d7b3dSmrg assert(crtc->bo->active_scanout); 7381428d7b3dSmrg assert(crtc->bo->refcnt >= crtc->bo->active_scanout); 7382428d7b3dSmrg crtc->bo->active_scanout--; 7383428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->bo); 7384428d7b3dSmrg 7385428d7b3dSmrg if (crtc->shadow_bo) { 7386428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->shadow_bo); 7387428d7b3dSmrg crtc->shadow_bo = NULL; 7388428d7b3dSmrg } 7389428d7b3dSmrg 7390428d7b3dSmrg crtc->bo = kgem_bo_reference(flip_bo); 7391428d7b3dSmrg crtc->bo->active_scanout++; 7392428d7b3dSmrg } else { 7393428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 7394428d7b3dSmrg "Failed to prepare CRTC for page flipping, disabling TearFree\n"); 7395428d7b3dSmrg sna->flags &= ~SNA_TEAR_FREE; 7396428d7b3dSmrg 7397428d7b3dSmrg if (sna->mode.flip_active == 0) { 7398428d7b3dSmrg DBG(("%s: abandoning flip attempt\n", __FUNCTION__)); 7399428d7b3dSmrg goto fixup_shadow; 7400428d7b3dSmrg } 7401428d7b3dSmrg 7402428d7b3dSmrg xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR, 7403428d7b3dSmrg "%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n", 7404428d7b3dSmrg __FUNCTION__, crtc->id, crtc->pipe); 7405428d7b3dSmrg sna_crtc_disable(crtc->base); 7406428d7b3dSmrg } 7407428d7b3dSmrg continue; 7408428d7b3dSmrg } 7409428d7b3dSmrg 7410428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) { 7411428d7b3dSmrg ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n", 7412428d7b3dSmrg __FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno)); 7413428d7b3dSmrg goto fixup_flip; 7414428d7b3dSmrg } 7415428d7b3dSmrg sna->mode.flip_active++; 7416428d7b3dSmrg 7417428d7b3dSmrg assert(crtc->flip_bo == NULL); 7418428d7b3dSmrg crtc->flip_handler = shadow_flip_handler; 7419428d7b3dSmrg crtc->flip_data = sna; 7420428d7b3dSmrg crtc->flip_bo = kgem_bo_reference(flip_bo); 7421428d7b3dSmrg crtc->flip_bo->active_scanout++; 7422428d7b3dSmrg crtc->flip_serial = crtc->mode_serial; 7423428d7b3dSmrg crtc->flip_pending = true; 7424428d7b3dSmrg 7425428d7b3dSmrg { 7426428d7b3dSmrg struct drm_i915_gem_busy busy = { flip_bo->handle }; 7427428d7b3dSmrg if (drmIoctl(sna->kgem.fd, DRM_IOCTL_I915_GEM_BUSY, &busy) == 0) { 7428428d7b3dSmrg if (busy.busy) { 7429428d7b3dSmrg int mode = KGEM_RENDER; 7430428d7b3dSmrg if (busy.busy & (0xfffe << 16)) 7431428d7b3dSmrg mode = KGEM_BLT; 7432428d7b3dSmrg DBG(("%s: marking flip bo as busy [%x -> mode=%d]\n", __FUNCTION__, busy.busy, mode)); 7433428d7b3dSmrg kgem_bo_mark_busy(&sna->kgem, flip_bo, mode); 7434428d7b3dSmrg } else 7435428d7b3dSmrg __kgem_bo_clear_busy(flip_bo); 7436428d7b3dSmrg } 7437428d7b3dSmrg } 7438428d7b3dSmrg } 7439428d7b3dSmrg 7440428d7b3dSmrg DBG(("%s: flipped %d outputs, shadow active? %d\n", 7441428d7b3dSmrg __FUNCTION__, 7442428d7b3dSmrg sna->mode.flip_active, 7443428d7b3dSmrg sna->mode.shadow ? sna->mode.shadow->handle : 0)); 7444428d7b3dSmrg 7445428d7b3dSmrg if (sna->mode.flip_active) { 7446428d7b3dSmrg assert(old == sna->mode.shadow); 7447428d7b3dSmrg assert(old->refcnt >= 1); 7448428d7b3dSmrg set_shadow(sna, region); 7449428d7b3dSmrg } 7450428d7b3dSmrg } else 7451428d7b3dSmrg kgem_submit(&sna->kgem); 7452428d7b3dSmrg 7453428d7b3dSmrg RegionEmpty(region); 7454428d7b3dSmrg} 7455428d7b3dSmrg 7456428d7b3dSmrgint sna_mode_wakeup(struct sna *sna) 7457428d7b3dSmrg{ 7458428d7b3dSmrg char buffer[1024]; 7459428d7b3dSmrg int len, i; 7460428d7b3dSmrg int ret = 0; 7461428d7b3dSmrg 7462428d7b3dSmrgagain: 7463428d7b3dSmrg /* In order to workaround a kernel bug in not honouring O_NONBLOCK, 7464428d7b3dSmrg * check that the fd is readable before attempting to read the next 7465428d7b3dSmrg * event from drm. 7466428d7b3dSmrg */ 7467428d7b3dSmrg if (!event_pending(sna->kgem.fd)) 7468428d7b3dSmrg return ret; 7469428d7b3dSmrg 7470428d7b3dSmrg /* The DRM read semantics guarantees that we always get only 7471428d7b3dSmrg * complete events. 7472428d7b3dSmrg */ 7473428d7b3dSmrg len = read(sna->kgem.fd, buffer, sizeof (buffer)); 7474428d7b3dSmrg if (len < (int)sizeof(struct drm_event)) 7475428d7b3dSmrg return ret; 7476428d7b3dSmrg 7477428d7b3dSmrg /* Note that we cannot rely on the passed in struct sna matching 7478428d7b3dSmrg * the struct sna used for the vblank event (in case it was submitted 7479428d7b3dSmrg * by a different ZaphodHead). When processing the event, we must 7480428d7b3dSmrg * ensure that we only use the pointer passed along with the event. 7481428d7b3dSmrg */ 7482428d7b3dSmrg 7483428d7b3dSmrg DBG(("%s: len=%d\n", __FUNCTION__, len)); 7484428d7b3dSmrg 7485428d7b3dSmrg i = 0; 7486428d7b3dSmrg while (i < len) { 7487428d7b3dSmrg struct drm_event *e = (struct drm_event *)&buffer[i]; 7488428d7b3dSmrg switch (e->type) { 7489428d7b3dSmrg case DRM_EVENT_VBLANK: 7490428d7b3dSmrg if (((uintptr_t)((struct drm_event_vblank *)e)->user_data) & 2) 7491428d7b3dSmrg sna_present_vblank_handler((struct drm_event_vblank *)e); 7492428d7b3dSmrg else 7493428d7b3dSmrg sna_dri2_vblank_handler((struct drm_event_vblank *)e); 7494428d7b3dSmrg break; 7495428d7b3dSmrg case DRM_EVENT_FLIP_COMPLETE: 7496428d7b3dSmrg { 7497428d7b3dSmrg struct drm_event_vblank *vbl = (struct drm_event_vblank *)e; 7498428d7b3dSmrg struct sna_crtc *crtc = (void *)(uintptr_t)vbl->user_data; 7499428d7b3dSmrg 7500428d7b3dSmrg /* Beware Zaphod! */ 7501428d7b3dSmrg sna = to_sna(crtc->base->scrn); 7502428d7b3dSmrg 7503428d7b3dSmrg crtc->swap.tv_sec = vbl->tv_sec; 7504428d7b3dSmrg crtc->swap.tv_usec = vbl->tv_usec; 7505428d7b3dSmrg crtc->swap.msc = msc64(crtc, vbl->sequence); 7506428d7b3dSmrg crtc->flip_pending = false; 7507428d7b3dSmrg 7508428d7b3dSmrg assert(crtc->flip_bo); 7509428d7b3dSmrg assert(crtc->flip_bo->active_scanout); 7510428d7b3dSmrg assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout); 7511428d7b3dSmrg 7512428d7b3dSmrg if (crtc->flip_serial == crtc->mode_serial) { 7513428d7b3dSmrg DBG(("%s: removing handle=%d from scanout, installing handle=%d\n", 7514428d7b3dSmrg __FUNCTION__, crtc->bo->handle, crtc->flip_bo->handle)); 7515428d7b3dSmrg assert(crtc->bo->active_scanout); 7516428d7b3dSmrg assert(crtc->bo->refcnt >= crtc->bo->active_scanout); 7517428d7b3dSmrg crtc->bo->active_scanout--; 7518428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->bo); 7519428d7b3dSmrg 7520428d7b3dSmrg if (crtc->shadow_bo) { 7521428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->shadow_bo); 7522428d7b3dSmrg crtc->shadow_bo = NULL; 7523428d7b3dSmrg } 7524428d7b3dSmrg 7525428d7b3dSmrg crtc->bo = crtc->flip_bo; 7526428d7b3dSmrg crtc->flip_bo = NULL; 7527428d7b3dSmrg } else { 7528428d7b3dSmrg crtc->flip_bo->active_scanout--; 7529428d7b3dSmrg kgem_bo_destroy(&sna->kgem, crtc->flip_bo); 7530428d7b3dSmrg crtc->flip_bo = NULL; 7531428d7b3dSmrg } 7532428d7b3dSmrg 7533428d7b3dSmrg DBG(("%s: flip complete, pending? %d\n", __FUNCTION__, sna->mode.flip_active)); 7534428d7b3dSmrg assert(sna->mode.flip_active); 7535428d7b3dSmrg if (--sna->mode.flip_active == 0) 7536428d7b3dSmrg crtc->flip_handler(vbl, crtc->flip_data); 7537428d7b3dSmrg } 7538428d7b3dSmrg break; 7539428d7b3dSmrg default: 7540428d7b3dSmrg break; 7541428d7b3dSmrg } 7542428d7b3dSmrg i += e->length; 7543428d7b3dSmrg ret++; 7544428d7b3dSmrg } 7545428d7b3dSmrg 7546428d7b3dSmrg goto again; 7547428d7b3dSmrg} 7548