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

Unified Diff: chromeos/display/output_configurator.cc

Issue 24081004: chromeos: Fix display failures when going to mirrored mode. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: uploading yet again 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 side-by-side diff with in-line comments
Download patch
Index: chromeos/display/output_configurator.cc
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
index 78cb31869d4bca60403cbc4c4909b547e95d431a..2b1d9916d430fd06179e492eaf03b384a2268cb4 100644
--- a/chromeos/display/output_configurator.cc
+++ b/chromeos/display/output_configurator.cc
@@ -101,12 +101,17 @@ bool IsProjecting(
OutputConfigurator::ModeInfo::ModeInfo()
: width(0),
height(0),
- interlaced(false) {}
+ interlaced(false),
+ refresh_rate(0.0) {}
-OutputConfigurator::ModeInfo::ModeInfo(int width, int height, bool interlaced)
+OutputConfigurator::ModeInfo::ModeInfo(int width,
+ int height,
+ bool interlaced,
+ float refresh_rate)
: width(width),
height(height),
- interlaced(interlaced) {}
+ interlaced(interlaced),
+ refresh_rate(refresh_rate) {}
OutputConfigurator::CoordinateTransformation::CoordinateTransformation()
: x_scale(1.0),
@@ -172,7 +177,7 @@ const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo(
if (mode == None)
return NULL;
- std::map<RRMode, ModeInfo>::const_iterator it = output.mode_infos.find(mode);
+ ModeInfoMap::const_iterator it = output.mode_infos.find(mode);
if (it == output.mode_infos.end()) {
LOG(WARNING) << "Unable to find info about mode " << mode
<< " for output " << output.output;
@@ -181,9 +186,44 @@ const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo(
return &it->second;
}
+// static
+RRMode OutputConfigurator::FindOutputModeMatchingSize(
+ const OutputSnapshot& output,
+ int width,
+ int height) {
+ RRMode found = None;
+ float best_rate = 0;
+ bool non_interlaced_found = false;
+ for (ModeInfoMap::const_iterator it = output.mode_infos.begin();
+ it != output.mode_infos.end(); ++it) {
+ RRMode mode = it->first;
+ const ModeInfo& info = it->second;
+
+ if (info.width == width && info.height == height) {
+ if (info.interlaced) {
+ if (non_interlaced_found)
+ continue;
+ } else {
+ // Reset the best rate if the non interlaced is
+ // found the first time.
+ if (!non_interlaced_found)
+ best_rate = info.refresh_rate;
+ non_interlaced_found = true;
+ }
+ if (info.refresh_rate < best_rate)
+ continue;
+
+ found = mode;
+ best_rate = info.refresh_rate;
+ }
+ }
+ return found;
+}
+
OutputConfigurator::OutputConfigurator()
: state_controller_(NULL),
mirroring_controller_(NULL),
+ is_panel_fitting_enabled_(false),
configure_display_(base::chromeos::IsRunningOnChromeOS()),
xrandr_event_base_(0),
output_state_(STATE_INVALID),
@@ -203,12 +243,12 @@ void OutputConfigurator::SetInitialDisplayPower(DisplayPowerState power_state) {
}
void OutputConfigurator::Init(bool is_panel_fitting_enabled) {
+ is_panel_fitting_enabled_ = is_panel_fitting_enabled;
if (!configure_display_)
return;
if (!delegate_)
delegate_.reset(new RealOutputConfiguratorDelegate());
- delegate_->SetPanelFittingEnabled(is_panel_fitting_enabled);
}
void OutputConfigurator::Start(uint32 background_color_argb) {
@@ -218,8 +258,7 @@ void OutputConfigurator::Start(uint32 background_color_argb) {
delegate_->GrabServer();
delegate_->InitXRandRExtension(&xrandr_event_base_);
- std::vector<OutputSnapshot> outputs =
- delegate_->GetOutputs(state_controller_);
+ std::vector<OutputSnapshot> outputs = GetOutputs();
if (outputs.size() > 1 && background_color_argb)
delegate_->SetBackgroundColor(background_color_argb);
const OutputState new_state = GetOutputState(outputs, power_state_);
@@ -249,8 +288,7 @@ bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state,
return true;
delegate_->GrabServer();
- std::vector<OutputSnapshot> outputs =
- delegate_->GetOutputs(state_controller_);
+ std::vector<OutputSnapshot> outputs = GetOutputs();
const OutputState new_state = GetOutputState(outputs, power_state);
bool attempted_change = false;
@@ -291,8 +329,7 @@ bool OutputConfigurator::SetDisplayMode(OutputState new_state) {
}
delegate_->GrabServer();
- std::vector<OutputSnapshot> outputs =
- delegate_->GetOutputs(state_controller_);
+ std::vector<OutputSnapshot> outputs = GetOutputs();
const bool success = EnterStateOrFallBackToSoftwareMirroring(
new_state, power_state_, outputs);
delegate_->UngrabServer();
@@ -418,12 +455,138 @@ void OutputConfigurator::ScheduleConfigureOutputs() {
}
}
+std::vector<OutputConfigurator::OutputSnapshot>
+OutputConfigurator::GetOutputs() {
+ std::vector<OutputSnapshot> outputs = delegate_->GetOutputs();
+
+ // Set |selected_mode| fields.
+ for (size_t i = 0; i < outputs.size(); ++i) {
+ OutputSnapshot* output = &outputs[i];
+ if (output->has_display_id) {
+ int width = 0, height = 0;
+ if (state_controller_ &&
+ state_controller_->GetResolutionForDisplayId(
+ output->display_id, &width, &height)) {
+ output->selected_mode =
+ FindOutputModeMatchingSize(*output, width, height);
+ }
+ }
+ // Fall back to native mode.
+ if (output->selected_mode == None)
+ output->selected_mode = output->native_mode;
+ }
+
+ // Set |mirror_mode| fields.
+ if (outputs.size() == 2) {
+ bool one_is_internal = outputs[0].is_internal;
+ bool two_is_internal = outputs[1].is_internal;
+ int internal_outputs = (one_is_internal ? 1 : 0) +
+ (two_is_internal ? 1 : 0);
+ DCHECK_LT(internal_outputs, 2);
+ LOG_IF(WARNING, internal_outputs == 2)
+ << "Two internal outputs detected.";
+
+ bool can_mirror = false;
+ for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) {
+ // Try preserving external output's aspect ratio on the first attempt.
+ // If that fails, fall back to the highest matching resolution.
+ bool preserve_aspect = attempt == 0;
+
+ if (internal_outputs == 1) {
+ if (one_is_internal) {
+ can_mirror = FindOrCreateMirrorMode(&outputs[0], &outputs[1],
+ is_panel_fitting_enabled_, preserve_aspect);
+ } else {
+ DCHECK(two_is_internal);
+ can_mirror = FindOrCreateMirrorMode(&outputs[1], &outputs[0],
+ is_panel_fitting_enabled_, preserve_aspect);
+ }
+ } else { // if (internal_outputs == 0)
+ // No panel fitting for external outputs, so fall back to exact match.
+ can_mirror = FindOrCreateMirrorMode(&outputs[0], &outputs[1], false,
+ preserve_aspect);
+ if (!can_mirror && preserve_aspect) {
+ // FindOrCreateMirrorMode will try to preserve aspect ratio of
+ // what it thinks is external display, so if it didn't succeed
+ // with one, maybe it will succeed with the other. This way we
+ // will have the correct aspect ratio on at least one of them.
+ can_mirror = FindOrCreateMirrorMode(&outputs[1], &outputs[0],
+ false, preserve_aspect);
+ }
+ }
+ }
+ }
+
+ return outputs;
+}
+
+bool OutputConfigurator::FindOrCreateMirrorMode(
+ OutputSnapshot* internal_output,
+ OutputSnapshot* external_output,
+ bool try_creating,
+ bool preserve_aspect) {
+ const ModeInfo* internal_native_info =
+ GetModeInfo(*internal_output, internal_output->native_mode);
+ const ModeInfo* external_native_info =
+ GetModeInfo(*external_output, external_output->native_mode);
+ if (!internal_native_info || !external_native_info)
+ return false;
+
+ // Check if some external output resolution can be mirrored on internal.
+ // Prefer the modes in the order that X sorts them, assuming this is the order
+ // in which they look better on the monitor.
+ for (ModeInfoMap::const_iterator external_it =
+ external_output->mode_infos.begin();
+ external_it != external_output->mode_infos.end(); ++external_it) {
+ const ModeInfo& external_info = external_it->second;
+ bool is_native_aspect_ratio =
+ external_native_info->width * external_info.height ==
+ external_native_info->height * external_info.width;
+ if (preserve_aspect && !is_native_aspect_ratio)
+ continue; // Allow only aspect ratio preserving modes for mirroring.
+
+ // Try finding an exact match.
+ for (ModeInfoMap::const_iterator internal_it =
+ internal_output->mode_infos.begin();
+ internal_it != internal_output->mode_infos.end(); ++internal_it) {
+ const ModeInfo& internal_info = internal_it->second;
+ if (internal_info.width == external_info.width &&
+ internal_info.height == external_info.height &&
+ internal_info.interlaced == external_info.interlaced) {
+ internal_output->mirror_mode = internal_it->first;
+ external_output->mirror_mode = external_it->first;
+ return true; // Mirror mode found.
+ }
+ }
+
+ // Try to create a matching internal output mode by panel fitting.
+ if (try_creating) {
+ // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
+ // ugly, so, can fit == can upscale. Also, internal panels don't support
+ // fitting interlaced modes.
+ bool can_fit =
+ internal_native_info->width >= external_info.width &&
+ internal_native_info->height >= external_info.height &&
+ !external_info.interlaced;
+ if (can_fit) {
+ RRMode mode = external_it->first;
+ delegate_->AddOutputMode(internal_output->output, mode);
+ internal_output->mode_infos.insert(std::make_pair(mode, external_info));
Daniel Erat 2013/09/17 15:53:27 (Side note: Apart from this line, which is the act
+ internal_output->mirror_mode = mode;
+ external_output->mirror_mode = mode;
+ return true; // Mirror mode created.
+ }
+ }
+ }
+
+ return false;
+}
+
void OutputConfigurator::ConfigureOutputs() {
configure_timer_.reset();
delegate_->GrabServer();
- std::vector<OutputSnapshot> outputs =
- delegate_->GetOutputs(state_controller_);
+ std::vector<OutputSnapshot> outputs = GetOutputs();
const OutputState new_state = GetOutputState(outputs, power_state_);
const bool success = EnterStateOrFallBackToSoftwareMirroring(
new_state, power_state_, outputs);

Powered by Google App Engine
This is Rietveld 408576698