| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/display/output_configurator.h" | 5 #include "chromeos/display/output_configurator.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
| 10 #include <X11/Xlib.h> | 10 #include <X11/Xlib.h> |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 #undef Status | 21 #undef Status |
| 22 #undef RootWindow | 22 #undef RootWindow |
| 23 | 23 |
| 24 #include "base/bind.h" | 24 #include "base/bind.h" |
| 25 #include "base/chromeos/chromeos_version.h" | 25 #include "base/chromeos/chromeos_version.h" |
| 26 #include "base/debug/trace_event.h" | 26 #include "base/debug/trace_event.h" |
| 27 #include "base/logging.h" | 27 #include "base/logging.h" |
| 28 #include "base/message_pump_aurax11.h" | 28 #include "base/message_pump_aurax11.h" |
| 29 #include "base/metrics/histogram.h" | 29 #include "base/metrics/histogram.h" |
| 30 #include "base/perftimer.h" | 30 #include "base/perftimer.h" |
| 31 #include "base/strings/string_number_conversions.h" |
| 31 #include "base/time.h" | 32 #include "base/time.h" |
| 32 #include "chromeos/dbus/dbus_thread_manager.h" | 33 #include "chromeos/dbus/dbus_thread_manager.h" |
| 33 #include "chromeos/dbus/power_manager_client.h" | 34 #include "chromeos/dbus/power_manager_client.h" |
| 34 | 35 |
| 35 namespace chromeos { | 36 namespace chromeos { |
| 36 | 37 |
| 37 struct OutputSnapshot { | 38 struct OutputSnapshot { |
| 38 RROutput output; | 39 RROutput output; |
| 39 RRCrtc crtc; | 40 RRCrtc crtc; |
| 40 RRMode current_mode; | 41 RRMode current_mode; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 }; | 87 }; |
| 87 | 88 |
| 88 enum MirrorModeType { | 89 enum MirrorModeType { |
| 89 MIRROR_MODE_NONE, | 90 MIRROR_MODE_NONE, |
| 90 MIRROR_MODE_ASPECT_PRESERVING, | 91 MIRROR_MODE_ASPECT_PRESERVING, |
| 91 MIRROR_MODE_FALLBACK, | 92 MIRROR_MODE_FALLBACK, |
| 92 MIRROR_MODE_TYPE_COUNT | 93 MIRROR_MODE_TYPE_COUNT |
| 93 }; | 94 }; |
| 94 | 95 |
| 95 namespace { | 96 namespace { |
| 97 |
| 96 // DPI measurements. | 98 // DPI measurements. |
| 97 const float kMmInInch = 25.4; | 99 const float kMmInInch = 25.4; |
| 98 const float kDpi96 = 96.0; | 100 const float kDpi96 = 96.0; |
| 99 const float kPixelsToMmScale = kMmInInch / kDpi96; | 101 const float kPixelsToMmScale = kMmInInch / kDpi96; |
| 100 | 102 |
| 101 // The DPI threshold to detech high density screen. | 103 // The DPI threshold to detech high density screen. |
| 102 // Higher DPI than this will use device_scale_factor=2 | 104 // Higher DPI than this will use device_scale_factor=2 |
| 103 // Should be kept in sync with display_change_observer_x11.cc | 105 // Should be kept in sync with display_change_observer_x11.cc |
| 104 const unsigned int kHighDensityDIPThreshold = 160; | 106 const unsigned int kHighDensityDIPThreshold = 160; |
| 105 | 107 |
| 106 // Prefixes for the built-in displays. | 108 // Prefixes for the built-in displays. |
| 107 const char kInternal_LVDS[] = "LVDS"; | 109 const char kInternal_LVDS[] = "LVDS"; |
| 108 const char kInternal_eDP[] = "eDP"; | 110 const char kInternal_eDP[] = "eDP"; |
| 109 | 111 |
| 110 // The delay to perform configuration after RRNotify. See the comment | 112 // The delay to perform configuration after RRNotify. See the comment |
| 111 // in |Dispatch()|. | 113 // in |Dispatch()|. |
| 112 const int64 kConfigureDelayMs = 500; | 114 const int64 kConfigureDelayMs = 500; |
| 113 | 115 |
| 114 // Gap between screens so cursor at bottom of active display doesn't partially | 116 // Gap between screens so cursor at bottom of active display doesn't partially |
| 115 // appear on top of inactive display. Higher numbers guard against larger | 117 // appear on top of inactive display. Higher numbers guard against larger |
| 116 // cursors, but also waste more memory. | 118 // cursors, but also waste more memory. |
| 117 // For simplicity, this is hard-coded to 60 to avoid the complexity of always | 119 // For simplicity, this is hard-coded to 60 to avoid the complexity of always |
| 118 // determining the DPI of the screen and rationalizing which screen we need to | 120 // determining the DPI of the screen and rationalizing which screen we need to |
| 119 // use for the DPI calculation. | 121 // use for the DPI calculation. |
| 120 // See crbug.com/130188 for initial discussion. | 122 // See crbug.com/130188 for initial discussion. |
| 121 const int kVerticalGap = 60; | 123 const int kVerticalGap = 60; |
| 122 | 124 |
| 125 // Returns a string describing |state|. |
| 126 std::string DisplayPowerStateToString(DisplayPowerState state) { |
| 127 switch (state) { |
| 128 case DISPLAY_POWER_ALL_ON: |
| 129 return "ALL_ON"; |
| 130 case DISPLAY_POWER_ALL_OFF: |
| 131 return "ALL_OFF"; |
| 132 case DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON: |
| 133 return "INTERNAL_OFF_EXTERNAL_ON"; |
| 134 case DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF: |
| 135 return "INTERNAL_ON_EXTERNAL_OFF"; |
| 136 default: |
| 137 return "unknown (" + base::IntToString(state) + ")"; |
| 138 } |
| 139 } |
| 140 |
| 123 // TODO: Determine if we need to organize modes in a way which provides better | 141 // TODO: Determine if we need to organize modes in a way which provides better |
| 124 // than O(n) lookup time. In many call sites, for example, the "next" mode is | 142 // than O(n) lookup time. In many call sites, for example, the "next" mode is |
| 125 // typically what we are looking for so using this helper might be too | 143 // typically what we are looking for so using this helper might be too |
| 126 // expensive. | 144 // expensive. |
| 127 XRRModeInfo* ModeInfoForID(XRRScreenResources* screen, RRMode modeID) { | 145 XRRModeInfo* ModeInfoForID(XRRScreenResources* screen, RRMode modeID) { |
| 128 XRRModeInfo* result = NULL; | 146 XRRModeInfo* result = NULL; |
| 129 for (int i = 0; (i < screen->nmode) && (result == NULL); i++) | 147 for (int i = 0; (i < screen->nmode) && (result == NULL); i++) |
| 130 if (modeID == screen->modes[i].id) | 148 if (modeID == screen->modes[i].id) |
| 131 result = &screen->modes[i]; | 149 result = &screen->modes[i]; |
| 132 | 150 |
| (...skipping 457 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 590 | 608 |
| 591 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> | 609 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> |
| 592 SetIsProjecting(is_projecting); | 610 SetIsProjecting(is_projecting); |
| 593 } | 611 } |
| 594 | 612 |
| 595 void OutputConfigurator::Stop() { | 613 void OutputConfigurator::Stop() { |
| 596 configure_display_ = false; | 614 configure_display_ = false; |
| 597 } | 615 } |
| 598 | 616 |
| 599 bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state, | 617 bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state, |
| 600 bool force_probe) { | 618 int flags) { |
| 601 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayPower"); | 619 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayPower"); |
| 602 VLOG(1) << "OutputConfigurator::SetDisplayPower: power_state=" << power_state | 620 VLOG(1) << "SetDisplayPower: power_state=" |
| 603 << " force_probe=" << force_probe; | 621 << DisplayPowerStateToString(power_state) << " flags=" << flags; |
| 604 | 622 |
| 605 if (!configure_display_) | 623 if (!configure_display_) |
| 606 return false; | 624 return false; |
| 607 if (power_state == power_state_ && !force_probe) | 625 if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe)) |
| 608 return true; | 626 return true; |
| 609 | 627 |
| 610 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); | 628 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
| 611 CHECK(display); | 629 CHECK(display); |
| 612 XGrabServer(display); | 630 XGrabServer(display); |
| 613 Window window = DefaultRootWindow(display); | 631 Window window = DefaultRootWindow(display); |
| 614 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window); | 632 XRRScreenResources* screen = GetScreenResourcesAndRecordUMA(display, window); |
| 615 CHECK(screen); | 633 CHECK(screen); |
| 616 std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen); | 634 std::vector<OutputSnapshot> outputs = GetDualOutputs(display, screen); |
| 617 connected_output_count_ = outputs.size(); | 635 connected_output_count_ = outputs.size(); |
| 618 | 636 |
| 619 if (EnterState(display, screen, window, output_state_, power_state, | 637 bool only_if_single_internal_display = |
| 638 flags & kSetDisplayPowerOnlyIfSingleInternalDisplay; |
| 639 bool single_internal_display = outputs.size() == 1 && outputs[0].is_internal; |
| 640 if ((single_internal_display || !only_if_single_internal_display) && |
| 641 EnterState(display, screen, window, output_state_, power_state, |
| 620 outputs)) { | 642 outputs)) { |
| 621 power_state_ = power_state; | 643 power_state_ = power_state; |
| 622 if (power_state != DISPLAY_POWER_ALL_OFF) { | 644 if (power_state != DISPLAY_POWER_ALL_OFF) { |
| 623 // Force the DPMS on since the driver doesn't always detect that it | 645 // Force the DPMS on since the driver doesn't always detect that it |
| 624 // should turn on. This is needed when coming back from idle suspend. | 646 // should turn on. This is needed when coming back from idle suspend. |
| 625 CHECK(DPMSEnable(display)); | 647 CHECK(DPMSEnable(display)); |
| 626 CHECK(DPMSForceLevel(display, DPMSModeOn)); | 648 CHECK(DPMSForceLevel(display, DPMSModeOn)); |
| 627 } | 649 } |
| 628 } | 650 } |
| 629 | 651 |
| 630 XRRFreeScreenResources(screen); | 652 XRRFreeScreenResources(screen); |
| 631 XUngrabServer(display); | 653 XUngrabServer(display); |
| 632 | |
| 633 return true; | 654 return true; |
| 634 } | 655 } |
| 635 | 656 |
| 636 bool OutputConfigurator::SetDisplayMode(OutputState new_state) { | 657 bool OutputConfigurator::SetDisplayMode(OutputState new_state) { |
| 637 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayMode"); | 658 TRACE_EVENT0("chromeos", "OutputConfigurator::SetDisplayMode"); |
| 638 if (output_state_ == STATE_INVALID || | 659 if (output_state_ == STATE_INVALID || |
| 639 output_state_ == STATE_HEADLESS || | 660 output_state_ == STATE_HEADLESS || |
| 640 output_state_ == STATE_SINGLE) | 661 output_state_ == STATE_SINGLE) |
| 641 return false; | 662 return false; |
| 642 | 663 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 750 void OutputConfigurator::RemoveObserver(Observer* observer) { | 771 void OutputConfigurator::RemoveObserver(Observer* observer) { |
| 751 observers_.RemoveObserver(observer); | 772 observers_.RemoveObserver(observer); |
| 752 } | 773 } |
| 753 | 774 |
| 754 // static | 775 // static |
| 755 bool OutputConfigurator::IsInternalOutputName(const std::string& name) { | 776 bool OutputConfigurator::IsInternalOutputName(const std::string& name) { |
| 756 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; | 777 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; |
| 757 } | 778 } |
| 758 | 779 |
| 759 void OutputConfigurator::SuspendDisplays() { | 780 void OutputConfigurator::SuspendDisplays() { |
| 760 // Turn internal displays on before suspend. At this point, the backlight | 781 // If the display is off due to user inactivity and there's only a single |
| 761 // is off, so we turn on the internal display so that we can resume | 782 // internal display connected, switch to the all-on state before |
| 762 // directly into "on" state. This greatly reduces resume times. | 783 // suspending. This shouldn't be very noticeable to the user since the |
| 763 SetDisplayPower(DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF, false); | 784 // backlight is off at this point, and doing this lets us resume directly |
| 785 // into the "on" state, which greatly reduces resume times. |
| 786 if (power_state_ == DISPLAY_POWER_ALL_OFF) { |
| 787 SetDisplayPower(DISPLAY_POWER_ALL_ON, |
| 788 kSetDisplayPowerOnlyIfSingleInternalDisplay); |
| 789 } |
| 764 | 790 |
| 765 // We need to make sure that the monitor configuration we just did actually | 791 // We need to make sure that the monitor configuration we just did actually |
| 766 // completes before we return, because otherwise the X message could be | 792 // completes before we return, because otherwise the X message could be |
| 767 // racing with the HandleSuspendReadiness message. | 793 // racing with the HandleSuspendReadiness message. |
| 768 XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), 0); | 794 XSync(base::MessagePumpAuraX11::GetDefaultXDisplay(), 0); |
| 769 } | 795 } |
| 770 | 796 |
| 771 void OutputConfigurator::ResumeDisplays() { | 797 void OutputConfigurator::ResumeDisplays() { |
| 772 // Force probing to ensure that we pick up any changes that were made | 798 // Force probing to ensure that we pick up any changes that were made |
| 773 // while the system was suspended. | 799 // while the system was suspended. |
| 774 SetDisplayPower(DISPLAY_POWER_ALL_ON, true); | 800 SetDisplayPower(power_state_, kSetDisplayPowerForceProbe); |
| 775 } | 801 } |
| 776 | 802 |
| 777 void OutputConfigurator::NotifyOnDisplayChanged() { | 803 void OutputConfigurator::NotifyOnDisplayChanged() { |
| 778 TRACE_EVENT0("chromeos", "OutputConfigurator::NotifyOnDisplayChanged"); | 804 TRACE_EVENT0("chromeos", "OutputConfigurator::NotifyOnDisplayChanged"); |
| 779 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); | 805 FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); |
| 780 } | 806 } |
| 781 | 807 |
| 782 std::vector<OutputSnapshot> OutputConfigurator::GetDualOutputs( | 808 std::vector<OutputSnapshot> OutputConfigurator::GetDualOutputs( |
| 783 Display* display, | 809 Display* display, |
| 784 XRRScreenResources* screen) { | 810 XRRScreenResources* screen) { |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 } | 1121 } |
| 1096 | 1122 |
| 1097 bool OutputConfigurator::EnterState( | 1123 bool OutputConfigurator::EnterState( |
| 1098 Display* display, | 1124 Display* display, |
| 1099 XRRScreenResources* screen, | 1125 XRRScreenResources* screen, |
| 1100 Window window, | 1126 Window window, |
| 1101 OutputState output_state, | 1127 OutputState output_state, |
| 1102 DisplayPowerState power_state, | 1128 DisplayPowerState power_state, |
| 1103 const std::vector<OutputSnapshot>& outputs) { | 1129 const std::vector<OutputSnapshot>& outputs) { |
| 1104 TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState"); | 1130 TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState"); |
| 1131 |
| 1132 std::vector<RRCrtc> crtcs(outputs.size()); |
| 1133 std::vector<bool> output_power(outputs.size()); |
| 1134 bool all_outputs_off = true; |
| 1135 |
| 1136 RRCrtc prev_crtc = None; |
| 1137 for (size_t i = 0; i < outputs.size(); prev_crtc = crtcs[i], ++i) { |
| 1138 crtcs[i] = GetNextCrtcAfter(display, screen, outputs[i].output, prev_crtc); |
| 1139 output_power[i] = power_state == DISPLAY_POWER_ALL_ON || |
| 1140 (power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && |
| 1141 !outputs[i].is_internal) || |
| 1142 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && |
| 1143 outputs[i].is_internal); |
| 1144 if (output_power[i]) |
| 1145 all_outputs_off = false; |
| 1146 } |
| 1147 |
| 1105 switch (outputs.size()) { | 1148 switch (outputs.size()) { |
| 1106 case 0: | 1149 case 0: |
| 1107 // Do nothing as no 0-display states are supported. | 1150 // Do nothing as no 0-display states are supported. |
| 1108 break; | 1151 break; |
| 1109 case 1: { | 1152 case 1: { |
| 1110 // Re-allocate the framebuffer to fit. | 1153 // Re-allocate the framebuffer to fit. |
| 1111 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].native_mode); | 1154 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].native_mode); |
| 1112 if (mode_info == NULL) { | 1155 if (!mode_info) { |
| 1113 UMA_HISTOGRAM_COUNTS("Display.EnterState.single_failures", 1); | 1156 UMA_HISTOGRAM_COUNTS("Display.EnterState.single_failures", 1); |
| 1114 return false; | 1157 return false; |
| 1115 } | 1158 } |
| 1116 | 1159 |
| 1117 bool power_on = power_state == DISPLAY_POWER_ALL_ON || | 1160 CrtcConfig config(crtcs[0], 0, 0, |
| 1118 (power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && | 1161 output_power[0] ? outputs[0].native_mode : None, |
| 1119 !outputs[0].is_internal) || | 1162 outputs[0].output); |
| 1120 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && | |
| 1121 outputs[0].is_internal); | |
| 1122 CrtcConfig config( | |
| 1123 GetNextCrtcAfter(display, screen, outputs[0].output, None), | |
| 1124 0, 0, power_on ? outputs[0].native_mode : None, outputs[0].output); | |
| 1125 | |
| 1126 CreateFrameBuffer(display, screen, window, mode_info->width, | 1163 CreateFrameBuffer(display, screen, window, mode_info->width, |
| 1127 mode_info->height, &config, NULL); | 1164 mode_info->height, &config, NULL); |
| 1128 | |
| 1129 ConfigureCrtc(display, screen, &config); | 1165 ConfigureCrtc(display, screen, &config); |
| 1130 | 1166 if (outputs[0].touch_device_id) { |
| 1131 // Restore identity transformation for single monitor in native mode. | 1167 // Restore identity transformation for single monitor in native mode. |
| 1132 if (outputs[0].touch_device_id != None) { | 1168 ConfigureCTM(display, outputs[0].touch_device_id, |
| 1133 CoordinateTransformation ctm; // Defaults to identity | 1169 CoordinateTransformation()); |
| 1134 ConfigureCTM(display, outputs[0].touch_device_id, ctm); | |
| 1135 } | 1170 } |
| 1136 break; | 1171 break; |
| 1137 } | 1172 } |
| 1138 case 2: { | 1173 case 2: { |
| 1139 RRCrtc primary_crtc = | |
| 1140 GetNextCrtcAfter(display, screen, outputs[0].output, None); | |
| 1141 RRCrtc secondary_crtc = | |
| 1142 GetNextCrtcAfter(display, screen, outputs[1].output, primary_crtc); | |
| 1143 | |
| 1144 // Workaround for crbug.com/148365: leave internal display on for | |
| 1145 // internal-off, external-on so user can move cursor (and hence | |
| 1146 // windows) onto internal display even when it's off. | |
| 1147 bool primary_power_on = power_state == DISPLAY_POWER_ALL_ON || | |
| 1148 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && | |
| 1149 outputs[0].is_internal); | |
| 1150 bool secondary_power_on = power_state == DISPLAY_POWER_ALL_ON || | |
| 1151 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && | |
| 1152 outputs[1].is_internal); | |
| 1153 | |
| 1154 if (output_state == STATE_DUAL_MIRROR) { | 1174 if (output_state == STATE_DUAL_MIRROR) { |
| 1155 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode); | 1175 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode); |
| 1156 if (mode_info == NULL) { | 1176 if (!mode_info) { |
| 1157 UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1); | 1177 UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1); |
| 1158 return false; | 1178 return false; |
| 1159 } | 1179 } |
| 1160 | 1180 |
| 1161 CrtcConfig config1(primary_crtc, 0, 0, | 1181 std::vector<CrtcConfig> configs(outputs.size()); |
| 1162 primary_power_on ? outputs[0].mirror_mode : None, | 1182 for (size_t i = 0; i < outputs.size(); ++i) { |
| 1163 outputs[0].output); | 1183 configs[i] = CrtcConfig( |
| 1164 CrtcConfig config2(secondary_crtc, 0, 0, | 1184 crtcs[i], 0, 0, |
| 1165 secondary_power_on ? outputs[1].mirror_mode : None, | 1185 output_power[i] ? outputs[i].mirror_mode : None, |
| 1166 outputs[1].output); | 1186 outputs[i].output); |
| 1187 } |
| 1167 | 1188 |
| 1168 CreateFrameBuffer(display, screen, window, mode_info->width, | 1189 CreateFrameBuffer(display, screen, window, mode_info->width, |
| 1169 mode_info->height, &config1, &config2); | 1190 mode_info->height, &configs[0], &configs[1]); |
| 1170 | 1191 |
| 1171 ConfigureCrtc(display, screen, &config1); | 1192 for (size_t i = 0; i < outputs.size(); ++i) { |
| 1172 ConfigureCrtc(display, screen, &config2); | 1193 ConfigureCrtc(display, screen, &configs[i]); |
| 1194 if (outputs[i].touch_device_id) { |
| 1195 CoordinateTransformation ctm; |
| 1196 // CTM needs to be calculated if aspect preserving scaling is used. |
| 1197 // Otherwise, assume it is full screen, and use identity CTM. |
| 1198 if (outputs[i].mirror_mode != outputs[i].native_mode && |
| 1199 outputs[i].is_aspect_preserving_scaling) { |
| 1200 ctm = GetMirrorModeCTM(screen, &outputs[i]); |
| 1201 } |
| 1202 ConfigureCTM(display, outputs[i].touch_device_id, ctm); |
| 1203 } |
| 1204 } |
| 1205 } else { // STATE_DUAL_EXTENDED |
| 1206 std::vector<XRRModeInfo*> mode_infos(outputs.size()); |
| 1207 std::vector<CrtcConfig> configs(outputs.size()); |
| 1208 int width = 0, height = 0; |
| 1173 | 1209 |
| 1174 for (size_t i = 0; i < outputs.size(); i++) { | 1210 for (size_t i = 0; i < outputs.size(); ++i) { |
| 1175 if (outputs[i].touch_device_id == None) | 1211 mode_infos[i] = ModeInfoForID(screen, outputs[i].native_mode); |
| 1176 continue; | 1212 if (!mode_infos[i]) { |
| 1213 UMA_HISTOGRAM_COUNTS("Display.EnterState.dual_failures", 1); |
| 1214 return false; |
| 1215 } |
| 1177 | 1216 |
| 1178 CoordinateTransformation ctm; | 1217 configs[i] = CrtcConfig( |
| 1179 // CTM needs to be calculated if aspect preserving scaling is used. | 1218 crtcs[i], 0, height, |
| 1180 // Otherwise, assume it is full screen, and use identity CTM. | 1219 output_power[i] ? outputs[i].native_mode : None, |
| 1181 if (outputs[i].mirror_mode != outputs[i].native_mode && | 1220 outputs[i].output); |
| 1182 outputs[i].is_aspect_preserving_scaling) { | 1221 |
| 1183 ctm = GetMirrorModeCTM(screen, &outputs[i]); | 1222 // Retain the full screen size if all outputs are off so the same |
| 1223 // desktop configuration can be restored when the outputs are |
| 1224 // turned back on. |
| 1225 if (output_power[i] || all_outputs_off) { |
| 1226 width = std::max<int>(width, mode_infos[i]->width); |
| 1227 height += (height ? kVerticalGap : 0) + mode_infos[i]->height; |
| 1184 } | 1228 } |
| 1185 ConfigureCTM(display, outputs[i].touch_device_id, ctm); | |
| 1186 } | |
| 1187 } else { | |
| 1188 XRRModeInfo* primary_mode_info = | |
| 1189 ModeInfoForID(screen, outputs[0].native_mode); | |
| 1190 XRRModeInfo* secondary_mode_info = | |
| 1191 ModeInfoForID(screen, outputs[1].native_mode); | |
| 1192 if (primary_mode_info == NULL || secondary_mode_info == NULL) { | |
| 1193 UMA_HISTOGRAM_COUNTS("Display.EnterState.dual_failures", 1); | |
| 1194 return false; | |
| 1195 } | 1229 } |
| 1196 | 1230 |
| 1197 int primary_height = primary_mode_info->height; | 1231 CreateFrameBuffer(display, screen, window, width, height, |
| 1198 int secondary_height = secondary_mode_info->height; | 1232 &configs[0], &configs[1]); |
| 1199 CrtcConfig config1(primary_crtc, 0, 0, | |
| 1200 primary_power_on ? outputs[0].native_mode : None, | |
| 1201 outputs[0].output); | |
| 1202 CrtcConfig config2(secondary_crtc, 0, 0, | |
| 1203 secondary_power_on ? outputs[1].native_mode : None, | |
| 1204 outputs[1].output); | |
| 1205 | 1233 |
| 1206 if (output_state == STATE_DUAL_EXTENDED) | 1234 for (size_t i = 0; i < outputs.size(); ++i) { |
| 1207 config2.y = primary_height + kVerticalGap; | 1235 ConfigureCrtc(display, screen, &configs[i]); |
| 1208 else | 1236 if (outputs[i].touch_device_id) { |
| 1209 config1.y = secondary_height + kVerticalGap; | 1237 CoordinateTransformation ctm; |
| 1210 | 1238 ctm.x_scale = static_cast<float>(mode_infos[i]->width) / width; |
| 1211 int width = std::max<int>( | 1239 ctm.x_offset = static_cast<float>(configs[i].x) / width; |
| 1212 primary_mode_info->width, secondary_mode_info->width); | 1240 ctm.y_scale = static_cast<float>(mode_infos[i]->height) / height; |
| 1213 int height = primary_height + secondary_height + kVerticalGap; | 1241 ctm.y_offset = static_cast<float>(configs[i].y) / height; |
| 1214 | 1242 ConfigureCTM(display, outputs[i].touch_device_id, ctm); |
| 1215 CreateFrameBuffer(display, screen, window, width, height, &config1, | 1243 } |
| 1216 &config2); | |
| 1217 | |
| 1218 ConfigureCrtc(display, screen, &config1); | |
| 1219 ConfigureCrtc(display, screen, &config2); | |
| 1220 | |
| 1221 if (outputs[0].touch_device_id != None) { | |
| 1222 CoordinateTransformation ctm; | |
| 1223 ctm.x_scale = static_cast<float>(primary_mode_info->width) / width; | |
| 1224 ctm.x_offset = static_cast<float>(config1.x) / width; | |
| 1225 ctm.y_scale = static_cast<float>(primary_height) / height; | |
| 1226 ctm.y_offset = static_cast<float>(config1.y) / height; | |
| 1227 ConfigureCTM(display, outputs[0].touch_device_id, ctm); | |
| 1228 } | |
| 1229 if (outputs[1].touch_device_id != None) { | |
| 1230 CoordinateTransformation ctm; | |
| 1231 ctm.x_scale = static_cast<float>(secondary_mode_info->width) / | |
| 1232 width; | |
| 1233 ctm.x_offset = static_cast<float>(config2.x) / width; | |
| 1234 ctm.y_scale = static_cast<float>(secondary_height) / height; | |
| 1235 ctm.y_offset = static_cast<float>(config2.y) / height; | |
| 1236 ConfigureCTM(display, outputs[1].touch_device_id, ctm); | |
| 1237 } | 1244 } |
| 1238 } | 1245 } |
| 1239 break; | 1246 break; |
| 1240 } | 1247 } |
| 1241 default: | 1248 default: |
| 1242 CHECK(false); | 1249 NOTREACHED() << "Got " << outputs.size() << " outputs"; |
| 1243 } | 1250 } |
| 1244 | 1251 |
| 1245 RecordPreviousStateUMA(); | 1252 RecordPreviousStateUMA(); |
| 1246 | |
| 1247 return true; | 1253 return true; |
| 1248 } | 1254 } |
| 1249 | 1255 |
| 1250 void OutputConfigurator::RecordPreviousStateUMA() { | 1256 void OutputConfigurator::RecordPreviousStateUMA() { |
| 1251 base::TimeDelta duration = base::TimeTicks::Now() - last_enter_state_time_; | 1257 base::TimeDelta duration = base::TimeTicks::Now() - last_enter_state_time_; |
| 1252 | 1258 |
| 1253 // |output_state_| can be used for the state being left, | 1259 // |output_state_| can be used for the state being left, |
| 1254 // since RecordPreviousStateUMA is called from EnterState, | 1260 // since RecordPreviousStateUMA is called from EnterState, |
| 1255 // and |output_state_| is always updated after EnterState is called. | 1261 // and |output_state_| is always updated after EnterState is called. |
| 1256 switch (output_state_) { | 1262 switch (output_state_) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1332 // static | 1338 // static |
| 1333 RRMode OutputConfigurator::GetOutputNativeMode( | 1339 RRMode OutputConfigurator::GetOutputNativeMode( |
| 1334 const XRROutputInfo* output_info) { | 1340 const XRROutputInfo* output_info) { |
| 1335 if (output_info->nmode <= 0) | 1341 if (output_info->nmode <= 0) |
| 1336 return None; | 1342 return None; |
| 1337 | 1343 |
| 1338 return output_info->modes[0]; | 1344 return output_info->modes[0]; |
| 1339 } | 1345 } |
| 1340 | 1346 |
| 1341 } // namespace chromeos | 1347 } // namespace chromeos |
| OLD | NEW |