1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 2013 Intel Corporation 3428d7b3dSmrg * 4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 6428d7b3dSmrg * to deal in the Software without restriction, including without limitation 7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 10428d7b3dSmrg * 11428d7b3dSmrg * The above copyright notice and this permission notice (including the next 12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 13428d7b3dSmrg * Software. 14428d7b3dSmrg * 15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21428d7b3dSmrg * SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg * Authors: 24428d7b3dSmrg * Chris Wilson <chris@chris-wilson.co.uk> 25428d7b3dSmrg * 26428d7b3dSmrg */ 27428d7b3dSmrg 28428d7b3dSmrg#ifdef HAVE_CONFIG_H 29428d7b3dSmrg#include "config.h" 30428d7b3dSmrg#endif 31428d7b3dSmrg 32428d7b3dSmrg#include "sna.h" 33428d7b3dSmrg 34428d7b3dSmrgstatic bool add_fake_output(struct sna *sna, bool late); 35428d7b3dSmrg 36428d7b3dSmrgstatic void 37428d7b3dSmrgsna_crtc_dpms(xf86CrtcPtr crtc, int mode) 38428d7b3dSmrg{ 39428d7b3dSmrg} 40428d7b3dSmrg 41428d7b3dSmrgstatic char *outputs_for_crtc(xf86CrtcPtr crtc, char *outputs, int max) 42428d7b3dSmrg{ 43428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 44428d7b3dSmrg int len, i; 45428d7b3dSmrg 46428d7b3dSmrg for (i = len = 0; i < config->num_output; i++) { 47428d7b3dSmrg xf86OutputPtr output = config->output[i]; 48428d7b3dSmrg 49428d7b3dSmrg if (output->crtc != crtc) 50428d7b3dSmrg continue; 51428d7b3dSmrg 52428d7b3dSmrg len += snprintf(outputs+len, max-len, "%s, ", output->name); 53428d7b3dSmrg } 54428d7b3dSmrg assert(len >= 2); 55428d7b3dSmrg outputs[len-2] = '\0'; 56428d7b3dSmrg 57428d7b3dSmrg return outputs; 58428d7b3dSmrg} 59428d7b3dSmrg 60428d7b3dSmrgstatic const char *rotation_to_str(Rotation rotation) 61428d7b3dSmrg{ 62428d7b3dSmrg switch (rotation & RR_Rotate_All) { 63428d7b3dSmrg case 0: 64428d7b3dSmrg case RR_Rotate_0: return "normal"; 65428d7b3dSmrg case RR_Rotate_90: return "left"; 66428d7b3dSmrg case RR_Rotate_180: return "inverted"; 67428d7b3dSmrg case RR_Rotate_270: return "right"; 68428d7b3dSmrg default: return "unknown"; 69428d7b3dSmrg } 70428d7b3dSmrg} 71428d7b3dSmrg 72428d7b3dSmrgstatic const char *reflection_to_str(Rotation rotation) 73428d7b3dSmrg{ 74428d7b3dSmrg switch (rotation & RR_Reflect_All) { 75428d7b3dSmrg case 0: return "none"; 76428d7b3dSmrg case RR_Reflect_X: return "X axis"; 77428d7b3dSmrg case RR_Reflect_Y: return "Y axis"; 78428d7b3dSmrg case RR_Reflect_X | RR_Reflect_Y: return "X and Y axes"; 79428d7b3dSmrg default: return "invalid"; 80428d7b3dSmrg } 81428d7b3dSmrg} 82428d7b3dSmrg 83428d7b3dSmrgstatic Bool 84428d7b3dSmrgsna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 85428d7b3dSmrg Rotation rotation, int x, int y) 86428d7b3dSmrg{ 87428d7b3dSmrg char outputs[256]; 88428d7b3dSmrg 89428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, 90428d7b3dSmrg "switch to mode %dx%d on %s, position (%d, %d), rotation %s, reflection %s\n", 91428d7b3dSmrg mode->HDisplay, mode->VDisplay, 92428d7b3dSmrg outputs_for_crtc(crtc, outputs, sizeof(outputs)), 93428d7b3dSmrg x, y, rotation_to_str(rotation), reflection_to_str(rotation)); 94428d7b3dSmrg 95428d7b3dSmrg return TRUE; 96428d7b3dSmrg} 97428d7b3dSmrg 98428d7b3dSmrgstatic void 99428d7b3dSmrgsna_crtc_gamma_set(xf86CrtcPtr crtc, 100428d7b3dSmrg CARD16 *red, CARD16 *green, CARD16 *blue, int size) 101428d7b3dSmrg{ 102428d7b3dSmrg} 103428d7b3dSmrg 104428d7b3dSmrgstatic void 105428d7b3dSmrgsna_crtc_destroy(xf86CrtcPtr crtc) 106428d7b3dSmrg{ 107428d7b3dSmrg} 108428d7b3dSmrg 109428d7b3dSmrgstatic const xf86CrtcFuncsRec sna_crtc_funcs = { 110428d7b3dSmrg .dpms = sna_crtc_dpms, 111428d7b3dSmrg .set_mode_major = sna_crtc_set_mode_major, 112428d7b3dSmrg .gamma_set = sna_crtc_gamma_set, 113428d7b3dSmrg .destroy = sna_crtc_destroy, 114428d7b3dSmrg}; 115428d7b3dSmrg 116428d7b3dSmrgstatic void 117428d7b3dSmrgsna_output_create_resources(xf86OutputPtr output) 118428d7b3dSmrg{ 119428d7b3dSmrg} 120428d7b3dSmrg 121428d7b3dSmrgstatic Bool 122428d7b3dSmrgsna_output_set_property(xf86OutputPtr output, Atom property, 123428d7b3dSmrg RRPropertyValuePtr value) 124428d7b3dSmrg{ 125428d7b3dSmrg return TRUE; 126428d7b3dSmrg} 127428d7b3dSmrg 128428d7b3dSmrgstatic Bool 129428d7b3dSmrgsna_output_get_property(xf86OutputPtr output, Atom property) 130428d7b3dSmrg{ 131428d7b3dSmrg return FALSE; 132428d7b3dSmrg} 133428d7b3dSmrg 134428d7b3dSmrgstatic void 135428d7b3dSmrgsna_output_dpms(xf86OutputPtr output, int dpms) 136428d7b3dSmrg{ 137428d7b3dSmrg} 138428d7b3dSmrg 139428d7b3dSmrgstatic xf86OutputStatus 140428d7b3dSmrgsna_output_detect(xf86OutputPtr output) 141428d7b3dSmrg{ 142428d7b3dSmrg DBG(("%s(%s) has user modes? %d\n", 143428d7b3dSmrg __FUNCTION__, output->name, 144428d7b3dSmrg output->randr_output && output->randr_output->numUserModes)); 145428d7b3dSmrg 146428d7b3dSmrg if (output->randr_output && output->randr_output->numUserModes) { 147428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn); 148428d7b3dSmrg 149428d7b3dSmrg if (xf86_config->output[xf86_config->num_output-1] == output) 150428d7b3dSmrg add_fake_output(to_sna(output->scrn), true); 151428d7b3dSmrg 152428d7b3dSmrg return XF86OutputStatusConnected; 153428d7b3dSmrg } 154428d7b3dSmrg 155428d7b3dSmrg return XF86OutputStatusDisconnected; 156428d7b3dSmrg} 157428d7b3dSmrg 158428d7b3dSmrgstatic Bool 159428d7b3dSmrgsna_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) 160428d7b3dSmrg{ 161428d7b3dSmrg if (mode->type & M_T_DEFAULT) 162428d7b3dSmrg return MODE_BAD; 163428d7b3dSmrg 164428d7b3dSmrg return MODE_OK; 165428d7b3dSmrg} 166428d7b3dSmrg 167428d7b3dSmrgstatic DisplayModePtr 168428d7b3dSmrgsna_output_get_modes(xf86OutputPtr output) 169428d7b3dSmrg{ 170428d7b3dSmrg return NULL; 171428d7b3dSmrg} 172428d7b3dSmrg 173428d7b3dSmrgstatic void 174428d7b3dSmrgsna_output_destroy(xf86OutputPtr output) 175428d7b3dSmrg{ 176428d7b3dSmrg} 177428d7b3dSmrg 178428d7b3dSmrgstatic const xf86OutputFuncsRec sna_output_funcs = { 179428d7b3dSmrg .create_resources = sna_output_create_resources, 180428d7b3dSmrg#ifdef RANDR_12_INTERFACE 181428d7b3dSmrg .set_property = sna_output_set_property, 182428d7b3dSmrg .get_property = sna_output_get_property, 183428d7b3dSmrg#endif 184428d7b3dSmrg .dpms = sna_output_dpms, 185428d7b3dSmrg .detect = sna_output_detect, 186428d7b3dSmrg .mode_valid = sna_output_mode_valid, 187428d7b3dSmrg 188428d7b3dSmrg .get_modes = sna_output_get_modes, 189428d7b3dSmrg .destroy = sna_output_destroy 190428d7b3dSmrg}; 191428d7b3dSmrg 192428d7b3dSmrgstatic Bool 193428d7b3dSmrgsna_mode_resize(ScrnInfoPtr scrn, int width, int height) 194428d7b3dSmrg{ 195428d7b3dSmrg ScreenPtr screen = scrn->pScreen; 196428d7b3dSmrg PixmapPtr new_front; 197428d7b3dSmrg 198428d7b3dSmrg DBG(("%s (%d, %d) -> (%d, %d)\n", __FUNCTION__, 199428d7b3dSmrg scrn->virtualX, scrn->virtualY, 200428d7b3dSmrg width, height)); 201428d7b3dSmrg 202428d7b3dSmrg if (scrn->virtualX == width && scrn->virtualY == height) 203428d7b3dSmrg return TRUE; 204428d7b3dSmrg 205428d7b3dSmrg assert(to_sna_from_screen(screen)->front); 206428d7b3dSmrg assert(screen->GetScreenPixmap(screen) == to_sna_from_screen(screen)->front); 207428d7b3dSmrg 208428d7b3dSmrg DBG(("%s: creating new framebuffer %dx%d\n", 209428d7b3dSmrg __FUNCTION__, width, height)); 210428d7b3dSmrg 211428d7b3dSmrg new_front = screen->CreatePixmap(screen, 212428d7b3dSmrg width, height, scrn->depth, 213428d7b3dSmrg 0); 214428d7b3dSmrg if (!new_front) 215428d7b3dSmrg return FALSE; 216428d7b3dSmrg 217428d7b3dSmrg scrn->virtualX = width; 218428d7b3dSmrg scrn->virtualY = height; 219428d7b3dSmrg scrn->displayWidth = width; 220428d7b3dSmrg 221428d7b3dSmrg screen->SetScreenPixmap(new_front); 222428d7b3dSmrg assert(screen->GetScreenPixmap(screen) == new_front); 223428d7b3dSmrg assert(to_sna_from_screen(screen)->front == new_front); 224428d7b3dSmrg 225428d7b3dSmrg screen->DestroyPixmap(new_front); 226428d7b3dSmrg 227428d7b3dSmrg return TRUE; 228428d7b3dSmrg} 229428d7b3dSmrg 230428d7b3dSmrgstatic const xf86CrtcConfigFuncsRec sna_mode_funcs = { 231428d7b3dSmrg sna_mode_resize 232428d7b3dSmrg}; 233428d7b3dSmrg 234428d7b3dSmrgstatic bool add_fake_output(struct sna *sna, bool late) 235428d7b3dSmrg{ 236428d7b3dSmrg ScrnInfoPtr scrn = sna->scrn; 237428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 238428d7b3dSmrg xf86OutputPtr output; 239428d7b3dSmrg xf86CrtcPtr crtc; 240428d7b3dSmrg RROutputPtr clones[32]; 241428d7b3dSmrg RRCrtcPtr crtcs[32]; 242428d7b3dSmrg char buf[80]; 243428d7b3dSmrg int i, len; 244428d7b3dSmrg 245428d7b3dSmrg if (sna->mode.num_fake >= 32) 246428d7b3dSmrg return false; 247428d7b3dSmrg 248428d7b3dSmrg DBG(("%s(late=%d, num_fake=%d)\n", __FUNCTION__, late, sna->mode.num_fake+1)); 249428d7b3dSmrg 250428d7b3dSmrg crtc = xf86CrtcCreate(scrn, &sna_crtc_funcs); 251428d7b3dSmrg if (crtc == NULL) 252428d7b3dSmrg return false; 253428d7b3dSmrg 254428d7b3dSmrg len = sprintf(buf, "VIRTUAL%d", sna->mode.num_fake+1); 255428d7b3dSmrg output = xf86OutputCreate(scrn, &sna_output_funcs, buf); 256428d7b3dSmrg if (!output) { 257428d7b3dSmrg xf86CrtcDestroy(crtc); 258428d7b3dSmrg return false; 259428d7b3dSmrg } 260428d7b3dSmrg 261428d7b3dSmrg output->mm_width = 0; 262428d7b3dSmrg output->mm_height = 0; 263428d7b3dSmrg output->interlaceAllowed = FALSE; 264428d7b3dSmrg output->subpixel_order = SubPixelNone; 265428d7b3dSmrg 266428d7b3dSmrg output->possible_crtcs = ~((1 << sna->mode.num_real_crtc) - 1); 267428d7b3dSmrg output->possible_clones = ~((1 << sna->mode.num_real_output) - 1); 268428d7b3dSmrg 269428d7b3dSmrg if (late) { 270428d7b3dSmrg ScreenPtr screen = xf86ScrnToScreen(scrn); 271428d7b3dSmrg 272428d7b3dSmrg crtc->randr_crtc = RRCrtcCreate(screen, crtc); 273428d7b3dSmrg output->randr_output = RROutputCreate(screen, buf, len, output); 274428d7b3dSmrg if (crtc->randr_crtc == NULL || output->randr_output == NULL) { 275428d7b3dSmrg xf86OutputDestroy(output); 276428d7b3dSmrg xf86CrtcDestroy(crtc); 277428d7b3dSmrg return false; 278428d7b3dSmrg } 279428d7b3dSmrg 280428d7b3dSmrg RRPostPendingProperties(output->randr_output); 281428d7b3dSmrg 282428d7b3dSmrg for (i = sna->mode.num_real_output; i < xf86_config->num_output; i++) 283428d7b3dSmrg clones[i - sna->mode.num_real_output] = xf86_config->output[i]->randr_output; 284428d7b3dSmrg assert(i - sna->mode.num_real_output == sna->mode.num_fake + 1); 285428d7b3dSmrg 286428d7b3dSmrg for (i = sna->mode.num_real_crtc; i < xf86_config->num_crtc; i++) 287428d7b3dSmrg crtcs[i - sna->mode.num_real_crtc] = xf86_config->crtc[i]->randr_crtc; 288428d7b3dSmrg assert(i - sna->mode.num_real_crtc == sna->mode.num_fake + 1); 289428d7b3dSmrg 290428d7b3dSmrg for (i = sna->mode.num_real_output; i < xf86_config->num_output; i++) { 291428d7b3dSmrg RROutputPtr rr_output = xf86_config->output[i]->randr_output; 292428d7b3dSmrg 293428d7b3dSmrg if (!RROutputSetCrtcs(rr_output, crtcs, sna->mode.num_fake + 1) || 294428d7b3dSmrg !RROutputSetClones(rr_output, clones, sna->mode.num_fake + 1)) 295428d7b3dSmrg goto err; 296428d7b3dSmrg } 297428d7b3dSmrg 298428d7b3dSmrg RRCrtcSetRotations(crtc->randr_crtc, 299428d7b3dSmrg RR_Rotate_All | RR_Reflect_All); 300428d7b3dSmrg } 301428d7b3dSmrg 302428d7b3dSmrg sna->mode.num_fake++; 303428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 304428d7b3dSmrg "Enabled output %s\n", 305428d7b3dSmrg output->name); 306428d7b3dSmrg return true; 307428d7b3dSmrg 308428d7b3dSmrgerr: 309428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 310428d7b3dSmrg output = xf86_config->output[i]; 311428d7b3dSmrg if (output->driver_private) 312428d7b3dSmrg continue; 313428d7b3dSmrg 314428d7b3dSmrg xf86OutputDestroy(output); 315428d7b3dSmrg } 316428d7b3dSmrg 317428d7b3dSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 318428d7b3dSmrg crtc = xf86_config->crtc[i]; 319428d7b3dSmrg if (crtc->driver_private) 320428d7b3dSmrg continue; 321428d7b3dSmrg xf86CrtcDestroy(crtc); 322428d7b3dSmrg } 323428d7b3dSmrg sna->mode.num_fake = -1; 324428d7b3dSmrg return false; 325428d7b3dSmrg} 326428d7b3dSmrg 327428d7b3dSmrgbool sna_mode_fake_init(struct sna *sna, int num_fake) 328428d7b3dSmrg{ 329428d7b3dSmrg bool ret; 330428d7b3dSmrg 331428d7b3dSmrg if (num_fake == 0) 332428d7b3dSmrg return true; 333428d7b3dSmrg 334428d7b3dSmrg if (sna->mode.num_real_crtc == 0) { 335428d7b3dSmrg xf86CrtcConfigInit(sna->scrn, &sna_mode_funcs); 336428d7b3dSmrg xf86CrtcSetSizeRange(sna->scrn, 1, 1, INT16_MAX, INT16_MAX); 337428d7b3dSmrg } 338428d7b3dSmrg 339428d7b3dSmrg ret = true; 340428d7b3dSmrg while (ret && num_fake--) 341428d7b3dSmrg ret = add_fake_output(sna, false); 342428d7b3dSmrg return ret; 343428d7b3dSmrg} 344