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 |