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

Unified Diff: chromeos/display/output_configurator.cc

Issue 192483007: Move chromeos/display/* to ui/display/chromeos (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Include display.gyp into ChromeOS builds only Created 6 years, 9 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
« no previous file with comments | « chromeos/display/output_configurator.h ('k') | chromeos/display/output_configurator_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chromeos/display/output_configurator.cc
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc
deleted file mode 100644
index bc6124815ce0aeef3a7a47bdcde20e7086602deb..0000000000000000000000000000000000000000
--- a/chromeos/display/output_configurator.cc
+++ /dev/null
@@ -1,1053 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chromeos/display/output_configurator.h"
-
-#include <X11/Xlib.h>
-#include <X11/extensions/Xrandr.h>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/sys_info.h"
-#include "base/time/time.h"
-#include "chromeos/display/native_display_delegate_x11.h"
-#include "chromeos/display/output_util.h"
-#include "chromeos/display/touchscreen_delegate_x11.h"
-
-namespace chromeos {
-
-namespace {
-
-// The delay to perform configuration after RRNotify. See the comment
-// in |Dispatch()|.
-const int64 kConfigureDelayMs = 500;
-
-// Returns a string describing |state|.
-std::string DisplayPowerStateToString(DisplayPowerState state) {
- switch (state) {
- case DISPLAY_POWER_ALL_ON:
- return "ALL_ON";
- case DISPLAY_POWER_ALL_OFF:
- return "ALL_OFF";
- case DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON:
- return "INTERNAL_OFF_EXTERNAL_ON";
- case DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF:
- return "INTERNAL_ON_EXTERNAL_OFF";
- default:
- return "unknown (" + base::IntToString(state) + ")";
- }
-}
-
-// Returns a string describing |state|.
-std::string OutputStateToString(ui::OutputState state) {
- switch (state) {
- case ui::OUTPUT_STATE_INVALID:
- return "INVALID";
- case ui::OUTPUT_STATE_HEADLESS:
- return "HEADLESS";
- case ui::OUTPUT_STATE_SINGLE:
- return "SINGLE";
- case ui::OUTPUT_STATE_DUAL_MIRROR:
- return "DUAL_MIRROR";
- case ui::OUTPUT_STATE_DUAL_EXTENDED:
- return "DUAL_EXTENDED";
- }
- NOTREACHED() << "Unknown state " << state;
- return "INVALID";
-}
-
-// Returns a string representation of OutputSnapshot.
-std::string OutputSnapshotToString(
- const OutputConfigurator::OutputSnapshot* output) {
- return base::StringPrintf(
- "[type=%d, output=%ld, crtc=%ld, mode=%ld, dim=%dx%d]",
- output->type,
- output->output,
- output->crtc,
- output->current_mode,
- static_cast<int>(output->width_mm),
- static_cast<int>(output->height_mm));
-}
-
-// Returns a string representation of ModeInfo.
-std::string ModeInfoToString(const OutputConfigurator::ModeInfo* mode) {
- return base::StringPrintf("[%dx%d %srate=%f]",
- mode->width,
- mode->height,
- mode->interlaced ? "interlaced " : "",
- mode->refresh_rate);
-
-}
-
-// Returns the number of outputs in |outputs| that should be turned on, per
-// |state|. If |output_power| is non-NULL, it is updated to contain the
-// on/off state of each corresponding entry in |outputs|.
-int GetOutputPower(
- const std::vector<OutputConfigurator::OutputSnapshot>& outputs,
- DisplayPowerState state,
- std::vector<bool>* output_power) {
- int num_on_outputs = 0;
- if (output_power)
- output_power->resize(outputs.size());
-
- for (size_t i = 0; i < outputs.size(); ++i) {
- bool internal = outputs[i].type == ui::OUTPUT_TYPE_INTERNAL;
- bool on = state == DISPLAY_POWER_ALL_ON ||
- (state == DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON && !internal) ||
- (state == DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF && internal);
- if (output_power)
- (*output_power)[i] = on;
- if (on)
- num_on_outputs++;
- }
- return num_on_outputs;
-}
-
-} // namespace
-
-OutputConfigurator::ModeInfo::ModeInfo()
- : width(0),
- height(0),
- interlaced(false),
- refresh_rate(0.0) {}
-
-OutputConfigurator::ModeInfo::ModeInfo(int width,
- int height,
- bool interlaced,
- float refresh_rate)
- : width(width),
- height(height),
- interlaced(interlaced),
- refresh_rate(refresh_rate) {}
-
-OutputConfigurator::CoordinateTransformation::CoordinateTransformation()
- : x_scale(1.0),
- x_offset(0.0),
- y_scale(1.0),
- y_offset(0.0) {}
-
-OutputConfigurator::OutputSnapshot::OutputSnapshot()
- : output(None),
- crtc(None),
- current_mode(None),
- native_mode(None),
- mirror_mode(None),
- selected_mode(None),
- x(0),
- y(0),
- width_mm(0),
- height_mm(0),
- is_aspect_preserving_scaling(false),
- type(ui::OUTPUT_TYPE_UNKNOWN),
- touch_device_id(0),
- display_id(0),
- has_display_id(false),
- index(0) {}
-
-OutputConfigurator::OutputSnapshot::~OutputSnapshot() {}
-
-bool OutputConfigurator::TestApi::TriggerConfigureTimeout() {
- if (configurator_->configure_timer_.get() &&
- configurator_->configure_timer_->IsRunning()) {
- configurator_->configure_timer_.reset();
- configurator_->ConfigureOutputs();
- return true;
- } else {
- return false;
- }
-}
-
-// static
-const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo(
- const OutputSnapshot& output,
- RRMode mode) {
- if (mode == None)
- return NULL;
-
- 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;
- return NULL;
- }
- 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::SysInfo::IsRunningOnChromeOS()),
- output_state_(ui::OUTPUT_STATE_INVALID),
- power_state_(DISPLAY_POWER_ALL_ON),
- next_output_protection_client_id_(1) {}
-
-OutputConfigurator::~OutputConfigurator() {
- if (native_display_delegate_)
- native_display_delegate_->RemoveObserver(this);
-}
-
-void OutputConfigurator::SetNativeDisplayDelegateForTesting(
- scoped_ptr<NativeDisplayDelegate> delegate) {
- DCHECK(!native_display_delegate_);
-
- native_display_delegate_ = delegate.Pass();
- native_display_delegate_->AddObserver(this);
- configure_display_ = true;
-}
-
-void OutputConfigurator::SetTouchscreenDelegateForTesting(
- scoped_ptr<TouchscreenDelegate> delegate) {
- DCHECK(!touchscreen_delegate_);
-
- touchscreen_delegate_ = delegate.Pass();
-}
-
-void OutputConfigurator::SetInitialDisplayPower(DisplayPowerState power_state) {
- DCHECK_EQ(output_state_, ui::OUTPUT_STATE_INVALID);
- power_state_ = power_state;
-}
-
-void OutputConfigurator::Init(bool is_panel_fitting_enabled) {
- is_panel_fitting_enabled_ = is_panel_fitting_enabled;
- if (!configure_display_)
- return;
-
- if (!native_display_delegate_) {
- native_display_delegate_.reset(new NativeDisplayDelegateX11());
- native_display_delegate_->AddObserver(this);
- }
-
- if (!touchscreen_delegate_)
- touchscreen_delegate_.reset(new TouchscreenDelegateX11());
-}
-
-void OutputConfigurator::ForceInitialConfigure(uint32 background_color_argb) {
- if (!configure_display_)
- return;
-
- native_display_delegate_->GrabServer();
- native_display_delegate_->Initialize();
-
- UpdateCachedOutputs();
- if (cached_outputs_.size() > 1 && background_color_argb)
- native_display_delegate_->SetBackgroundColor(background_color_argb);
- const ui::OutputState new_state = ChooseOutputState(power_state_);
- const bool success = EnterStateOrFallBackToSoftwareMirroring(
- new_state, power_state_);
-
- // Force the DPMS on chrome startup as the driver doesn't always detect
- // that all displays are on when signing out.
- native_display_delegate_->ForceDPMSOn();
- native_display_delegate_->UngrabServer();
- NotifyObservers(success, new_state);
-}
-
-bool OutputConfigurator::ApplyProtections(const DisplayProtections& requests) {
- for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin();
- it != cached_outputs_.end(); ++it) {
- uint32_t all_desired = 0;
- DisplayProtections::const_iterator request_it = requests.find(
- it->display_id);
- if (request_it != requests.end())
- all_desired = request_it->second;
- switch (it->type) {
- case ui::OUTPUT_TYPE_UNKNOWN:
- return false;
- // DisplayPort, DVI, and HDMI all support HDCP.
- case ui::OUTPUT_TYPE_DISPLAYPORT:
- case ui::OUTPUT_TYPE_DVI:
- case ui::OUTPUT_TYPE_HDMI: {
- ui::HDCPState new_desired_state =
- (all_desired & ui::OUTPUT_PROTECTION_METHOD_HDCP)
- ? ui::HDCP_STATE_DESIRED
- : ui::HDCP_STATE_UNDESIRED;
- if (!native_display_delegate_->SetHDCPState(*it, new_desired_state))
- return false;
- break;
- }
- case ui::OUTPUT_TYPE_INTERNAL:
- case ui::OUTPUT_TYPE_VGA:
- case ui::OUTPUT_TYPE_NETWORK:
- // No protections for these types. Do nothing.
- break;
- case ui::OUTPUT_TYPE_NONE:
- NOTREACHED();
- break;
- }
- }
-
- return true;
-}
-
-OutputConfigurator::OutputProtectionClientId
-OutputConfigurator::RegisterOutputProtectionClient() {
- if (!configure_display_)
- return kInvalidClientId;
-
- return next_output_protection_client_id_++;
-}
-
-void OutputConfigurator::UnregisterOutputProtectionClient(
- OutputProtectionClientId client_id) {
- client_protection_requests_.erase(client_id);
-
- DisplayProtections protections;
- for (ProtectionRequests::const_iterator it =
- client_protection_requests_.begin();
- it != client_protection_requests_.end();
- ++it) {
- for (DisplayProtections::const_iterator it2 = it->second.begin();
- it2 != it->second.end(); ++it2) {
- protections[it2->first] |= it2->second;
- }
- }
-
- ApplyProtections(protections);
-}
-
-bool OutputConfigurator::QueryOutputProtectionStatus(
- OutputProtectionClientId client_id,
- int64 display_id,
- uint32_t* link_mask,
- uint32_t* protection_mask) {
- if (!configure_display_)
- return false;
-
- uint32_t enabled = 0;
- uint32_t unfulfilled = 0;
- *link_mask = 0;
- for (std::vector<OutputSnapshot>::const_iterator it = cached_outputs_.begin();
- it != cached_outputs_.end(); ++it) {
- if (it->display_id != display_id)
- continue;
- *link_mask |= it->type;
- switch (it->type) {
- case ui::OUTPUT_TYPE_UNKNOWN:
- return false;
- // DisplayPort, DVI, and HDMI all support HDCP.
- case ui::OUTPUT_TYPE_DISPLAYPORT:
- case ui::OUTPUT_TYPE_DVI:
- case ui::OUTPUT_TYPE_HDMI: {
- ui::HDCPState state;
- if (!native_display_delegate_->GetHDCPState(*it, &state))
- return false;
- if (state == ui::HDCP_STATE_ENABLED)
- enabled |= ui::OUTPUT_PROTECTION_METHOD_HDCP;
- else
- unfulfilled |= ui::OUTPUT_PROTECTION_METHOD_HDCP;
- break;
- }
- case ui::OUTPUT_TYPE_INTERNAL:
- case ui::OUTPUT_TYPE_VGA:
- case ui::OUTPUT_TYPE_NETWORK:
- // No protections for these types. Do nothing.
- break;
- case ui::OUTPUT_TYPE_NONE:
- NOTREACHED();
- break;
- }
- }
-
- // Don't reveal protections requested by other clients.
- ProtectionRequests::iterator it = client_protection_requests_.find(client_id);
- if (it != client_protection_requests_.end()) {
- uint32_t requested_mask = 0;
- if (it->second.find(display_id) != it->second.end())
- requested_mask = it->second[display_id];
- *protection_mask = enabled & ~unfulfilled & requested_mask;
- } else {
- *protection_mask = 0;
- }
- return true;
-}
-
-bool OutputConfigurator::EnableOutputProtection(
- OutputProtectionClientId client_id,
- int64 display_id,
- uint32_t desired_method_mask) {
- if (!configure_display_)
- return false;
-
- DisplayProtections protections;
- for (ProtectionRequests::const_iterator it =
- client_protection_requests_.begin();
- it != client_protection_requests_.end();
- ++it) {
- for (DisplayProtections::const_iterator it2 = it->second.begin();
- it2 != it->second.end(); ++it2) {
- if (it->first == client_id && it2->first == display_id)
- continue;
- protections[it2->first] |= it2->second;
- }
- }
- protections[display_id] |= desired_method_mask;
-
- if (!ApplyProtections(protections))
- return false;
-
- if (desired_method_mask == ui::OUTPUT_PROTECTION_METHOD_NONE) {
- if (client_protection_requests_.find(client_id) !=
- client_protection_requests_.end()) {
- client_protection_requests_[client_id].erase(display_id);
- if (client_protection_requests_[client_id].size() == 0)
- client_protection_requests_.erase(client_id);
- }
- } else {
- client_protection_requests_[client_id][display_id] = desired_method_mask;
- }
-
- return true;
-}
-
-void OutputConfigurator::PrepareForExit() {
- configure_display_ = false;
-}
-
-bool OutputConfigurator::SetDisplayPower(DisplayPowerState power_state,
- int flags) {
- if (!configure_display_)
- return false;
-
- VLOG(1) << "SetDisplayPower: power_state="
- << DisplayPowerStateToString(power_state) << " flags=" << flags
- << ", configure timer="
- << ((configure_timer_.get() && configure_timer_->IsRunning()) ?
- "Running" : "Stopped");
- if (power_state == power_state_ && !(flags & kSetDisplayPowerForceProbe))
- return true;
-
- native_display_delegate_->GrabServer();
- UpdateCachedOutputs();
-
- const ui::OutputState new_state = ChooseOutputState(power_state);
- bool attempted_change = false;
- bool success = false;
-
- bool only_if_single_internal_display =
- flags & kSetDisplayPowerOnlyIfSingleInternalDisplay;
- bool single_internal_display =
- cached_outputs_.size() == 1 &&
- cached_outputs_[0].type == ui::OUTPUT_TYPE_INTERNAL;
- if (single_internal_display || !only_if_single_internal_display) {
- success = EnterStateOrFallBackToSoftwareMirroring(new_state, power_state);
- attempted_change = true;
-
- // Force the DPMS on since the driver doesn't always detect that it
- // should turn on. This is needed when coming back from idle suspend.
- if (success && power_state != DISPLAY_POWER_ALL_OFF)
- native_display_delegate_->ForceDPMSOn();
- }
-
- native_display_delegate_->UngrabServer();
- if (attempted_change)
- NotifyObservers(success, new_state);
- return true;
-}
-
-bool OutputConfigurator::SetDisplayMode(ui::OutputState new_state) {
- if (!configure_display_)
- return false;
-
- VLOG(1) << "SetDisplayMode: state=" << OutputStateToString(new_state);
- if (output_state_ == new_state) {
- // Cancel software mirroring if the state is moving from
- // OUTPUT_STATE_DUAL_EXTENDED to OUTPUT_STATE_DUAL_EXTENDED.
- if (mirroring_controller_ && new_state == ui::OUTPUT_STATE_DUAL_EXTENDED)
- mirroring_controller_->SetSoftwareMirroring(false);
- NotifyObservers(true, new_state);
- return true;
- }
-
- native_display_delegate_->GrabServer();
- UpdateCachedOutputs();
- const bool success = EnterStateOrFallBackToSoftwareMirroring(
- new_state, power_state_);
- native_display_delegate_->UngrabServer();
-
- NotifyObservers(success, new_state);
- return success;
-}
-
-void OutputConfigurator::OnConfigurationChanged() {
- // Configure outputs with |kConfigureDelayMs| delay,
- // so that time-consuming ConfigureOutputs() won't be called multiple times.
- if (configure_timer_.get()) {
- configure_timer_->Reset();
- } else {
- configure_timer_.reset(new base::OneShotTimer<OutputConfigurator>());
- configure_timer_->Start(
- FROM_HERE,
- base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
- this,
- &OutputConfigurator::ConfigureOutputs);
- }
-}
-
-void OutputConfigurator::AddObserver(Observer* observer) {
- observers_.AddObserver(observer);
-}
-
-void OutputConfigurator::RemoveObserver(Observer* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void OutputConfigurator::SuspendDisplays() {
- // If the display is off due to user inactivity and there's only a single
- // internal display connected, switch to the all-on state before
- // suspending. This shouldn't be very noticeable to the user since the
- // backlight is off at this point, and doing this lets us resume directly
- // into the "on" state, which greatly reduces resume times.
- if (power_state_ == DISPLAY_POWER_ALL_OFF) {
- SetDisplayPower(DISPLAY_POWER_ALL_ON,
- kSetDisplayPowerOnlyIfSingleInternalDisplay);
-
- // We need to make sure that the monitor configuration we just did actually
- // completes before we return, because otherwise the X message could be
- // racing with the HandleSuspendReadiness message.
- native_display_delegate_->SyncWithServer();
- }
-}
-
-void OutputConfigurator::ResumeDisplays() {
- // Force probing to ensure that we pick up any changes that were made
- // while the system was suspended.
- SetDisplayPower(power_state_, kSetDisplayPowerForceProbe);
-}
-
-void OutputConfigurator::UpdateCachedOutputs() {
- cached_outputs_ = native_display_delegate_->GetOutputs();
- touchscreen_delegate_->AssociateTouchscreens(&cached_outputs_);
-
- // Set |selected_mode| fields.
- for (size_t i = 0; i < cached_outputs_.size(); ++i) {
- OutputSnapshot* output = &cached_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 (cached_outputs_.size() == 2) {
- bool one_is_internal = cached_outputs_[0].type == ui::OUTPUT_TYPE_INTERNAL;
- bool two_is_internal = cached_outputs_[1].type == ui::OUTPUT_TYPE_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 = FindMirrorMode(&cached_outputs_[0], &cached_outputs_[1],
- is_panel_fitting_enabled_, preserve_aspect);
- } else {
- DCHECK(two_is_internal);
- can_mirror = FindMirrorMode(&cached_outputs_[1], &cached_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 = FindMirrorMode(&cached_outputs_[0], &cached_outputs_[1],
- false, preserve_aspect);
- if (!can_mirror && preserve_aspect) {
- // FindMirrorMode() 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 = FindMirrorMode(&cached_outputs_[1], &cached_outputs_[0],
- false, preserve_aspect);
- }
- }
- }
- }
-}
-
-bool OutputConfigurator::FindMirrorMode(OutputSnapshot* internal_output,
- OutputSnapshot* external_output,
- bool try_panel_fitting,
- 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_panel_fitting) {
- // 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;
- native_display_delegate_->AddMode(*internal_output, mode);
- internal_output->mode_infos.insert(std::make_pair(mode, external_info));
- internal_output->mirror_mode = mode;
- external_output->mirror_mode = mode;
- return true; // Mirror mode created.
- }
- }
- }
-
- return false;
-}
-
-void OutputConfigurator::ConfigureOutputs() {
- configure_timer_.reset();
-
- if (!configure_display_)
- return;
-
- native_display_delegate_->GrabServer();
- UpdateCachedOutputs();
- const ui::OutputState new_state = ChooseOutputState(power_state_);
- const bool success = EnterStateOrFallBackToSoftwareMirroring(
- new_state, power_state_);
- native_display_delegate_->UngrabServer();
-
- NotifyObservers(success, new_state);
-}
-
-void OutputConfigurator::NotifyObservers(bool success,
- ui::OutputState attempted_state) {
- if (success) {
- FOR_EACH_OBSERVER(Observer, observers_,
- OnDisplayModeChanged(cached_outputs_));
- } else {
- FOR_EACH_OBSERVER(Observer, observers_,
- OnDisplayModeChangeFailed(attempted_state));
- }
-}
-
-bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring(
- ui::OutputState output_state,
- DisplayPowerState power_state) {
- bool success = EnterState(output_state, power_state);
- if (mirroring_controller_) {
- bool enable_software_mirroring = false;
- if (!success && output_state == ui::OUTPUT_STATE_DUAL_MIRROR) {
- if (output_state_ != ui::OUTPUT_STATE_DUAL_EXTENDED ||
- power_state_ != power_state)
- EnterState(ui::OUTPUT_STATE_DUAL_EXTENDED, power_state);
- enable_software_mirroring = success =
- output_state_ == ui::OUTPUT_STATE_DUAL_EXTENDED;
- }
- mirroring_controller_->SetSoftwareMirroring(enable_software_mirroring);
- }
- return success;
-}
-
-bool OutputConfigurator::EnterState(ui::OutputState output_state,
- DisplayPowerState power_state) {
- std::vector<bool> output_power;
- int num_on_outputs = GetOutputPower(
- cached_outputs_, power_state, &output_power);
- VLOG(1) << "EnterState: output=" << OutputStateToString(output_state)
- << " power=" << DisplayPowerStateToString(power_state);
-
- // Framebuffer dimensions.
- int width = 0, height = 0;
- std::vector<OutputSnapshot> updated_outputs = cached_outputs_;
-
- switch (output_state) {
- case ui::OUTPUT_STATE_INVALID:
- NOTREACHED() << "Ignoring request to enter invalid state with "
- << updated_outputs.size() << " connected output(s)";
- return false;
- case ui::OUTPUT_STATE_HEADLESS:
- if (updated_outputs.size() != 0) {
- LOG(WARNING) << "Ignoring request to enter headless mode with "
- << updated_outputs.size() << " connected output(s)";
- return false;
- }
- break;
- case ui::OUTPUT_STATE_SINGLE: {
- // If there are multiple outputs connected, only one should be turned on.
- if (updated_outputs.size() != 1 && num_on_outputs != 1) {
- LOG(WARNING) << "Ignoring request to enter single mode with "
- << updated_outputs.size() << " connected outputs and "
- << num_on_outputs << " turned on";
- return false;
- }
-
- for (size_t i = 0; i < updated_outputs.size(); ++i) {
- OutputSnapshot* output = &updated_outputs[i];
- output->x = 0;
- output->y = 0;
- output->current_mode = output_power[i] ? output->selected_mode : None;
-
- if (output_power[i] || updated_outputs.size() == 1) {
- const ModeInfo* mode_info =
- GetModeInfo(*output, output->selected_mode);
- if (!mode_info)
- return false;
- if (mode_info->width == 1024 && mode_info->height == 768) {
- VLOG(1) << "Potentially misdetecting display(1024x768):"
- << " outputs size=" << updated_outputs.size()
- << ", num_on_outputs=" << num_on_outputs
- << ", current size:" << width << "x" << height
- << ", i=" << i
- << ", output=" << OutputSnapshotToString(output)
- << ", mode_info=" << ModeInfoToString(mode_info);
- }
- width = mode_info->width;
- height = mode_info->height;
- }
- }
- break;
- }
- case ui::OUTPUT_STATE_DUAL_MIRROR: {
- if (updated_outputs.size() != 2 ||
- (num_on_outputs != 0 && num_on_outputs != 2)) {
- LOG(WARNING) << "Ignoring request to enter mirrored mode with "
- << updated_outputs.size() << " connected output(s) and "
- << num_on_outputs << " turned on";
- return false;
- }
-
- if (!updated_outputs[0].mirror_mode)
- return false;
- const ModeInfo* mode_info =
- GetModeInfo(updated_outputs[0], updated_outputs[0].mirror_mode);
- if (!mode_info)
- return false;
- width = mode_info->width;
- height = mode_info->height;
-
- for (size_t i = 0; i < updated_outputs.size(); ++i) {
- OutputSnapshot* output = &updated_outputs[i];
- output->x = 0;
- output->y = 0;
- output->current_mode = output_power[i] ? output->mirror_mode : None;
- if (output->touch_device_id) {
- // CTM needs to be calculated if aspect preserving scaling is used.
- // Otherwise, assume it is full screen, and use identity CTM.
- if (output->mirror_mode != output->native_mode &&
- output->is_aspect_preserving_scaling) {
- output->transform = GetMirrorModeCTM(*output);
- mirrored_display_area_ratio_map_[output->touch_device_id] =
- GetMirroredDisplayAreaRatio(*output);
- }
- }
- }
- break;
- }
- case ui::OUTPUT_STATE_DUAL_EXTENDED: {
- if (updated_outputs.size() != 2 ||
- (num_on_outputs != 0 && num_on_outputs != 2)) {
- LOG(WARNING) << "Ignoring request to enter extended mode with "
- << updated_outputs.size() << " connected output(s) and "
- << num_on_outputs << " turned on";
- return false;
- }
-
- for (size_t i = 0; i < updated_outputs.size(); ++i) {
- OutputSnapshot* output = &updated_outputs[i];
- output->x = 0;
- output->y = height ? height + kVerticalGap : 0;
- output->current_mode = output_power[i] ? output->selected_mode : None;
-
- // Retain the full screen size even if all outputs are off so the
- // same desktop configuration can be restored when the outputs are
- // turned back on.
- const ModeInfo* mode_info =
- GetModeInfo(updated_outputs[i], updated_outputs[i].selected_mode);
- if (!mode_info)
- return false;
- width = std::max<int>(width, mode_info->width);
- height += (height ? kVerticalGap : 0) + mode_info->height;
- }
-
- for (size_t i = 0; i < updated_outputs.size(); ++i) {
- OutputSnapshot* output = &updated_outputs[i];
- if (output->touch_device_id)
- output->transform = GetExtendedModeCTM(*output, width, height);
- }
- break;
- }
- }
-
- // Finally, apply the desired changes.
- DCHECK_EQ(cached_outputs_.size(), updated_outputs.size());
- bool all_succeeded = true;
- if (!updated_outputs.empty()) {
- native_display_delegate_->CreateFrameBuffer(width, height, updated_outputs);
- for (size_t i = 0; i < updated_outputs.size(); ++i) {
- const OutputSnapshot& output = updated_outputs[i];
- bool configure_succeeded =false;
-
- while (true) {
- if (native_display_delegate_->Configure(output,
- output.current_mode,
- output.x,
- output.y)) {
- configure_succeeded = true;
- break;
- }
-
- LOG(WARNING) << "Unable to configure CRTC " << output.crtc << ":"
- << " mode=" << output.current_mode
- << " output=" << output.output
- << " x=" << output.x
- << " y=" << output.y;
-
- const ModeInfo* mode_info = GetModeInfo(output, output.current_mode);
- if (!mode_info)
- break;
-
- // Find the mode with the next-best resolution and see if that can
- // be set.
- int best_mode_pixels = 0;
-
- int current_mode_pixels = mode_info->width * mode_info->height;
- for (ModeInfoMap::const_iterator it = output.mode_infos.begin();
- it != output.mode_infos.end(); it++) {
- int pixel_count = it->second.width * it->second.height;
- if ((pixel_count < current_mode_pixels) &&
- (pixel_count > best_mode_pixels)) {
- updated_outputs[i].current_mode = it->first;
- best_mode_pixels = pixel_count;
- }
- }
-
- if (best_mode_pixels == 0)
- break;
- }
-
- if (configure_succeeded) {
- if (output.touch_device_id)
- touchscreen_delegate_->ConfigureCTM(output.touch_device_id,
- output.transform);
- cached_outputs_[i] = updated_outputs[i];
- } else {
- all_succeeded = false;
- }
-
- // If we are trying to set mirror mode and one of the modesets fails,
- // then the two monitors will be mis-matched. In this case, return
- // false to let the observers be aware.
- if (output_state == ui::OUTPUT_STATE_DUAL_MIRROR && output_power[i] &&
- output.current_mode != output.mirror_mode)
- all_succeeded = false;
-
- }
- }
-
- if (all_succeeded) {
- output_state_ = output_state;
- power_state_ = power_state;
- }
- return all_succeeded;
-}
-
-ui::OutputState OutputConfigurator::ChooseOutputState(
- DisplayPowerState power_state) const {
- int num_on_outputs = GetOutputPower(cached_outputs_, power_state, NULL);
- switch (cached_outputs_.size()) {
- case 0:
- return ui::OUTPUT_STATE_HEADLESS;
- case 1:
- return ui::OUTPUT_STATE_SINGLE;
- case 2: {
- if (num_on_outputs == 1) {
- // If only one output is currently turned on, return the "single"
- // state so that its native mode will be used.
- return ui::OUTPUT_STATE_SINGLE;
- } else {
- // With either both outputs on or both outputs off, use one of the
- // dual modes.
- std::vector<int64> display_ids;
- for (size_t i = 0; i < cached_outputs_.size(); ++i) {
- // If display id isn't available, switch to extended mode.
- if (!cached_outputs_[i].has_display_id)
- return ui::OUTPUT_STATE_DUAL_EXTENDED;
- display_ids.push_back(cached_outputs_[i].display_id);
- }
- return state_controller_->GetStateForDisplayIds(display_ids);
- }
- }
- default:
- NOTREACHED();
- }
- return ui::OUTPUT_STATE_INVALID;
-}
-
-OutputConfigurator::CoordinateTransformation
-OutputConfigurator::GetMirrorModeCTM(
- const OutputConfigurator::OutputSnapshot& output) {
- CoordinateTransformation ctm; // Default to identity
- const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode);
- const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode);
-
- if (!native_mode_info || !mirror_mode_info ||
- native_mode_info->height == 0 || mirror_mode_info->height == 0 ||
- native_mode_info->width == 0 || mirror_mode_info->width == 0)
- return ctm;
-
- float native_mode_ar = static_cast<float>(native_mode_info->width) /
- static_cast<float>(native_mode_info->height);
- float mirror_mode_ar = static_cast<float>(mirror_mode_info->width) /
- static_cast<float>(mirror_mode_info->height);
-
- if (mirror_mode_ar > native_mode_ar) { // Letterboxing
- ctm.x_scale = 1.0;
- ctm.x_offset = 0.0;
- ctm.y_scale = mirror_mode_ar / native_mode_ar;
- ctm.y_offset = (native_mode_ar / mirror_mode_ar - 1.0) * 0.5;
- return ctm;
- }
- if (native_mode_ar > mirror_mode_ar) { // Pillarboxing
- ctm.y_scale = 1.0;
- ctm.y_offset = 0.0;
- ctm.x_scale = native_mode_ar / mirror_mode_ar;
- ctm.x_offset = (mirror_mode_ar / native_mode_ar - 1.0) * 0.5;
- return ctm;
- }
-
- return ctm; // Same aspect ratio - return identity
-}
-
-OutputConfigurator::CoordinateTransformation
-OutputConfigurator::GetExtendedModeCTM(
- const OutputConfigurator::OutputSnapshot& output,
- int framebuffer_width,
- int framebuffer_height) {
- CoordinateTransformation ctm; // Default to identity
- const ModeInfo* mode_info = GetModeInfo(output, output.selected_mode);
- DCHECK(mode_info);
- if (!mode_info)
- return ctm;
- // An example of how to calculate the CTM.
- // Suppose we have 2 monitors, the first one has size 1366 x 768.
- // The second one has size 2560 x 1600
- // The total size of framebuffer is 2560 x 2428
- // where 2428 = 768 + 60 (hidden gap) + 1600
- // and the sceond monitor is translated to Point (0, 828) in the
- // framebuffer.
- // X will first map input event location to [0, 2560) x [0, 2428),
- // then apply CTM on it.
- // So to compute CTM, for monitor1, we have
- // x_scale = (1366 - 1) / (2560 - 1)
- // x_offset = 0 / (2560 - 1)
- // y_scale = (768 - 1) / (2428 - 1)
- // y_offset = 0 / (2428 -1)
- // For Monitor 2, we have
- // x_scale = (2560 - 1) / (2560 - 1)
- // x_offset = 0 / (2560 - 1)
- // y_scale = (1600 - 1) / (2428 - 1)
- // y_offset = 828 / (2428 -1)
- // See the unittest OutputConfiguratorTest.CTMForMultiScreens.
- ctm.x_scale =
- static_cast<float>(mode_info->width - 1) / (framebuffer_width - 1);
- ctm.x_offset = static_cast<float>(output.x) / (framebuffer_width - 1);
- ctm.y_scale =
- static_cast<float>(mode_info->height - 1) / (framebuffer_height - 1);
- ctm.y_offset = static_cast<float>(output.y) / (framebuffer_height - 1);
- return ctm;
-}
-
-float OutputConfigurator::GetMirroredDisplayAreaRatio(
- const OutputConfigurator::OutputSnapshot& output) {
- float area_ratio = 1.0f;
- const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode);
- const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode);
-
- if (!native_mode_info || !mirror_mode_info ||
- native_mode_info->height == 0 || mirror_mode_info->height == 0 ||
- native_mode_info->width == 0 || mirror_mode_info->width == 0)
- return area_ratio;
-
- float width_ratio = static_cast<float>(mirror_mode_info->width) /
- static_cast<float>(native_mode_info->width);
- float height_ratio = static_cast<float>(mirror_mode_info->height) /
- static_cast<float>(native_mode_info->height);
-
- area_ratio = width_ratio * height_ratio;
- return area_ratio;
-}
-
-} // namespace chromeos
« no previous file with comments | « chromeos/display/output_configurator.h ('k') | chromeos/display/output_configurator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698