103b705cfSriastradh/* 203b705cfSriastradh * Copyright © 2013 Intel Corporation 303b705cfSriastradh * 403b705cfSriastradh * Permission is hereby granted, free of charge, to any person obtaining a 503b705cfSriastradh * copy of this software and associated documentation files (the "Software"), 603b705cfSriastradh * to deal in the Software without restriction, including without limitation 703b705cfSriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 803b705cfSriastradh * and/or sell copies of the Software, and to permit persons to whom the 903b705cfSriastradh * Software is furnished to do so, subject to the following conditions: 1003b705cfSriastradh * 1103b705cfSriastradh * The above copyright notice and this permission notice (including the next 1203b705cfSriastradh * paragraph) shall be included in all copies or substantial portions of the 1303b705cfSriastradh * Software. 1403b705cfSriastradh * 1503b705cfSriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1603b705cfSriastradh * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1703b705cfSriastradh * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1803b705cfSriastradh * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1903b705cfSriastradh * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2003b705cfSriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 2103b705cfSriastradh * SOFTWARE. 2203b705cfSriastradh * 2303b705cfSriastradh * Authors: 2403b705cfSriastradh * Chris Wilson <chris@chris-wilson.co.uk> 2503b705cfSriastradh * 2603b705cfSriastradh */ 2703b705cfSriastradh 2803b705cfSriastradh#ifdef HAVE_CONFIG_H 2903b705cfSriastradh#include "config.h" 3003b705cfSriastradh#endif 3103b705cfSriastradh 3203b705cfSriastradh#include "sna.h" 3303b705cfSriastradh 3442542f5fSchristosstatic bool add_fake_output(struct sna *sna, bool late); 3542542f5fSchristos 3603b705cfSriastradhstatic void 3703b705cfSriastradhsna_crtc_dpms(xf86CrtcPtr crtc, int mode) 3803b705cfSriastradh{ 3903b705cfSriastradh} 4003b705cfSriastradh 4142542f5fSchristosstatic char *outputs_for_crtc(xf86CrtcPtr crtc, char *outputs, int max) 4203b705cfSriastradh{ 4342542f5fSchristos xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 4442542f5fSchristos int len, i; 4503b705cfSriastradh 4642542f5fSchristos for (i = len = 0; i < config->num_output; i++) { 4742542f5fSchristos xf86OutputPtr output = config->output[i]; 4803b705cfSriastradh 4942542f5fSchristos if (output->crtc != crtc) 5042542f5fSchristos continue; 5142542f5fSchristos 5242542f5fSchristos len += snprintf(outputs+len, max-len, "%s, ", output->name); 5342542f5fSchristos } 5442542f5fSchristos assert(len >= 2); 5542542f5fSchristos outputs[len-2] = '\0'; 5642542f5fSchristos 5742542f5fSchristos return outputs; 5803b705cfSriastradh} 5903b705cfSriastradh 6042542f5fSchristosstatic const char *rotation_to_str(Rotation rotation) 6103b705cfSriastradh{ 6242542f5fSchristos switch (rotation & RR_Rotate_All) { 6342542f5fSchristos case 0: 6442542f5fSchristos case RR_Rotate_0: return "normal"; 6542542f5fSchristos case RR_Rotate_90: return "left"; 6642542f5fSchristos case RR_Rotate_180: return "inverted"; 6742542f5fSchristos case RR_Rotate_270: return "right"; 6842542f5fSchristos default: return "unknown"; 6942542f5fSchristos } 7003b705cfSriastradh} 7103b705cfSriastradh 7242542f5fSchristosstatic const char *reflection_to_str(Rotation rotation) 7303b705cfSriastradh{ 7442542f5fSchristos switch (rotation & RR_Reflect_All) { 7542542f5fSchristos case 0: return "none"; 7642542f5fSchristos case RR_Reflect_X: return "X axis"; 7742542f5fSchristos case RR_Reflect_Y: return "Y axis"; 7842542f5fSchristos case RR_Reflect_X | RR_Reflect_Y: return "X and Y axes"; 7942542f5fSchristos default: return "invalid"; 8042542f5fSchristos } 8103b705cfSriastradh} 8203b705cfSriastradh 8342542f5fSchristosstatic Bool 8442542f5fSchristossna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 8542542f5fSchristos Rotation rotation, int x, int y) 8603b705cfSriastradh{ 8742542f5fSchristos char outputs[256]; 8842542f5fSchristos 8942542f5fSchristos xf86DrvMsg(crtc->scrn->scrnIndex, X_INFO, 9042542f5fSchristos "switch to mode %dx%d on %s, position (%d, %d), rotation %s, reflection %s\n", 9142542f5fSchristos mode->HDisplay, mode->VDisplay, 9242542f5fSchristos outputs_for_crtc(crtc, outputs, sizeof(outputs)), 9342542f5fSchristos x, y, rotation_to_str(rotation), reflection_to_str(rotation)); 9442542f5fSchristos 9542542f5fSchristos return TRUE; 9603b705cfSriastradh} 9703b705cfSriastradh 9803b705cfSriastradhstatic void 9903b705cfSriastradhsna_crtc_destroy(xf86CrtcPtr crtc) 10003b705cfSriastradh{ 10103b705cfSriastradh} 10203b705cfSriastradh 10303b705cfSriastradhstatic const xf86CrtcFuncsRec sna_crtc_funcs = { 10403b705cfSriastradh .dpms = sna_crtc_dpms, 10503b705cfSriastradh .set_mode_major = sna_crtc_set_mode_major, 10603b705cfSriastradh .destroy = sna_crtc_destroy, 10703b705cfSriastradh}; 10803b705cfSriastradh 10903b705cfSriastradhstatic void 11003b705cfSriastradhsna_output_create_resources(xf86OutputPtr output) 11103b705cfSriastradh{ 11203b705cfSriastradh} 11303b705cfSriastradh 11403b705cfSriastradhstatic Bool 11503b705cfSriastradhsna_output_set_property(xf86OutputPtr output, Atom property, 11603b705cfSriastradh RRPropertyValuePtr value) 11703b705cfSriastradh{ 11803b705cfSriastradh return TRUE; 11903b705cfSriastradh} 12003b705cfSriastradh 12103b705cfSriastradhstatic Bool 12203b705cfSriastradhsna_output_get_property(xf86OutputPtr output, Atom property) 12303b705cfSriastradh{ 12403b705cfSriastradh return FALSE; 12503b705cfSriastradh} 12603b705cfSriastradh 12703b705cfSriastradhstatic void 12803b705cfSriastradhsna_output_dpms(xf86OutputPtr output, int dpms) 12903b705cfSriastradh{ 13003b705cfSriastradh} 13103b705cfSriastradh 13203b705cfSriastradhstatic xf86OutputStatus 13303b705cfSriastradhsna_output_detect(xf86OutputPtr output) 13403b705cfSriastradh{ 13542542f5fSchristos DBG(("%s(%s) has user modes? %d\n", 13642542f5fSchristos __FUNCTION__, output->name, 13742542f5fSchristos output->randr_output && output->randr_output->numUserModes)); 13842542f5fSchristos 13942542f5fSchristos if (output->randr_output && output->randr_output->numUserModes) { 14042542f5fSchristos xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(output->scrn); 14142542f5fSchristos 14242542f5fSchristos if (xf86_config->output[xf86_config->num_output-1] == output) 14342542f5fSchristos add_fake_output(to_sna(output->scrn), true); 14442542f5fSchristos 14542542f5fSchristos return XF86OutputStatusConnected; 14642542f5fSchristos } 14742542f5fSchristos 14803b705cfSriastradh return XF86OutputStatusDisconnected; 14903b705cfSriastradh} 15003b705cfSriastradh 15103b705cfSriastradhstatic Bool 15203b705cfSriastradhsna_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) 15303b705cfSriastradh{ 15442542f5fSchristos if (mode->type & M_T_DEFAULT) 15542542f5fSchristos return MODE_BAD; 15642542f5fSchristos 15703b705cfSriastradh return MODE_OK; 15803b705cfSriastradh} 15903b705cfSriastradh 16003b705cfSriastradhstatic DisplayModePtr 16103b705cfSriastradhsna_output_get_modes(xf86OutputPtr output) 16203b705cfSriastradh{ 16342542f5fSchristos return NULL; 16403b705cfSriastradh} 16503b705cfSriastradh 16603b705cfSriastradhstatic void 16703b705cfSriastradhsna_output_destroy(xf86OutputPtr output) 16803b705cfSriastradh{ 16903b705cfSriastradh} 17003b705cfSriastradh 17103b705cfSriastradhstatic const xf86OutputFuncsRec sna_output_funcs = { 17203b705cfSriastradh .create_resources = sna_output_create_resources, 17303b705cfSriastradh#ifdef RANDR_12_INTERFACE 17403b705cfSriastradh .set_property = sna_output_set_property, 17503b705cfSriastradh .get_property = sna_output_get_property, 17603b705cfSriastradh#endif 17703b705cfSriastradh .dpms = sna_output_dpms, 17803b705cfSriastradh .detect = sna_output_detect, 17903b705cfSriastradh .mode_valid = sna_output_mode_valid, 18003b705cfSriastradh 18103b705cfSriastradh .get_modes = sna_output_get_modes, 18203b705cfSriastradh .destroy = sna_output_destroy 18303b705cfSriastradh}; 18403b705cfSriastradh 18503b705cfSriastradhstatic Bool 18603b705cfSriastradhsna_mode_resize(ScrnInfoPtr scrn, int width, int height) 18703b705cfSriastradh{ 188fe8aea9eSmrg ScreenPtr screen = xf86ScrnToScreen(scrn); 18942542f5fSchristos PixmapPtr new_front; 19003b705cfSriastradh 19103b705cfSriastradh DBG(("%s (%d, %d) -> (%d, %d)\n", __FUNCTION__, 19203b705cfSriastradh scrn->virtualX, scrn->virtualY, 19303b705cfSriastradh width, height)); 19403b705cfSriastradh 19503b705cfSriastradh if (scrn->virtualX == width && scrn->virtualY == height) 19603b705cfSriastradh return TRUE; 19703b705cfSriastradh 19842542f5fSchristos assert(to_sna_from_screen(screen)->front); 19942542f5fSchristos assert(screen->GetScreenPixmap(screen) == to_sna_from_screen(screen)->front); 20003b705cfSriastradh 20103b705cfSriastradh DBG(("%s: creating new framebuffer %dx%d\n", 20203b705cfSriastradh __FUNCTION__, width, height)); 20303b705cfSriastradh 20403b705cfSriastradh new_front = screen->CreatePixmap(screen, 20503b705cfSriastradh width, height, scrn->depth, 20642542f5fSchristos 0); 20703b705cfSriastradh if (!new_front) 20803b705cfSriastradh return FALSE; 20903b705cfSriastradh 21003b705cfSriastradh scrn->virtualX = width; 21103b705cfSriastradh scrn->virtualY = height; 21203b705cfSriastradh scrn->displayWidth = width; 21303b705cfSriastradh 21442542f5fSchristos screen->SetScreenPixmap(new_front); 21542542f5fSchristos assert(screen->GetScreenPixmap(screen) == new_front); 21642542f5fSchristos assert(to_sna_from_screen(screen)->front == new_front); 21703b705cfSriastradh 21842542f5fSchristos screen->DestroyPixmap(new_front); 21903b705cfSriastradh 22003b705cfSriastradh return TRUE; 22103b705cfSriastradh} 22203b705cfSriastradh 22303b705cfSriastradhstatic const xf86CrtcConfigFuncsRec sna_mode_funcs = { 22403b705cfSriastradh sna_mode_resize 22503b705cfSriastradh}; 22603b705cfSriastradh 22742542f5fSchristosstatic bool add_fake_output(struct sna *sna, bool late) 22842542f5fSchristos{ 22942542f5fSchristos ScrnInfoPtr scrn = sna->scrn; 23042542f5fSchristos xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 23142542f5fSchristos xf86OutputPtr output; 23242542f5fSchristos xf86CrtcPtr crtc; 23342542f5fSchristos RROutputPtr clones[32]; 23442542f5fSchristos RRCrtcPtr crtcs[32]; 23542542f5fSchristos char buf[80]; 23642542f5fSchristos int i, len; 23742542f5fSchristos 23842542f5fSchristos if (sna->mode.num_fake >= 32) 23942542f5fSchristos return false; 24042542f5fSchristos 24142542f5fSchristos DBG(("%s(late=%d, num_fake=%d)\n", __FUNCTION__, late, sna->mode.num_fake+1)); 24242542f5fSchristos 24342542f5fSchristos crtc = xf86CrtcCreate(scrn, &sna_crtc_funcs); 24442542f5fSchristos if (crtc == NULL) 24542542f5fSchristos return false; 24642542f5fSchristos 24742542f5fSchristos len = sprintf(buf, "VIRTUAL%d", sna->mode.num_fake+1); 24842542f5fSchristos output = xf86OutputCreate(scrn, &sna_output_funcs, buf); 24942542f5fSchristos if (!output) { 25042542f5fSchristos xf86CrtcDestroy(crtc); 25142542f5fSchristos return false; 25242542f5fSchristos } 25342542f5fSchristos 25442542f5fSchristos output->mm_width = 0; 25542542f5fSchristos output->mm_height = 0; 25642542f5fSchristos output->interlaceAllowed = FALSE; 25742542f5fSchristos output->subpixel_order = SubPixelNone; 258fe8aea9eSmrg output->status = XF86OutputStatusDisconnected; 25942542f5fSchristos 26042542f5fSchristos output->possible_crtcs = ~((1 << sna->mode.num_real_crtc) - 1); 26142542f5fSchristos output->possible_clones = ~((1 << sna->mode.num_real_output) - 1); 26242542f5fSchristos 26342542f5fSchristos if (late) { 26442542f5fSchristos ScreenPtr screen = xf86ScrnToScreen(scrn); 26542542f5fSchristos 26642542f5fSchristos crtc->randr_crtc = RRCrtcCreate(screen, crtc); 26742542f5fSchristos output->randr_output = RROutputCreate(screen, buf, len, output); 26842542f5fSchristos if (crtc->randr_crtc == NULL || output->randr_output == NULL) { 26942542f5fSchristos xf86OutputDestroy(output); 27042542f5fSchristos xf86CrtcDestroy(crtc); 27142542f5fSchristos return false; 27242542f5fSchristos } 27342542f5fSchristos 27442542f5fSchristos RRPostPendingProperties(output->randr_output); 27542542f5fSchristos 27642542f5fSchristos for (i = sna->mode.num_real_output; i < xf86_config->num_output; i++) 27742542f5fSchristos clones[i - sna->mode.num_real_output] = xf86_config->output[i]->randr_output; 27842542f5fSchristos assert(i - sna->mode.num_real_output == sna->mode.num_fake + 1); 27942542f5fSchristos 28042542f5fSchristos for (i = sna->mode.num_real_crtc; i < xf86_config->num_crtc; i++) 28142542f5fSchristos crtcs[i - sna->mode.num_real_crtc] = xf86_config->crtc[i]->randr_crtc; 28242542f5fSchristos assert(i - sna->mode.num_real_crtc == sna->mode.num_fake + 1); 28342542f5fSchristos 28442542f5fSchristos for (i = sna->mode.num_real_output; i < xf86_config->num_output; i++) { 28542542f5fSchristos RROutputPtr rr_output = xf86_config->output[i]->randr_output; 28642542f5fSchristos 28742542f5fSchristos if (!RROutputSetCrtcs(rr_output, crtcs, sna->mode.num_fake + 1) || 28842542f5fSchristos !RROutputSetClones(rr_output, clones, sna->mode.num_fake + 1)) 28942542f5fSchristos goto err; 29042542f5fSchristos } 29142542f5fSchristos 29242542f5fSchristos RRCrtcSetRotations(crtc->randr_crtc, 29342542f5fSchristos RR_Rotate_All | RR_Reflect_All); 294fe8aea9eSmrg if (!RRCrtcGammaSetSize(crtc->randr_crtc, 256)) 295fe8aea9eSmrg goto err; 29642542f5fSchristos } 29742542f5fSchristos 29842542f5fSchristos sna->mode.num_fake++; 29942542f5fSchristos xf86DrvMsg(scrn->scrnIndex, X_INFO, 30042542f5fSchristos "Enabled output %s\n", 30142542f5fSchristos output->name); 30242542f5fSchristos return true; 30342542f5fSchristos 30442542f5fSchristoserr: 30542542f5fSchristos for (i = 0; i < xf86_config->num_output; i++) { 30642542f5fSchristos output = xf86_config->output[i]; 30742542f5fSchristos if (output->driver_private) 30842542f5fSchristos continue; 30942542f5fSchristos 31042542f5fSchristos xf86OutputDestroy(output); 311fe8aea9eSmrg i--; 31242542f5fSchristos } 31342542f5fSchristos 31442542f5fSchristos for (i = 0; i < xf86_config->num_crtc; i++) { 31542542f5fSchristos crtc = xf86_config->crtc[i]; 31642542f5fSchristos if (crtc->driver_private) 31742542f5fSchristos continue; 318fe8aea9eSmrg 31942542f5fSchristos xf86CrtcDestroy(crtc); 320fe8aea9eSmrg i--; 32142542f5fSchristos } 32242542f5fSchristos sna->mode.num_fake = -1; 32342542f5fSchristos return false; 32442542f5fSchristos} 32542542f5fSchristos 32642542f5fSchristosbool sna_mode_fake_init(struct sna *sna, int num_fake) 32703b705cfSriastradh{ 32842542f5fSchristos bool ret; 32942542f5fSchristos 33042542f5fSchristos if (num_fake == 0) 33142542f5fSchristos return true; 33242542f5fSchristos 33342542f5fSchristos if (sna->mode.num_real_crtc == 0) { 33442542f5fSchristos xf86CrtcConfigInit(sna->scrn, &sna_mode_funcs); 33542542f5fSchristos xf86CrtcSetSizeRange(sna->scrn, 1, 1, INT16_MAX, INT16_MAX); 33642542f5fSchristos } 33742542f5fSchristos 33842542f5fSchristos ret = true; 33942542f5fSchristos while (ret && num_fake--) 34042542f5fSchristos ret = add_fake_output(sna, false); 34142542f5fSchristos return ret; 34203b705cfSriastradh} 343