diff options
author | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-09 01:53:30 +0000 |
---|---|---|
committer | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-09 01:53:30 +0000 |
commit | dd807f42f2d8ded6eee0b06e3fa238380deb5d9c (patch) | |
tree | 412cb3600aec92bbac7441345e68e3e2a359aa88 /chromeos/display | |
parent | 0369d6ab1a40a774b2aed9b9a76cf6891376912c (diff) | |
download | chromium_src-dd807f42f2d8ded6eee0b06e3fa238380deb5d9c.zip chromium_src-dd807f42f2d8ded6eee0b06e3fa238380deb5d9c.tar.gz chromium_src-dd807f42f2d8ded6eee0b06e3fa238380deb5d9c.tar.bz2 |
chromeos: Make OutputConfigurator save latest config.
This updates the OutputConfigurator class to save
OutputSnapshot structs describing outputs' last-configured
states.
Planned changes that will build on this one:
1. Make OutputConfigurator ignore RRNotify events describing
the same configuration that was just requested.
2. Add additional data to OutputSnapshot and pass snapshots
to observers so they don't need to query the current
state themselves.
BUG=254667,266113
Review URL: https://chromiumcodereview.appspot.com/22605008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@216536 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/display')
-rw-r--r-- | chromeos/display/output_configurator.cc | 155 | ||||
-rw-r--r-- | chromeos/display/output_configurator.h | 69 | ||||
-rw-r--r-- | chromeos/display/output_configurator_unittest.cc | 20 | ||||
-rw-r--r-- | chromeos/display/real_output_configurator_delegate.cc | 82 | ||||
-rw-r--r-- | chromeos/display/real_output_configurator_delegate.h | 11 |
5 files changed, 169 insertions, 168 deletions
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc index c1d2b30..a8c1681 100644 --- a/chromeos/display/output_configurator.cc +++ b/chromeos/display/output_configurator.cc @@ -98,6 +98,12 @@ bool IsProjecting( } // namespace +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), @@ -105,37 +111,14 @@ OutputConfigurator::OutputSnapshot::OutputSnapshot() native_mode(None), mirror_mode(None), selected_mode(None), + x(0), y(0), - height(0), is_internal(false), is_aspect_preserving_scaling(false), touch_device_id(0), display_id(0), has_display_id(false) {} -OutputConfigurator::CoordinateTransformation::CoordinateTransformation() - : x_scale(1.0), - x_offset(0.0), - y_scale(1.0), - y_offset(0.0) {} - -OutputConfigurator::CrtcConfig::CrtcConfig() - : crtc(None), - x(0), - y(0), - mode(None), - output(None) {} - -OutputConfigurator::CrtcConfig::CrtcConfig(RRCrtc crtc, - int x, int y, - RRMode mode, - RROutput output) - : crtc(crtc), - x(x), - y(y), - mode(mode), - output(output) {} - bool OutputConfigurator::TestApi::SendOutputChangeEvents(bool connected) { XRRScreenChangeNotifyEvent screen_event; memset(&screen_event, 0, sizeof(screen_event)); @@ -418,7 +401,16 @@ bool OutputConfigurator::EnterState( int num_on_outputs = GetOutputPower(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 = outputs; + switch (output_state) { + case STATE_INVALID: + NOTREACHED() << "Ignoring request to enter invalid state with " + << outputs.size() << " connected output(s)"; + return false; case STATE_HEADLESS: if (outputs.size() != 0) { LOG(WARNING) << "Ignoring request to enter headless mode with " @@ -435,28 +427,16 @@ bool OutputConfigurator::EnterState( return false; } - // Determine which output to use. - const OutputSnapshot& output = outputs.size() == 1 ? outputs[0] : - (output_power[0] ? outputs[0] : outputs[1]); - int width = 0, height = 0; - if (!delegate_->GetModeDetails( - output.selected_mode, &width, &height, NULL)) - return false; - - std::vector<CrtcConfig> configs(outputs.size()); - for (size_t i = 0; i < outputs.size(); ++i) { - configs[i] = CrtcConfig( - outputs[i].crtc, 0, 0, - output_power[i] ? outputs[i].selected_mode : None, - outputs[i].output); - } - delegate_->CreateFrameBuffer(width, height, configs); + 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; - for (size_t i = 0; i < outputs.size(); ++i) { - delegate_->ConfigureCrtc(&configs[i]); - if (outputs[i].touch_device_id) { - delegate_->ConfigureCTM(outputs[i].touch_device_id, - CoordinateTransformation()); + if (output_power[i] || outputs.size() == 1) { + if (!delegate_->GetModeDetails( + output->selected_mode, &width, &height, NULL)) + return false; } } break; @@ -469,34 +449,24 @@ bool OutputConfigurator::EnterState( return false; } - int width = 0, height = 0; if (!delegate_->GetModeDetails( - outputs[0].mirror_mode, &width, &height, NULL)) { + outputs[0].mirror_mode, &width, &height, NULL)) return false; - } - std::vector<CrtcConfig> configs(outputs.size()); for (size_t i = 0; i < outputs.size(); ++i) { - configs[i] = CrtcConfig( - outputs[i].crtc, 0, 0, - output_power[i] ? outputs[i].mirror_mode : None, - outputs[i].output); - } - delegate_->CreateFrameBuffer(width, height, configs); - - for (size_t i = 0; i < outputs.size(); ++i) { - delegate_->ConfigureCrtc(&configs[i]); - if (outputs[i].touch_device_id) { - CoordinateTransformation ctm; + 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 (outputs[i].mirror_mode != outputs[i].native_mode && - outputs[i].is_aspect_preserving_scaling) { - ctm = GetMirrorModeCTM(&outputs[i]); - mirrored_display_area_ratio_map_[outputs[i].touch_device_id] = - GetMirroredDisplayAreaRatio(&outputs[i]); + 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); } - delegate_->ConfigureCTM(outputs[i].touch_device_id, ctm); } } break; @@ -511,8 +481,6 @@ bool OutputConfigurator::EnterState( // Pairs are [width, height] corresponding to the given output's mode. std::vector<std::pair<int, int> > mode_sizes(outputs.size()); - std::vector<CrtcConfig> configs(outputs.size()); - int width = 0, height = 0; for (size_t i = 0; i < outputs.size(); ++i) { if (!delegate_->GetModeDetails(outputs[i].selected_mode, @@ -520,10 +488,10 @@ bool OutputConfigurator::EnterState( return false; } - configs[i] = CrtcConfig( - outputs[i].crtc, 0, (height ? height + kVerticalGap : 0), - output_power[i] ? outputs[i].selected_mode : None, - outputs[i].output); + 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 @@ -532,29 +500,44 @@ bool OutputConfigurator::EnterState( height += (height ? kVerticalGap : 0) + mode_sizes[i].second; } - delegate_->CreateFrameBuffer(width, height, configs); - for (size_t i = 0; i < outputs.size(); ++i) { - delegate_->ConfigureCrtc(&configs[i]); - if (outputs[i].touch_device_id) { - CoordinateTransformation ctm; - ctm.x_scale = static_cast<float>(mode_sizes[i].first) / width; - ctm.x_offset = static_cast<float>(configs[i].x) / width; - ctm.y_scale = static_cast<float>(mode_sizes[i].second) / height; - ctm.y_offset = static_cast<float>(configs[i].y) / height; - delegate_->ConfigureCTM(outputs[i].touch_device_id, ctm); + OutputSnapshot* output = &updated_outputs[i]; + if (output->touch_device_id) { + CoordinateTransformation* ctm = &(output->transform); + ctm->x_scale = static_cast<float>(mode_sizes[i].first) / width; + ctm->x_offset = static_cast<float>(output->x) / width; + ctm->y_scale = static_cast<float>(mode_sizes[i].second) / height; + ctm->y_offset = static_cast<float>(output->y) / height; } } break; } - default: - NOTREACHED() << "Got request to enter output state " << output_state - << " with " << outputs.size() << " output(s)"; - return false; + } + + // Finally, apply the desired changes. + DCHECK_EQ(outputs.size(), updated_outputs.size()); + if (!outputs.empty()) { + delegate_->CreateFrameBuffer(width, height, updated_outputs); + for (size_t i = 0; i < outputs.size(); ++i) { + const OutputSnapshot& output = updated_outputs[i]; + if (delegate_->ConfigureCrtc(output.crtc, output.current_mode, + output.output, output.x, output.y)) { + if (output.touch_device_id) + delegate_->ConfigureCTM(output.touch_device_id, output.transform); + } else { + LOG(WARNING) << "Unable to configure CRTC " << output.crtc << ":" + << " mode=" << output.current_mode + << " output=" << output.output + << " x=" << output.x + << " y=" << output.y; + updated_outputs[i] = outputs[i]; + } + } } output_state_ = output_state; power_state_ = power_state; + cached_outputs_ = updated_outputs; return true; } diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h index a308a45..fbc7804 100644 --- a/chromeos/display/output_configurator.h +++ b/chromeos/display/output_configurator.h @@ -42,23 +42,41 @@ class CHROMEOS_EXPORT OutputConfigurator : public base::MessageLoop::Dispatcher, public base::MessagePumpObserver { public: + struct CoordinateTransformation { + // Initialized to the identity transformation. + CoordinateTransformation(); + + float x_scale; + float x_offset; + float y_scale; + float y_offset; + }; + // Information about an output's current state. struct OutputSnapshot { OutputSnapshot(); RROutput output; - // CRTC that should be used for this output. Not necessarily the CRTC + // CRTC that should be used for this output. Not necessarily the CRTC // that XRandR reports is currently being used. RRCrtc crtc; + // Mode currently being used by the output. RRMode current_mode; + + // "Best" mode supported by the output. RRMode native_mode; + + // Mode used when displaying the same desktop on multiple outputs. RRMode mirror_mode; + + // User-selected mode for the output. RRMode selected_mode; + // Output's origin on the framebuffer. + int x; int y; - int height; bool is_internal; bool is_aspect_preserving_scaling; @@ -66,33 +84,14 @@ class CHROMEOS_EXPORT OutputConfigurator // XInput device ID or 0 if this output isn't a touchscreen. int touch_device_id; + CoordinateTransformation transform; + // Display id for this output. int64 display_id; bool has_display_id; }; - struct CoordinateTransformation { - // Initialized to the identity transformation. - CoordinateTransformation(); - - float x_scale; - float x_offset; - float y_scale; - float y_offset; - }; - - struct CrtcConfig { - CrtcConfig(); - CrtcConfig(RRCrtc crtc, int x, int y, RRMode mode, RROutput output); - - RRCrtc crtc; - int x; - int y; - RRMode mode; - RROutput output; - }; - class Observer { public: virtual ~Observer() {} @@ -176,16 +175,20 @@ class CHROMEOS_EXPORT OutputConfigurator int* height, bool* interlaced) = 0; - // Calls XRRSetCrtcConfig() with the given options but some of our - // default output count and rotation arguments. - virtual void ConfigureCrtc(CrtcConfig* config) = 0; + // Calls XRRSetCrtcConfig() with the given options but some of our default + // output count and rotation arguments. Returns true on success. + virtual bool ConfigureCrtc(RRCrtc crtc, + RRMode mode, + RROutput output, + int x, + int y) = 0; // Called to set the frame buffer (underlying XRR "screen") size. Has // a side-effect of disabling all CRTCs. virtual void CreateFrameBuffer( int width, int height, - const std::vector<OutputConfigurator::CrtcConfig>& configs) = 0; + const std::vector<OutputConfigurator::OutputSnapshot>& outputs) = 0; // Configures XInput's Coordinate Transformation Matrix property. // |touch_device_id| the ID of the touchscreen device to configure. @@ -325,15 +328,17 @@ class CHROMEOS_EXPORT OutputConfigurator // Switches to the state specified in |output_state| and |power_state|. // If the hardware mirroring failed and |mirroring_controller_| is set, // it switches to |STATE_DUAL_EXTENDED| and calls |SetSoftwareMirroring()| - // to enable software based mirroing. - // On success, updates |output_state_| and |power_state_| and returns true. + // to enable software based mirroring. + // On success, updates |output_state_|, |power_state_|, and |cached_outputs_| + // and returns true. bool EnterStateOrFallBackToSoftwareMirroring( OutputState output_state, DisplayPowerState power_state, const std::vector<OutputSnapshot>& outputs); // Switches to the state specified in |output_state| and |power_state|. - // On success, updates |output_state_| and |power_state_| and returns true. + // On success, updates |output_state_|, |power_state_|, and + // |cached_outputs_| and returns true. bool EnterState(OutputState output_state, DisplayPowerState power_state, const std::vector<OutputSnapshot>& outputs); @@ -383,6 +388,10 @@ class CHROMEOS_EXPORT OutputConfigurator // The current power state. DisplayPowerState power_state_; + // Most-recently-used output configuration. Note that the actual + // configuration changes asynchronously. + std::vector<OutputSnapshot> cached_outputs_; + ObserverList<Observer> observers_; // The timer to delay configuring outputs. See also the comments in diff --git a/chromeos/display/output_configurator_unittest.cc b/chromeos/display/output_configurator_unittest.cc index 246a436..96386f5 100644 --- a/chromeos/display/output_configurator_unittest.cc +++ b/chromeos/display/output_configurator_unittest.cc @@ -148,19 +148,23 @@ class TestDelegate : public OutputConfigurator::Delegate { *interlaced = it->second.interlaced; return true; } - virtual void ConfigureCrtc(OutputConfigurator::CrtcConfig* config) OVERRIDE { - AppendAction(GetCrtcAction(config->crtc, config->x, config->y, config->mode, - config->output)); + virtual bool ConfigureCrtc(RRCrtc crtc, + RRMode mode, + RROutput output, + int x, + int y) OVERRIDE { + AppendAction(GetCrtcAction(crtc, x, y, mode, output)); + return true; } virtual void CreateFrameBuffer( int width, int height, - const std::vector<OutputConfigurator::CrtcConfig>& configs) OVERRIDE { + const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE { AppendAction( GetFramebufferAction(width, height, - configs.size() >= 1 ? configs[0].crtc : 0, - configs.size() >= 2 ? configs[1].crtc : 0)); + outputs.size() >= 1 ? outputs[0].crtc : 0, + outputs.size() >= 2 ? outputs[1].crtc : 0)); } virtual void ConfigureCTM( int touch_device_id, @@ -263,8 +267,8 @@ class OutputConfiguratorTest : public testing::Test { o->native_mode = kSmallModeId; o->selected_mode = kSmallModeId; o->mirror_mode = kSmallModeId; + o->x = 0; o->y = 0; - o->height = kSmallModeHeight; o->is_internal = true; o->is_aspect_preserving_scaling = true; o->touch_device_id = 0; @@ -277,8 +281,8 @@ class OutputConfiguratorTest : public testing::Test { o->native_mode = kBigModeId; o->selected_mode = kBigModeId; o->mirror_mode = kSmallModeId; + o->x = 0; o->y = 0; - o->height = kBigModeHeight; o->is_internal = false; o->is_aspect_preserving_scaling = true; o->touch_device_id = 0; diff --git a/chromeos/display/real_output_configurator_delegate.cc b/chromeos/display/real_output_configurator_delegate.cc index 0ed0437..47fbd58 100644 --- a/chromeos/display/real_output_configurator_delegate.cc +++ b/chromeos/display/real_output_configurator_delegate.cc @@ -138,7 +138,7 @@ RealOutputConfiguratorDelegate::GetOutputs( XRRCrtcInfo* crtc_info = XRRGetCrtcInfo( display_, screen_, output_info->crtc); to_populate.current_mode = crtc_info->mode; - to_populate.height = crtc_info->height; + to_populate.x = crtc_info->x; to_populate.y = crtc_info->y; XRRFreeCrtcInfo(crtc_info); } @@ -252,38 +252,37 @@ bool RealOutputConfiguratorDelegate::GetModeDetails(RRMode mode, return false; } -void RealOutputConfiguratorDelegate::ConfigureCrtc( - OutputConfigurator::CrtcConfig* config) { +bool RealOutputConfiguratorDelegate::ConfigureCrtc( + RRCrtc crtc, + RRMode mode, + RROutput output, + int x, + int y) { CHECK(screen_) << "Server not grabbed"; - VLOG(1) << "ConfigureCrtc: crtc=" << config->crtc - << " mode=" << config->mode - << " output=" << config->output - << " x=" << config->x - << " y=" << config->y; - - RROutput* outputs = NULL; - int num_outputs = 0; - if (config->output && config->mode) { - outputs = &config->output; - num_outputs = 1; - } - - XRRSetCrtcConfig(display_, - screen_, - config->crtc, - CurrentTime, - config->x, - config->y, - config->mode, - RR_Rotate_0, - outputs, - num_outputs); + VLOG(1) << "ConfigureCrtc: crtc=" << crtc + << " mode=" << mode + << " output=" << output + << " x=" << x + << " y=" << y; + // Xrandr.h is full of lies. XRRSetCrtcConfig() is defined as returning a + // Status, which is typically 0 for failure and 1 for success. In + // actuality it returns a RRCONFIGSTATUS, which uses 0 for success. + return XRRSetCrtcConfig(display_, + screen_, + crtc, + CurrentTime, + x, + y, + mode, + RR_Rotate_0, + (output && mode) ? &output : NULL, + (output && mode) ? 1 : 0) == RRSetConfigSuccess; } void RealOutputConfiguratorDelegate::CreateFrameBuffer( int width, int height, - const std::vector<OutputConfigurator::CrtcConfig>& configs) { + const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { CHECK(screen_) << "Server not grabbed"; int current_width = DisplayWidth(display_, DefaultScreen(display_)); int current_height = DisplayHeight(display_, DefaultScreen(display_)); @@ -292,7 +291,7 @@ void RealOutputConfiguratorDelegate::CreateFrameBuffer( if (width == current_width && height == current_height) return; - DestroyUnusedCrtcs(configs); + DestroyUnusedCrtcs(outputs); int mm_width = width * kPixelsToMmScale; int mm_height = height * kPixelsToMmScale; XRRSetScreenSize(display_, window_, width, height, mm_width, mm_height); @@ -345,7 +344,7 @@ void RealOutputConfiguratorDelegate::SendProjectingStateToPowerManager( } void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( - const std::vector<OutputConfigurator::CrtcConfig>& configs) { + const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { CHECK(screen_) << "Server not grabbed"; // Setting the screen size will fail if any CRTC doesn't fit afterwards. // At the same time, turning CRTCs off and back on uses up a lot of time. @@ -360,31 +359,32 @@ void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( // out of the way so we can rebuild the frame buffer. for (int i = 0; i < screen_->ncrtc; ++i) { // Default config is to disable the crtcs. - OutputConfigurator::CrtcConfig config( - screen_->crtcs[i], 0, 0, None, None); - for (std::vector<OutputConfigurator::CrtcConfig>::const_iterator it = - configs.begin(); it != configs.end(); ++it) { - if (config.crtc == it->crtc) { - config.mode = it->mode; - config.output = it->output; + RRCrtc crtc = screen_->crtcs[i]; + RRMode mode = None; + RROutput output = None; + for (std::vector<OutputConfigurator::OutputSnapshot>::const_iterator it = + outputs.begin(); it != outputs.end(); ++it) { + if (crtc == it->crtc) { + mode = it->current_mode; + output = it->output; break; } } - if (config.mode != None) { + if (mode != None) { // In case our CRTC doesn't fit in our current framebuffer, disable it. // It'll get reenabled after we resize the framebuffer. int mode_width = 0, mode_height = 0; - CHECK(GetModeDetails(config.mode, &mode_width, &mode_height, NULL)); + CHECK(GetModeDetails(mode, &mode_width, &mode_height, NULL)); int current_width = DisplayWidth(display_, DefaultScreen(display_)); int current_height = DisplayHeight(display_, DefaultScreen(display_)); if (mode_width > current_width || mode_height > current_height) { - config.mode = None; - config.output = None; + mode = None; + output = None; } } - ConfigureCrtc(&config); + ConfigureCrtc(crtc, mode, output, 0, 0); } } diff --git a/chromeos/display/real_output_configurator_delegate.h b/chromeos/display/real_output_configurator_delegate.h index eeec2ab..9f083cf 100644 --- a/chromeos/display/real_output_configurator_delegate.h +++ b/chromeos/display/real_output_configurator_delegate.h @@ -44,11 +44,16 @@ class RealOutputConfiguratorDelegate : public OutputConfigurator::Delegate { int* width, int* height, bool* interlaced) OVERRIDE; - virtual void ConfigureCrtc(OutputConfigurator::CrtcConfig* config) OVERRIDE; + virtual bool ConfigureCrtc( + RRCrtc crtc, + RRMode mode, + RROutput output, + int x, + int y) OVERRIDE; virtual void CreateFrameBuffer( int width, int height, - const std::vector<OutputConfigurator::CrtcConfig>& configs) OVERRIDE; + const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE; virtual void ConfigureCTM( int touch_device_id, const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE; @@ -59,7 +64,7 @@ class RealOutputConfiguratorDelegate : public OutputConfigurator::Delegate { // framebuffer resize. This is faster than turning them off, resizing, // then turning them back on. void DestroyUnusedCrtcs( - const std::vector<OutputConfigurator::CrtcConfig>& configs); + const std::vector<OutputConfigurator::OutputSnapshot>& outputs); // Returns whether |id| is configured to preserve aspect when scaling. bool IsOutputAspectPreservingScaling(RROutput id); |