Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: chromeos/display/real_output_configurator_delegate.cc

Issue 24081004: chromeos: Fix display failures when going to mirrored mode. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix DisplayChangeObserverTest Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chromeos/display/real_output_configurator_delegate.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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/real_output_configurator_delegate.h" 5 #include "chromeos/display/real_output_configurator_delegate.h"
6 6
7 #include <X11/Xatom.h> 7 #include <X11/Xatom.h>
8 #include <X11/Xlib.h> 8 #include <X11/Xlib.h>
9 #include <X11/extensions/dpms.h> 9 #include <X11/extensions/dpms.h>
10 #include <X11/extensions/XInput.h> 10 #include <X11/extensions/XInput.h>
(...skipping 25 matching lines...) Expand all
36 36
37 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { 37 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) {
38 return output_info->nmode > 0 ? output_info->modes[0] : None; 38 return output_info->nmode > 0 ? output_info->modes[0] : None;
39 } 39 }
40 40
41 } // namespace 41 } // namespace
42 42
43 RealOutputConfiguratorDelegate::RealOutputConfiguratorDelegate() 43 RealOutputConfiguratorDelegate::RealOutputConfiguratorDelegate()
44 : display_(base::MessagePumpX11::GetDefaultXDisplay()), 44 : display_(base::MessagePumpX11::GetDefaultXDisplay()),
45 window_(DefaultRootWindow(display_)), 45 window_(DefaultRootWindow(display_)),
46 screen_(NULL), 46 screen_(NULL) {
47 is_panel_fitting_enabled_(false) {
48 } 47 }
49 48
50 RealOutputConfiguratorDelegate::~RealOutputConfiguratorDelegate() { 49 RealOutputConfiguratorDelegate::~RealOutputConfiguratorDelegate() {
51 } 50 }
52 51
53 void RealOutputConfiguratorDelegate::SetPanelFittingEnabled(bool enabled) {
54 is_panel_fitting_enabled_ = enabled;
55 }
56
57 void RealOutputConfiguratorDelegate::InitXRandRExtension(int* event_base) { 52 void RealOutputConfiguratorDelegate::InitXRandRExtension(int* event_base) {
58 int error_base_ignored = 0; 53 int error_base_ignored = 0;
59 XRRQueryExtension(display_, event_base, &error_base_ignored); 54 XRRQueryExtension(display_, event_base, &error_base_ignored);
60 } 55 }
61 56
62 void RealOutputConfiguratorDelegate::UpdateXRandRConfiguration( 57 void RealOutputConfiguratorDelegate::UpdateXRandRConfiguration(
63 const base::NativeEvent& event) { 58 const base::NativeEvent& event) {
64 XRRUpdateConfiguration(event); 59 XRRUpdateConfiguration(event);
65 } 60 }
66 61
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 XChangeWindowAttributes(display_, window_, CWBackPixel, &swa); 95 XChangeWindowAttributes(display_, window_, CWBackPixel, &swa);
101 XFreeColors(display_, colormap, &color.pixel, 1, 0); 96 XFreeColors(display_, colormap, &color.pixel, 1, 0);
102 } 97 }
103 98
104 void RealOutputConfiguratorDelegate::ForceDPMSOn() { 99 void RealOutputConfiguratorDelegate::ForceDPMSOn() {
105 CHECK(DPMSEnable(display_)); 100 CHECK(DPMSEnable(display_));
106 CHECK(DPMSForceLevel(display_, DPMSModeOn)); 101 CHECK(DPMSForceLevel(display_, DPMSModeOn));
107 } 102 }
108 103
109 std::vector<OutputConfigurator::OutputSnapshot> 104 std::vector<OutputConfigurator::OutputSnapshot>
110 RealOutputConfiguratorDelegate::GetOutputs( 105 RealOutputConfiguratorDelegate::GetOutputs() {
111 const OutputConfigurator::StateController* state_controller) {
112 CHECK(screen_) << "Server not grabbed"; 106 CHECK(screen_) << "Server not grabbed";
113 107
114 std::vector<OutputConfigurator::OutputSnapshot> outputs; 108 std::vector<OutputConfigurator::OutputSnapshot> outputs;
115 XRROutputInfo* one_info = NULL;
116 XRROutputInfo* two_info = NULL;
117 RRCrtc last_used_crtc = None; 109 RRCrtc last_used_crtc = None;
118 110
119 for (int i = 0; i < screen_->noutput && outputs.size() < 2; ++i) { 111 for (int i = 0; i < screen_->noutput && outputs.size() < 2; ++i) {
120 RROutput output_id = screen_->outputs[i]; 112 RROutput output_id = screen_->outputs[i];
121 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id); 113 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id);
122 bool is_connected = (output_info->connection == RR_Connected); 114 if (output_info->connection == RR_Connected) {
123 115 OutputConfigurator::OutputSnapshot output = InitOutputSnapshot(
124 if (!is_connected) { 116 output_id, output_info, &last_used_crtc, i);
125 XRRFreeOutputInfo(output_info); 117 VLOG(2) << "Found display " << outputs.size() << ":"
126 continue; 118 << " output=" << output.output
119 << " crtc=" << output.crtc
120 << " current_mode=" << output.current_mode;
121 outputs.push_back(output);
127 } 122 }
128 123 XRRFreeOutputInfo(output_info);
129 (outputs.empty() ? one_info : two_info) = output_info;
130
131 OutputConfigurator::OutputSnapshot output = InitOutputSnapshot(
132 output_id, output_info, &last_used_crtc, i);
133
134 if (output.has_display_id) {
135 int width = 0, height = 0;
136 if (state_controller &&
137 state_controller->GetResolutionForDisplayId(
138 output.display_id, &width, &height)) {
139 output.selected_mode =
140 FindOutputModeMatchingSize(screen_, output_info, width, height);
141 }
142 }
143 // Fall back to native mode.
144 if (output.selected_mode == None)
145 output.selected_mode = output.native_mode;
146
147 VLOG(2) << "Found display " << outputs.size() << ":"
148 << " output=" << output.output
149 << " crtc=" << output.crtc
150 << " current_mode=" << output.current_mode;
151 outputs.push_back(output);
152 }
153
154 if (outputs.size() == 2) {
155 bool one_is_internal = IsInternalOutput(one_info);
156 bool two_is_internal = IsInternalOutput(two_info);
157 int internal_outputs = (one_is_internal ? 1 : 0) +
158 (two_is_internal ? 1 : 0);
159 DCHECK_LT(internal_outputs, 2);
160 LOG_IF(WARNING, internal_outputs == 2)
161 << "Two internal outputs detected.";
162
163 bool can_mirror = false;
164 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) {
165 // Try preserving external output's aspect ratio on the first attempt.
166 // If that fails, fall back to the highest matching resolution.
167 bool preserve_aspect = attempt == 0;
168
169 if (internal_outputs == 1) {
170 if (one_is_internal) {
171 can_mirror = FindOrCreateMirrorMode(one_info, two_info,
172 outputs[0].output, is_panel_fitting_enabled_, preserve_aspect,
173 &outputs[0].mirror_mode, &outputs[1].mirror_mode);
174 } else { // if (two_is_internal)
175 can_mirror = FindOrCreateMirrorMode(two_info, one_info,
176 outputs[1].output, is_panel_fitting_enabled_, preserve_aspect,
177 &outputs[1].mirror_mode, &outputs[0].mirror_mode);
178 }
179 } else { // if (internal_outputs == 0)
180 // No panel fitting for external outputs, so fall back to exact match.
181 can_mirror = FindOrCreateMirrorMode(one_info, two_info,
182 outputs[0].output, false, preserve_aspect,
183 &outputs[0].mirror_mode, &outputs[1].mirror_mode);
184 if (!can_mirror && preserve_aspect) {
185 // FindOrCreateMirrorMode will try to preserve aspect ratio of
186 // what it thinks is external display, so if it didn't succeed
187 // with one, maybe it will succeed with the other. This way we
188 // will have correct aspect ratio on at least one of them.
189 can_mirror = FindOrCreateMirrorMode(two_info, one_info,
190 outputs[1].output, false, preserve_aspect,
191 &outputs[1].mirror_mode, &outputs[0].mirror_mode);
192 }
193 }
194 }
195 } 124 }
196 125
197 GetTouchscreens(&outputs); 126 GetTouchscreens(&outputs);
198 XRRFreeOutputInfo(one_info);
199 XRRFreeOutputInfo(two_info);
200 return outputs; 127 return outputs;
201 } 128 }
202 129
130 void RealOutputConfiguratorDelegate::AddOutputMode(RROutput output,
131 RRMode mode) {
132 CHECK(screen_) << "Server not grabbed";
133 VLOG(1) << "AddOutputMode: output=" << output << " mode=" << mode;
134 XRRAddOutputMode(display_, output, mode);
135 }
136
203 bool RealOutputConfiguratorDelegate::ConfigureCrtc( 137 bool RealOutputConfiguratorDelegate::ConfigureCrtc(
204 RRCrtc crtc, 138 RRCrtc crtc,
205 RRMode mode, 139 RRMode mode,
206 RROutput output, 140 RROutput output,
207 int x, 141 int x,
208 int y) { 142 int y) {
209 CHECK(screen_) << "Server not grabbed"; 143 CHECK(screen_) << "Server not grabbed";
210 VLOG(1) << "ConfigureCrtc: crtc=" << crtc 144 VLOG(1) << "ConfigureCrtc: crtc=" << crtc
211 << " mode=" << mode 145 << " mode=" << mode
212 << " output=" << output 146 << " output=" << output
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
284 } 218 }
285 XIFreeDeviceInfo(info); 219 XIFreeDeviceInfo(info);
286 } 220 }
287 221
288 void RealOutputConfiguratorDelegate::SendProjectingStateToPowerManager( 222 void RealOutputConfiguratorDelegate::SendProjectingStateToPowerManager(
289 bool projecting) { 223 bool projecting) {
290 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()-> 224 chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->
291 SetIsProjecting(projecting); 225 SetIsProjecting(projecting);
292 } 226 }
293 227
294 bool RealOutputConfiguratorDelegate::GetModeDetails(RRMode mode, 228 bool RealOutputConfiguratorDelegate::InitModeInfo(
295 int* width, 229 RRMode mode,
296 int* height, 230 OutputConfigurator::ModeInfo* mode_info) {
297 bool* interlaced) { 231 DCHECK(mode_info);
298 CHECK(screen_) << "Server not grabbed"; 232 CHECK(screen_) << "Server not grabbed";
299 // TODO: Determine if we need to organize modes in a way which provides 233 // TODO: Determine if we need to organize modes in a way which provides
300 // better than O(n) lookup time. In many call sites, for example, the 234 // better than O(n) lookup time. In many call sites, for example, the
301 // "next" mode is typically what we are looking for so using this 235 // "next" mode is typically what we are looking for so using this
302 // helper might be too expensive. 236 // helper might be too expensive.
303 for (int i = 0; i < screen_->nmode; ++i) { 237 for (int i = 0; i < screen_->nmode; ++i) {
304 if (mode == screen_->modes[i].id) { 238 if (mode == screen_->modes[i].id) {
305 const XRRModeInfo& info = screen_->modes[i]; 239 const XRRModeInfo& info = screen_->modes[i];
306 if (width) 240 mode_info->width = info.width;
307 *width = info.width; 241 mode_info->height = info.height;
308 if (height) 242 mode_info->interlaced = info.modeFlags & RR_Interlace;
309 *height = info.height; 243 if (info.hTotal && info.vTotal) {
310 if (interlaced) 244 mode_info->refresh_rate = static_cast<float>(info.dotClock) /
311 *interlaced = info.modeFlags & RR_Interlace; 245 (static_cast<float>(info.hTotal) *
246 static_cast<float>(info.vTotal));
247 } else {
248 mode_info->refresh_rate = 0.0f;
249 }
312 return true; 250 return true;
313 } 251 }
314 } 252 }
315 return false; 253 return false;
316 } 254 }
317 255
318 OutputConfigurator::OutputSnapshot 256 OutputConfigurator::OutputSnapshot
319 RealOutputConfiguratorDelegate::InitOutputSnapshot( 257 RealOutputConfiguratorDelegate::InitOutputSnapshot(
320 RROutput id, 258 RROutput id,
321 XRROutputInfo* info, 259 XRROutputInfo* info,
(...skipping 30 matching lines...) Expand all
352 } 290 }
353 } 291 }
354 292
355 output.native_mode = GetOutputNativeMode(info); 293 output.native_mode = GetOutputNativeMode(info);
356 output.is_aspect_preserving_scaling = IsOutputAspectPreservingScaling(id); 294 output.is_aspect_preserving_scaling = IsOutputAspectPreservingScaling(id);
357 output.touch_device_id = None; 295 output.touch_device_id = None;
358 296
359 for (int i = 0; i < info->nmode; ++i) { 297 for (int i = 0; i < info->nmode; ++i) {
360 const RRMode mode = info->modes[i]; 298 const RRMode mode = info->modes[i];
361 OutputConfigurator::ModeInfo mode_info; 299 OutputConfigurator::ModeInfo mode_info;
362 if (GetModeDetails(mode, &mode_info.width, &mode_info.height, 300 if (InitModeInfo(mode, &mode_info))
363 &mode_info.interlaced)) {
364 output.mode_infos.insert(std::make_pair(mode, mode_info)); 301 output.mode_infos.insert(std::make_pair(mode, mode_info));
365 } else { 302 else
366 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; 303 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode;
367 }
368 } 304 }
369 305
370 return output; 306 return output;
371 } 307 }
372 308
373 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( 309 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs(
374 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { 310 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
375 CHECK(screen_) << "Server not grabbed"; 311 CHECK(screen_) << "Server not grabbed";
376 // Setting the screen size will fail if any CRTC doesn't fit afterwards. 312 // Setting the screen size will fail if any CRTC doesn't fit afterwards.
377 // At the same time, turning CRTCs off and back on uses up a lot of time. 313 // At the same time, turning CRTCs off and back on uses up a lot of time.
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
451 if (values) 387 if (values)
452 XFree(values); 388 XFree(values);
453 } 389 }
454 } 390 }
455 if (props) 391 if (props)
456 XFree(props); 392 XFree(props);
457 393
458 return ret; 394 return ret;
459 } 395 }
460 396
461 bool RealOutputConfiguratorDelegate::FindOrCreateMirrorMode(
462 XRROutputInfo* internal_info,
463 XRROutputInfo* external_info,
464 RROutput internal_output_id,
465 bool try_creating,
466 bool preserve_aspect,
467 RRMode* internal_mirror_mode,
468 RRMode* external_mirror_mode) {
469 RRMode internal_mode_id = GetOutputNativeMode(internal_info);
470 RRMode external_mode_id = GetOutputNativeMode(external_info);
471
472 if (internal_mode_id == None || external_mode_id == None)
473 return false;
474
475 int internal_native_width = 0, internal_native_height = 0;
476 int external_native_width = 0, external_native_height = 0;
477 CHECK(GetModeDetails(internal_mode_id, &internal_native_width,
478 &internal_native_height, NULL));
479 CHECK(GetModeDetails(external_mode_id, &external_native_width,
480 &external_native_height, NULL));
481
482 // Check if some external output resolution can be mirrored on internal.
483 // Prefer the modes in the order that X sorts them,
484 // assuming this is the order in which they look better on the monitor.
485 // If X's order is not satisfactory, we can either fix X's sorting,
486 // or implement our sorting here.
487 for (int i = 0; i < external_info->nmode; i++) {
488 external_mode_id = external_info->modes[i];
489 int external_width = 0, external_height = 0;
490 bool is_external_interlaced = false;
491 CHECK(GetModeDetails(external_mode_id, &external_width, &external_height,
492 &is_external_interlaced));
493 bool is_native_aspect_ratio =
494 external_native_width * external_height ==
495 external_native_height * external_width;
496 if (preserve_aspect && !is_native_aspect_ratio)
497 continue; // Allow only aspect ratio preserving modes for mirroring
498
499 // Try finding exact match
500 for (int j = 0; j < internal_info->nmode; j++) {
501 internal_mode_id = internal_info->modes[j];
502 int internal_width = 0, internal_height = 0;
503 bool is_internal_interlaced = false;
504 CHECK(GetModeDetails(internal_mode_id, &internal_width,
505 &internal_height, &is_internal_interlaced));
506 if (internal_width == external_width &&
507 internal_height == external_height &&
508 is_internal_interlaced == is_external_interlaced) {
509 *internal_mirror_mode = internal_mode_id;
510 *external_mirror_mode = external_mode_id;
511 return true; // Mirror mode found
512 }
513 }
514
515 // Try to create a matching internal output mode by panel fitting
516 if (try_creating) {
517 // We can downscale by 1.125, and upscale indefinitely
518 // Downscaling looks ugly, so, can fit == can upscale
519 // Also, internal panels don't support fitting interlaced modes
520 bool can_fit =
521 internal_native_width >= external_width &&
522 internal_native_height >= external_height &&
523 !is_external_interlaced;
524 if (can_fit) {
525 XRRAddOutputMode(display_, internal_output_id, external_mode_id);
526 *internal_mirror_mode = *external_mirror_mode = external_mode_id;
527 return true; // Mirror mode created
528 }
529 }
530 }
531
532 return false;
533 }
534
535 void RealOutputConfiguratorDelegate::GetTouchscreens( 397 void RealOutputConfiguratorDelegate::GetTouchscreens(
536 std::vector<OutputConfigurator::OutputSnapshot>* outputs) { 398 std::vector<OutputConfigurator::OutputSnapshot>* outputs) {
537 int ndevices = 0; 399 int ndevices = 0;
538 Atom valuator_x = XInternAtom(display_, "Abs MT Position X", False); 400 Atom valuator_x = XInternAtom(display_, "Abs MT Position X", False);
539 Atom valuator_y = XInternAtom(display_, "Abs MT Position Y", False); 401 Atom valuator_y = XInternAtom(display_, "Abs MT Position Y", False);
540 if (valuator_x == None || valuator_y == None) 402 if (valuator_x == None || valuator_y == None)
541 return; 403 return;
542 404
543 std::set<int> no_match_touchscreen; 405 std::set<int> no_match_touchscreen;
544 XIDeviceInfo* info = XIQueryDevice(display_, XIAllDevices, &ndevices); 406 XIDeviceInfo* info = XIQueryDevice(display_, XIAllDevices, &ndevices);
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
638 << (*outputs)[i].touch_device_id << " to output #" << i; 500 << (*outputs)[i].touch_device_id << " to output #" << i;
639 break; 501 break;
640 } 502 }
641 } 503 }
642 } 504 }
643 505
644 XIFreeDeviceInfo(info); 506 XIFreeDeviceInfo(info);
645 } 507 }
646 508
647 } // namespace chromeos 509 } // namespace chromeos
OLDNEW
« no previous file with comments | « chromeos/display/real_output_configurator_delegate.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698