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 1084 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1095 } | 1095 } |
1096 | 1096 |
1097 bool OutputConfigurator::EnterState( | 1097 bool OutputConfigurator::EnterState( |
1098 Display* display, | 1098 Display* display, |
1099 XRRScreenResources* screen, | 1099 XRRScreenResources* screen, |
1100 Window window, | 1100 Window window, |
1101 OutputState output_state, | 1101 OutputState output_state, |
1102 DisplayPowerState power_state, | 1102 DisplayPowerState power_state, |
1103 const std::vector<OutputSnapshot>& outputs) { | 1103 const std::vector<OutputSnapshot>& outputs) { |
1104 TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState"); | 1104 TRACE_EVENT0("chromeos", "OutputConfigurator::EnterState"); |
1105 | |
1106 std::vector<RRCrtc> crtcs(outputs.size()); | |
1107 std::vector<bool> output_power(outputs.size()); | |
1108 bool all_outputs_off = true; | |
1109 | |
1110 RRCrtc prev_crtc = None; | |
1111 for (size_t i = 0; i < outputs.size(); prev_crtc = crtcs[i], ++i) { | |
1112 crtcs[i] = GetNextCrtcAfter(display, screen, outputs[i].output, prev_crtc); | |
1113 output_power[i] = power_state == DISPLAY_POWER_ALL_ON || | |
1114 (power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && | |
1115 !outputs[i].is_internal) || | |
1116 (power_state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && | |
1117 outputs[i].is_internal); | |
1118 if (output_power[i]) | |
1119 all_outputs_off = false; | |
1120 } | |
1121 | |
1105 switch (outputs.size()) { | 1122 switch (outputs.size()) { |
1106 case 0: | 1123 case 0: |
1107 // Do nothing as no 0-display states are supported. | 1124 // Do nothing as no 0-display states are supported. |
1108 break; | 1125 break; |
1109 case 1: { | 1126 case 1: { |
1110 // Re-allocate the framebuffer to fit. | 1127 // Re-allocate the framebuffer to fit. |
1111 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].native_mode); | 1128 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].native_mode); |
1112 if (mode_info == NULL) { | 1129 if (!mode_info) { |
1113 UMA_HISTOGRAM_COUNTS("Display.EnterState.single_failures", 1); | 1130 UMA_HISTOGRAM_COUNTS("Display.EnterState.single_failures", 1); |
1114 return false; | 1131 return false; |
1115 } | 1132 } |
1116 | 1133 |
1117 bool power_on = power_state == DISPLAY_POWER_ALL_ON || | 1134 CrtcConfig config(crtcs[0], 0, 0, |
1118 (power_state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && | 1135 output_power[0] ? outputs[0].native_mode : None, |
1119 !outputs[0].is_internal) || | 1136 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, | 1137 CreateFrameBuffer(display, screen, window, mode_info->width, |
1127 mode_info->height, &config, NULL); | 1138 mode_info->height, &config, NULL); |
1128 | |
1129 ConfigureCrtc(display, screen, &config); | 1139 ConfigureCrtc(display, screen, &config); |
1130 | 1140 if (outputs[0].touch_device_id) { |
1131 // Restore identity transformation for single monitor in native mode. | 1141 // Restore identity transformation for single monitor in native mode. |
1132 if (outputs[0].touch_device_id != None) { | 1142 ConfigureCTM(display, outputs[0].touch_device_id, |
1133 CoordinateTransformation ctm; // Defaults to identity | 1143 CoordinateTransformation()); |
1134 ConfigureCTM(display, outputs[0].touch_device_id, ctm); | |
1135 } | 1144 } |
1136 break; | 1145 break; |
1137 } | 1146 } |
1138 case 2: { | 1147 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) { | 1148 if (output_state == STATE_DUAL_MIRROR) { |
1155 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode); | 1149 XRRModeInfo* mode_info = ModeInfoForID(screen, outputs[0].mirror_mode); |
1156 if (mode_info == NULL) { | 1150 if (!mode_info) { |
1157 UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1); | 1151 UMA_HISTOGRAM_COUNTS("Display.EnterState.mirror_failures", 1); |
1158 return false; | 1152 return false; |
1159 } | 1153 } |
1160 | 1154 |
1161 CrtcConfig config1(primary_crtc, 0, 0, | 1155 std::vector<CrtcConfig> configs(outputs.size()); |
1162 primary_power_on ? outputs[0].mirror_mode : None, | 1156 for (size_t i = 0; i < outputs.size(); ++i) { |
1163 outputs[0].output); | 1157 configs[i] = CrtcConfig( |
1164 CrtcConfig config2(secondary_crtc, 0, 0, | 1158 crtcs[i], 0, 0, |
1165 secondary_power_on ? outputs[1].mirror_mode : None, | 1159 output_power[i] ? outputs[i].mirror_mode : None, |
1166 outputs[1].output); | 1160 outputs[i].output); |
1161 } | |
1167 | 1162 |
1168 CreateFrameBuffer(display, screen, window, mode_info->width, | 1163 CreateFrameBuffer(display, screen, window, mode_info->width, |
1169 mode_info->height, &config1, &config2); | 1164 mode_info->height, &configs[0], &configs[1]); |
1170 | 1165 |
1171 ConfigureCrtc(display, screen, &config1); | 1166 for (size_t i = 0; i < outputs.size(); ++i) { |
1172 ConfigureCrtc(display, screen, &config2); | 1167 ConfigureCrtc(display, screen, &configs[i]); |
1168 if (outputs[i].touch_device_id) { | |
1169 CoordinateTransformation ctm; | |
1170 // CTM needs to be calculated if aspect preserving scaling is used. | |
1171 // Otherwise, assume it is full screen, and use identity CTM. | |
1172 if (outputs[i].mirror_mode != outputs[i].native_mode && | |
1173 outputs[i].is_aspect_preserving_scaling) { | |
1174 ctm = GetMirrorModeCTM(screen, &outputs[i]); | |
1175 } | |
1176 ConfigureCTM(display, outputs[i].touch_device_id, ctm); | |
1177 } | |
1178 } | |
1179 } else { // STATE_DUAL_EXTENDED | |
1180 std::vector<XRRModeInfo*> mode_infos(outputs.size()); | |
1181 std::vector<CrtcConfig> configs(outputs.size()); | |
1182 int width = 0, height = 0; | |
1173 | 1183 |
1174 for (size_t i = 0; i < outputs.size(); i++) { | 1184 for (size_t i = 0; i < outputs.size(); ++i) { |
1175 if (outputs[i].touch_device_id == None) | 1185 mode_infos[i] = ModeInfoForID(screen, outputs[i].native_mode); |
1176 continue; | 1186 if (!mode_infos[i]) { |
1187 UMA_HISTOGRAM_COUNTS("Display.EnterState.dual_failures", 1); | |
1188 return false; | |
1189 } | |
1177 | 1190 |
1178 CoordinateTransformation ctm; | 1191 configs[i] = CrtcConfig( |
1179 // CTM needs to be calculated if aspect preserving scaling is used. | 1192 crtcs[i], 0, height, |
1180 // Otherwise, assume it is full screen, and use identity CTM. | 1193 output_power[i] ? outputs[i].native_mode : None, |
1181 if (outputs[i].mirror_mode != outputs[i].native_mode && | 1194 outputs[i].output); |
1182 outputs[i].is_aspect_preserving_scaling) { | 1195 |
1183 ctm = GetMirrorModeCTM(screen, &outputs[i]); | 1196 // Avoid ending up with 0-by-0 if all outputs are off. |
oshima
2013/03/26 23:20:31
// Keep the full screen size if all outputs are of
Daniel Erat
2013/03/26 23:23:16
Done.
| |
1197 if (output_power[i] || all_outputs_off) { | |
1198 width = std::max<int>(width, mode_infos[i]->width); | |
1199 height += (height ? kVerticalGap : 0) + mode_infos[i]->height; | |
1184 } | 1200 } |
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 } | 1201 } |
1196 | 1202 |
1197 int primary_height = primary_mode_info->height; | 1203 CreateFrameBuffer(display, screen, window, width, height, |
1198 int secondary_height = secondary_mode_info->height; | 1204 &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 | 1205 |
1206 if (output_state == STATE_DUAL_EXTENDED) | 1206 for (size_t i = 0; i < outputs.size(); ++i) { |
1207 config2.y = primary_height + kVerticalGap; | 1207 ConfigureCrtc(display, screen, &configs[i]); |
1208 else | 1208 if (outputs[i].touch_device_id) { |
1209 config1.y = secondary_height + kVerticalGap; | 1209 CoordinateTransformation ctm; |
1210 | 1210 ctm.x_scale = static_cast<float>(mode_infos[i]->width) / width; |
1211 int width = std::max<int>( | 1211 ctm.x_offset = static_cast<float>(configs[i].x) / width; |
1212 primary_mode_info->width, secondary_mode_info->width); | 1212 ctm.y_scale = static_cast<float>(mode_infos[i]->height) / height; |
1213 int height = primary_height + secondary_height + kVerticalGap; | 1213 ctm.y_offset = static_cast<float>(configs[i].y) / height; |
1214 | 1214 ConfigureCTM(display, outputs[i].touch_device_id, ctm); |
1215 CreateFrameBuffer(display, screen, window, width, height, &config1, | 1215 } |
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 } | 1216 } |
1238 } | 1217 } |
1239 break; | 1218 break; |
1240 } | 1219 } |
1241 default: | 1220 default: |
1242 CHECK(false); | 1221 NOTREACHED() << "Got " << outputs.size() << " outputs"; |
1243 } | 1222 } |
1244 | 1223 |
1245 RecordPreviousStateUMA(); | 1224 RecordPreviousStateUMA(); |
1246 | |
1247 return true; | 1225 return true; |
1248 } | 1226 } |
1249 | 1227 |
1250 void OutputConfigurator::RecordPreviousStateUMA() { | 1228 void OutputConfigurator::RecordPreviousStateUMA() { |
1251 base::TimeDelta duration = base::TimeTicks::Now() - last_enter_state_time_; | 1229 base::TimeDelta duration = base::TimeTicks::Now() - last_enter_state_time_; |
1252 | 1230 |
1253 // |output_state_| can be used for the state being left, | 1231 // |output_state_| can be used for the state being left, |
1254 // since RecordPreviousStateUMA is called from EnterState, | 1232 // since RecordPreviousStateUMA is called from EnterState, |
1255 // and |output_state_| is always updated after EnterState is called. | 1233 // and |output_state_| is always updated after EnterState is called. |
1256 switch (output_state_) { | 1234 switch (output_state_) { |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1332 // static | 1310 // static |
1333 RRMode OutputConfigurator::GetOutputNativeMode( | 1311 RRMode OutputConfigurator::GetOutputNativeMode( |
1334 const XRROutputInfo* output_info) { | 1312 const XRROutputInfo* output_info) { |
1335 if (output_info->nmode <= 0) | 1313 if (output_info->nmode <= 0) |
1336 return None; | 1314 return None; |
1337 | 1315 |
1338 return output_info->modes[0]; | 1316 return output_info->modes[0]; |
1339 } | 1317 } |
1340 | 1318 |
1341 } // namespace chromeos | 1319 } // namespace chromeos |
OLD | NEW |