Chromium Code Reviews| 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 |