diff options
author | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-16 19:56:47 +0000 |
---|---|---|
committer | derat@chromium.org <derat@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-16 19:56:47 +0000 |
commit | 5d99ee6aabc1dc165374898d0fcd4d114e4e1698 (patch) | |
tree | f6dd48eb0397711a04300a62210eeb3e8be5046f /chromeos/display | |
parent | 1d07e92b5484360b2bbf8855c2ed29f5684c114c (diff) | |
download | chromium_src-5d99ee6aabc1dc165374898d0fcd4d114e4e1698.zip chromium_src-5d99ee6aabc1dc165374898d0fcd4d114e4e1698.tar.gz chromium_src-5d99ee6aabc1dc165374898d0fcd4d114e4e1698.tar.bz2 |
chromeos: Include mode details in OutputSnapshot.
This updates OutputConfigurator to include modes'
resolutions and interlaced-ness in OutputSnapshot structs,
and to pass OutputSnapshots to observers after the display
mode is changed.
A following change will update ash's
DisplayChangeObserverX11 class to use OutputSnapshots
instead of asking the X server for the same information via
XRandR.
BUG=266113
Review URL: https://chromiumcodereview.appspot.com/22871010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@218069 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/display')
-rw-r--r-- | chromeos/display/output_configurator.cc | 116 | ||||
-rw-r--r-- | chromeos/display/output_configurator.h | 45 | ||||
-rw-r--r-- | chromeos/display/output_configurator_unittest.cc | 39 | ||||
-rw-r--r-- | chromeos/display/output_util.cc | 6 | ||||
-rw-r--r-- | chromeos/display/output_util.h | 2 | ||||
-rw-r--r-- | chromeos/display/real_output_configurator_delegate.cc | 217 | ||||
-rw-r--r-- | chromeos/display/real_output_configurator_delegate.h | 18 |
7 files changed, 252 insertions, 191 deletions
diff --git a/chromeos/display/output_configurator.cc b/chromeos/display/output_configurator.cc index be84741..c8de844 100644 --- a/chromeos/display/output_configurator.cc +++ b/chromeos/display/output_configurator.cc @@ -98,6 +98,11 @@ bool IsProjecting( } // namespace +OutputConfigurator::ModeInfo::ModeInfo() + : width(0), + height(0), + interlaced(false) {} + OutputConfigurator::CoordinateTransformation::CoordinateTransformation() : x_scale(1.0), x_offset(0.0), @@ -113,12 +118,16 @@ OutputConfigurator::OutputSnapshot::OutputSnapshot() selected_mode(None), x(0), y(0), + width_mm(0), + height_mm(0), is_internal(false), is_aspect_preserving_scaling(false), touch_device_id(0), display_id(0), has_display_id(false) {} +OutputConfigurator::OutputSnapshot::~OutputSnapshot() {} + void OutputConfigurator::TestApi::SendScreenChangeEvent() { XRRScreenChangeNotifyEvent event = {0}; event.type = xrandr_event_base_ + RRScreenChangeNotify; @@ -150,6 +159,19 @@ bool OutputConfigurator::TestApi::TriggerConfigureTimeout() { } } +// static +const OutputConfigurator::ModeInfo* OutputConfigurator::GetModeInfo( + const OutputSnapshot& output, + RRMode mode) { + std::map<RRMode, ModeInfo>::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; +} + OutputConfigurator::OutputConfigurator() : state_controller_(NULL), mirroring_controller_(NULL), @@ -405,7 +427,8 @@ void OutputConfigurator::ConfigureOutputs() { } void OutputConfigurator::NotifyOnDisplayChanged() { - FOR_EACH_OBSERVER(Observer, observers_, OnDisplayModeChanged()); + FOR_EACH_OBSERVER(Observer, observers_, + OnDisplayModeChanged(cached_outputs_)); } bool OutputConfigurator::EnterStateOrFallBackToSoftwareMirroring( @@ -467,9 +490,12 @@ bool OutputConfigurator::EnterState( output->current_mode = output_power[i] ? output->selected_mode : None; if (output_power[i] || outputs.size() == 1) { - if (!delegate_->GetModeDetails( - output->selected_mode, &width, &height, NULL)) + const ModeInfo* mode_info = + GetModeInfo(*output, output->selected_mode); + if (!mode_info) return false; + width = mode_info->width; + height = mode_info->height; } } break; @@ -482,9 +508,14 @@ bool OutputConfigurator::EnterState( return false; } - if (!delegate_->GetModeDetails( - outputs[0].mirror_mode, &width, &height, NULL)) + if (!outputs[0].mirror_mode) + return false; + const ModeInfo* mode_info = + GetModeInfo(outputs[0], outputs[0].mirror_mode); + if (!mode_info) return false; + width = mode_info->width; + height = mode_info->height; for (size_t i = 0; i < outputs.size(); ++i) { OutputSnapshot* output = &updated_outputs[i]; @@ -496,9 +527,9 @@ bool OutputConfigurator::EnterState( // 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); + output->transform = GetMirrorModeCTM(*output); mirrored_display_area_ratio_map_[output->touch_device_id] = - GetMirroredDisplayAreaRatio(output); + GetMirroredDisplayAreaRatio(*output); } } } @@ -512,15 +543,7 @@ bool OutputConfigurator::EnterState( return false; } - // Pairs are [width, height] corresponding to the given output's mode. - std::vector<std::pair<int, int> > mode_sizes(outputs.size()); - for (size_t i = 0; i < outputs.size(); ++i) { - if (!delegate_->GetModeDetails(outputs[i].selected_mode, - &(mode_sizes[i].first), &(mode_sizes[i].second), NULL)) { - return false; - } - OutputSnapshot* output = &updated_outputs[i]; output->x = 0; output->y = height ? height + kVerticalGap : 0; @@ -529,17 +552,24 @@ bool OutputConfigurator::EnterState( // 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. - width = std::max<int>(width, mode_sizes[i].first); - height += (height ? kVerticalGap : 0) + mode_sizes[i].second; + const ModeInfo* mode_info = + GetModeInfo(outputs[i], 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 < outputs.size(); ++i) { OutputSnapshot* output = &updated_outputs[i]; if (output->touch_device_id) { + const ModeInfo* mode_info = + GetModeInfo(*output, output->selected_mode); + DCHECK(mode_info); CoordinateTransformation* ctm = &(output->transform); - ctm->x_scale = static_cast<float>(mode_sizes[i].first) / width; + ctm->x_scale = static_cast<float>(mode_info->width) / width; ctm->x_offset = static_cast<float>(output->x) / width; - ctm->y_scale = static_cast<float>(mode_sizes[i].second) / height; + ctm->y_scale = static_cast<float>(mode_info->height) / height; ctm->y_offset = static_cast<float>(output->y) / height; } } @@ -609,24 +639,20 @@ OutputState OutputConfigurator::GetOutputState( OutputConfigurator::CoordinateTransformation OutputConfigurator::GetMirrorModeCTM( - const OutputConfigurator::OutputSnapshot* output) { + const OutputConfigurator::OutputSnapshot& output) { CoordinateTransformation ctm; // Default to identity - int native_mode_width = 0, native_mode_height = 0; - int mirror_mode_width = 0, mirror_mode_height = 0; - if (!delegate_->GetModeDetails(output->native_mode, - &native_mode_width, &native_mode_height, NULL) || - !delegate_->GetModeDetails(output->mirror_mode, - &mirror_mode_width, &mirror_mode_height, NULL)) - return ctm; + const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); + const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); - if (native_mode_height == 0 || mirror_mode_height == 0 || - native_mode_width == 0 || mirror_mode_width == 0) + 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_width) / - static_cast<float>(native_mode_height); - float mirror_mode_ar = static_cast<float>(mirror_mode_width) / - static_cast<float>(mirror_mode_height); + 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; @@ -647,24 +673,20 @@ OutputConfigurator::GetMirrorModeCTM( } float OutputConfigurator::GetMirroredDisplayAreaRatio( - const OutputConfigurator::OutputSnapshot* output) { + const OutputConfigurator::OutputSnapshot& output) { float area_ratio = 1.0f; - int native_mode_width = 0, native_mode_height = 0; - int mirror_mode_width = 0, mirror_mode_height = 0; - if (!delegate_->GetModeDetails(output->native_mode, - &native_mode_width, &native_mode_height, NULL) || - !delegate_->GetModeDetails(output->mirror_mode, - &mirror_mode_width, &mirror_mode_height, NULL)) - return area_ratio; + const ModeInfo* native_mode_info = GetModeInfo(output, output.native_mode); + const ModeInfo* mirror_mode_info = GetModeInfo(output, output.mirror_mode); - if (native_mode_height == 0 || mirror_mode_height == 0 || - native_mode_width == 0 || mirror_mode_width == 0) + 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_width) / - static_cast<float>(native_mode_width); - float height_ratio = static_cast<float>(mirror_mode_height) / - static_cast<float>(native_mode_height); + 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; diff --git a/chromeos/display/output_configurator.h b/chromeos/display/output_configurator.h index b9d7faf..6e25b4d 100644 --- a/chromeos/display/output_configurator.h +++ b/chromeos/display/output_configurator.h @@ -42,6 +42,14 @@ class CHROMEOS_EXPORT OutputConfigurator : public base::MessageLoop::Dispatcher, public base::MessagePumpObserver { public: + struct ModeInfo { + ModeInfo(); + + int width; + int height; + bool interlaced; + }; + struct CoordinateTransformation { // Initialized to the identity transformation. CoordinateTransformation(); @@ -55,6 +63,7 @@ class CHROMEOS_EXPORT OutputConfigurator // Information about an output's current state. struct OutputSnapshot { OutputSnapshot(); + ~OutputSnapshot(); RROutput output; @@ -78,9 +87,16 @@ class CHROMEOS_EXPORT OutputConfigurator int x; int y; + // Output's physical dimensions. + uint64 width_mm; + uint64 height_mm; + bool is_internal; bool is_aspect_preserving_scaling; + // Map from mode IDs to details about the corresponding modes. + std::map<RRMode, ModeInfo> mode_infos; + // XInput device ID or 0 if this output isn't a touchscreen. int touch_device_id; @@ -96,12 +112,15 @@ class CHROMEOS_EXPORT OutputConfigurator public: virtual ~Observer() {} - // Called when the change of the display mode finished. It will usually - // start the fading in the displays. - virtual void OnDisplayModeChanged() {} + // Called after the display mode has been changed. |output| contains the + // just-applied configuration. Note that the X server is no longer grabbed + // when this method is called, so the actual configuration could've changed + // already. + virtual void OnDisplayModeChanged( + const std::vector<OutputSnapshot>& outputs) {} - // Called when the change of the display mode is issued but failed. - // |failed_new_state| is the new state which the system failed to enter. + // Called after a display mode change attempt failed. |failed_new_state| is + // the new state which the system failed to enter. virtual void OnDisplayModeChangeFailed(OutputState failed_new_state) {} }; @@ -168,13 +187,6 @@ class CHROMEOS_EXPORT OutputConfigurator virtual std::vector<OutputSnapshot> GetOutputs( const StateController* state_controller) = 0; - // Gets details corresponding to |mode|. Parameters may be NULL. - // Returns true on success. - virtual bool GetModeDetails(RRMode mode, - int* width, - int* height, - bool* interlaced) = 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, @@ -249,6 +261,11 @@ class CHROMEOS_EXPORT OutputConfigurator // See crbug.com/130188 for initial discussion. static const int kVerticalGap = 60; + // Returns a pointer to the ModeInfo struct in |output| corresponding to + // |mode|, or NULL if the struct isn't present. + static const ModeInfo* GetModeInfo(const OutputSnapshot& output, + RRMode mode); + OutputConfigurator(); virtual ~OutputConfigurator(); @@ -360,12 +377,12 @@ class CHROMEOS_EXPORT OutputConfigurator // |output| is the output on which mirror mode is being applied. // Returns the transformation or identity if computations fail. CoordinateTransformation GetMirrorModeCTM( - const OutputConfigurator::OutputSnapshot* output); + const OutputConfigurator::OutputSnapshot& output); // Returns the ratio between mirrored mode area and native mode area: // (mirror_mode_width * mirrow_mode_height) / (native_width * native_height) float GetMirroredDisplayAreaRatio( - const OutputConfigurator::OutputSnapshot* output); + const OutputConfigurator::OutputSnapshot& output); StateController* state_controller_; SoftwareMirroringController* mirroring_controller_; diff --git a/chromeos/display/output_configurator_unittest.cc b/chromeos/display/output_configurator_unittest.cc index 6769e51..0749399 100644 --- a/chromeos/display/output_configurator_unittest.cc +++ b/chromeos/display/output_configurator_unittest.cc @@ -114,11 +114,6 @@ class TestDelegate : public OutputConfigurator::Delegate { return actions; } - // Adds a mode to be returned by GetModeDetails(). - void AddMode(RRMode mode, int width, int height, bool interlaced) { - modes_[mode] = ModeDetails(width, height, interlaced); - } - // OutputConfigurator::Delegate overrides: virtual void SetPanelFittingEnabled(bool enabled) OVERRIDE {} virtual void InitXRandRExtension(int* event_base) OVERRIDE { @@ -138,23 +133,6 @@ class TestDelegate : public OutputConfigurator::Delegate { const OutputConfigurator::StateController* controller) OVERRIDE { return outputs_; } - virtual bool GetModeDetails( - RRMode mode, - int* width, - int* height, - bool* interlaced) OVERRIDE { - std::map<RRMode, ModeDetails>::const_iterator it = modes_.find(mode); - if (it == modes_.end()) - return false; - - if (width) - *width = it->second.width; - if (height) - *height = it->second.height; - if (interlaced) - *interlaced = it->second.interlaced; - return true; - } virtual bool ConfigureCrtc(RRCrtc crtc, RRMode mode, RROutput output, @@ -270,6 +248,14 @@ class OutputConfiguratorTest : public testing::Test { configurator_.set_state_controller(&state_controller_); configurator_.set_mirroring_controller(&mirroring_controller_); + OutputConfigurator::ModeInfo small_mode_info; + small_mode_info.width = kSmallModeWidth; + small_mode_info.height = kSmallModeHeight; + + OutputConfigurator::ModeInfo big_mode_info; + big_mode_info.width = kBigModeWidth; + big_mode_info.height = kBigModeHeight; + OutputConfigurator::OutputSnapshot* o = &outputs_[0]; o->output = 1; o->crtc = 10; @@ -281,6 +267,7 @@ class OutputConfiguratorTest : public testing::Test { o->y = 0; o->is_internal = true; o->is_aspect_preserving_scaling = true; + o->mode_infos[kSmallModeId] = small_mode_info; o->touch_device_id = 0; o->has_display_id = true; @@ -295,12 +282,12 @@ class OutputConfiguratorTest : public testing::Test { o->y = 0; o->is_internal = false; o->is_aspect_preserving_scaling = true; + o->mode_infos[kSmallModeId] = small_mode_info; + o->mode_infos[kBigModeId] = big_mode_info; o->touch_device_id = 0; o->has_display_id = true; UpdateOutputs(2, false); - delegate_->AddMode(kSmallModeId, kSmallModeWidth, kSmallModeHeight, false); - delegate_->AddMode(kBigModeId, kBigModeWidth, kBigModeHeight, false); } void DisableNativeMirroring() { @@ -704,9 +691,7 @@ TEST_F(OutputConfiguratorTest, Headless) { delegate_->GetActionsAndClear()); // Connect an external display and check that it's configured correctly. - outputs_[0].is_internal = false; - outputs_[0].native_mode = kBigModeId; - outputs_[0].selected_mode = kBigModeId; + outputs_[0] = outputs_[1]; UpdateOutputs(1, true); EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab, GetFramebufferAction(kBigModeWidth, kBigModeHeight, diff --git a/chromeos/display/output_util.cc b/chromeos/display/output_util.cc index d9d2913..4800a2d 100644 --- a/chromeos/display/output_util.cc +++ b/chromeos/display/output_util.cc @@ -331,8 +331,8 @@ bool IsInternalOutputName(const std::string& name) { name.find(kInternal_DSI) == 0; } -const XRRModeInfo* FindModeInfo(const XRRScreenResources* screen_resources, - XID current_mode) { +const XRRModeInfo* FindXRRModeInfo(const XRRScreenResources* screen_resources, + XID current_mode) { for (int m = 0; m < screen_resources->nmode; m++) { XRRModeInfo *mode = &screen_resources->modes[m]; if (mode->id == current_mode) @@ -353,7 +353,7 @@ RRMode FindOutputModeMatchingSize( bool non_interlaced_found = false; for (int i = 0; i < output_info->nmode; ++i) { RRMode mode = output_info->modes[i]; - const XRRModeInfo* info = FindModeInfo(screen_resources, mode); + const XRRModeInfo* info = FindXRRModeInfo(screen_resources, mode); if (info->width == width && info->height == height) { float rate = GetRefreshRate(info); diff --git a/chromeos/display/output_util.h b/chromeos/display/output_util.h index d464ba6..d2f1f01 100644 --- a/chromeos/display/output_util.h +++ b/chromeos/display/output_util.h @@ -65,7 +65,7 @@ CHROMEOS_EXPORT bool ParseOutputOverscanFlag(const unsigned char* prop, CHROMEOS_EXPORT bool IsInternalOutputName(const std::string& name); // Find a XRRModeInfo that matches |mode|. -CHROMEOS_EXPORT const XRRModeInfo* FindModeInfo( +CHROMEOS_EXPORT const XRRModeInfo* FindXRRModeInfo( const XRRScreenResources* screen_resources, XID mode); diff --git a/chromeos/display/real_output_configurator_delegate.cc b/chromeos/display/real_output_configurator_delegate.cc index 5b2d3c7..6d3497b 100644 --- a/chromeos/display/real_output_configurator_delegate.cc +++ b/chromeos/display/real_output_configurator_delegate.cc @@ -13,6 +13,7 @@ #include <cmath> #include <set> +#include <utility> #include "base/logging.h" #include "base/message_loop/message_pump_aurax11.h" @@ -116,68 +117,38 @@ RealOutputConfiguratorDelegate::GetOutputs( RRCrtc last_used_crtc = None; for (int i = 0; i < screen_->noutput && outputs.size() < 2; ++i) { - RROutput this_id = screen_->outputs[i]; - XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, this_id); + RROutput output_id = screen_->outputs[i]; + XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, output_id); bool is_connected = (output_info->connection == RR_Connected); - if (is_connected) { - OutputConfigurator::OutputSnapshot to_populate; - to_populate.output = this_id; - to_populate.has_display_id = - GetDisplayId(this_id, i, &to_populate.display_id); - to_populate.is_internal = IsInternalOutput(output_info); - // Use the index as a valid display id even if the internal - // display doesn't have valid EDID because the index - // will never change. - if (!to_populate.has_display_id && to_populate.is_internal) - to_populate.has_display_id = true; - - (outputs.empty() ? one_info : two_info) = output_info; - - // Now, look up the current CRTC and any related info. - if (output_info->crtc) { - XRRCrtcInfo* crtc_info = XRRGetCrtcInfo( - display_, screen_, output_info->crtc); - to_populate.current_mode = crtc_info->mode; - to_populate.x = crtc_info->x; - to_populate.y = crtc_info->y; - XRRFreeCrtcInfo(crtc_info); - } + if (!is_connected) { + XRRFreeOutputInfo(output_info); + continue; + } - // Assign a CRTC that isn't already in use. - for (int j = 0; j < output_info->ncrtc; ++j) { - if (output_info->crtcs[j] != last_used_crtc) { - to_populate.crtc = output_info->crtcs[j]; - last_used_crtc = to_populate.crtc; - break; - } - } - to_populate.native_mode = GetOutputNativeMode(output_info); - if (to_populate.has_display_id) { - int width = 0, height = 0; - if (state_controller && - state_controller->GetResolutionForDisplayId( - to_populate.display_id, &width, &height)) { - to_populate.selected_mode = - FindOutputModeMatchingSize(screen_, output_info, width, height); - } + (outputs.empty() ? one_info : two_info) = output_info; + + OutputConfigurator::OutputSnapshot output = InitOutputSnapshot( + output_id, output_info, &last_used_crtc, 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(screen_, output_info, width, height); } - // Fallback to native mode. - if (to_populate.selected_mode == None) - to_populate.selected_mode = to_populate.native_mode; - - to_populate.is_aspect_preserving_scaling = - IsOutputAspectPreservingScaling(this_id); - to_populate.touch_device_id = None; - - VLOG(2) << "Found display " << outputs.size() << ":" - << " output=" << to_populate.output - << " crtc=" << to_populate.crtc - << " current_mode=" << to_populate.current_mode; - outputs.push_back(to_populate); - } else { - XRRFreeOutputInfo(output_info); } + // Fall back to native mode. + if (output.selected_mode == None) + output.selected_mode = output.native_mode; + + VLOG(2) << "Found display " << outputs.size() << ":" + << " output=" << output.output + << " crtc=" << output.crtc + << " current_mode=" << output.current_mode; + outputs.push_back(output); } if (outputs.size() == 2) { @@ -229,30 +200,6 @@ RealOutputConfiguratorDelegate::GetOutputs( return outputs; } -bool RealOutputConfiguratorDelegate::GetModeDetails(RRMode mode, - int* width, - int* height, - bool* interlaced) { - CHECK(screen_) << "Server not grabbed"; - // TODO: Determine if we need to organize modes in a way which provides - // better than O(n) lookup time. In many call sites, for example, the - // "next" mode is typically what we are looking for so using this - // helper might be too expensive. - for (int i = 0; i < screen_->nmode; ++i) { - if (mode == screen_->modes[i].id) { - const XRRModeInfo& info = screen_->modes[i]; - if (width) - *width = info.width; - if (height) - *height = info.height; - if (interlaced) - *interlaced = info.modeFlags & RR_Interlace; - return true; - } - } - return false; -} - bool RealOutputConfiguratorDelegate::ConfigureCrtc( RRCrtc crtc, RRMode mode, @@ -344,6 +291,84 @@ void RealOutputConfiguratorDelegate::SendProjectingStateToPowerManager( SetIsProjecting(projecting); } +bool RealOutputConfiguratorDelegate::GetModeDetails(RRMode mode, + int* width, + int* height, + bool* interlaced) { + CHECK(screen_) << "Server not grabbed"; + // TODO: Determine if we need to organize modes in a way which provides + // better than O(n) lookup time. In many call sites, for example, the + // "next" mode is typically what we are looking for so using this + // helper might be too expensive. + for (int i = 0; i < screen_->nmode; ++i) { + if (mode == screen_->modes[i].id) { + const XRRModeInfo& info = screen_->modes[i]; + if (width) + *width = info.width; + if (height) + *height = info.height; + if (interlaced) + *interlaced = info.modeFlags & RR_Interlace; + return true; + } + } + return false; +} + +OutputConfigurator::OutputSnapshot +RealOutputConfiguratorDelegate::InitOutputSnapshot( + RROutput id, + XRROutputInfo* info, + RRCrtc* last_used_crtc, + int index) { + OutputConfigurator::OutputSnapshot output; + output.output = id; + output.width_mm = info->mm_width; + output.height_mm = info->mm_height; + output.has_display_id = GetDisplayId(id, index, &output.display_id); + output.is_internal = IsInternalOutput(info); + + // Use the index as a valid display ID even if the internal + // display doesn't have valid EDID because the index + // will never change. + if (!output.has_display_id && output.is_internal) + output.has_display_id = true; + + if (info->crtc) { + XRRCrtcInfo* crtc_info = XRRGetCrtcInfo(display_, screen_, info->crtc); + output.current_mode = crtc_info->mode; + output.x = crtc_info->x; + output.y = crtc_info->y; + XRRFreeCrtcInfo(crtc_info); + } + + // Assign a CRTC that isn't already in use. + for (int i = 0; i < info->ncrtc; ++i) { + if (info->crtcs[i] != *last_used_crtc) { + output.crtc = info->crtcs[i]; + *last_used_crtc = output.crtc; + break; + } + } + + output.native_mode = GetOutputNativeMode(info); + output.is_aspect_preserving_scaling = IsOutputAspectPreservingScaling(id); + output.touch_device_id = None; + + for (int i = 0; i < info->nmode; ++i) { + const RRMode mode = info->modes[i]; + OutputConfigurator::ModeInfo mode_info; + if (GetModeDetails(mode, &mode_info.width, &mode_info.height, + &mode_info.interlaced)) { + output.mode_infos.insert(std::make_pair(mode, mode_info)); + } else { + LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; + } + } + + return output; +} + void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { CHECK(screen_) << "Server not grabbed"; @@ -363,25 +388,28 @@ void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( RRCrtc crtc = screen_->crtcs[i]; RRMode mode = None; RROutput output = None; + const OutputConfigurator::ModeInfo* mode_info = NULL; 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; + if (mode != None) + mode_info = OutputConfigurator::GetModeInfo(*it, mode); break; } } - if (mode != None) { + if (mode_info) { // 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(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) { + if (mode_info->width > current_width || + mode_info->height > current_height) { mode = None; output = None; + mode_info = NULL; } } @@ -556,12 +584,13 @@ void RealOutputConfiguratorDelegate::GetTouchscreens( if (width > 0.0 && height > 0.0 && is_direct_touch) { size_t k = 0; for (; k < outputs->size(); k++) { - if ((*outputs)[k].native_mode == None || - (*outputs)[k].touch_device_id != None) + OutputConfigurator::OutputSnapshot* output = &(*outputs)[k]; + if (output->native_mode == None || output->touch_device_id != None) continue; - int native_mode_width = 0, native_mode_height = 0; - if (!GetModeDetails((*outputs)[k].native_mode, &native_mode_width, - &native_mode_height, NULL)) + + const OutputConfigurator::ModeInfo* mode_info = + OutputConfigurator::GetModeInfo(*output, output->native_mode); + if (!mode_info) continue; // Allow 1 pixel difference between screen and touchscreen @@ -569,12 +598,12 @@ void RealOutputConfiguratorDelegate::GetTouchscreens( // 1024x768 touchscreen's resolution would be 1024x768, but for // some 1023x767. It really depends on touchscreen's firmware // configuration. - if (std::abs(native_mode_width - width) <= 1.0 && - std::abs(native_mode_height - height) <= 1.0) { - (*outputs)[k].touch_device_id = info[i].deviceid; + if (std::abs(mode_info->width - width) <= 1.0 && + std::abs(mode_info->height - height) <= 1.0) { + output->touch_device_id = info[i].deviceid; VLOG(2) << "Found touchscreen for output #" << k - << " id " << (*outputs)[k].touch_device_id + << " id " << output->touch_device_id << " width " << width << " height " << height; break; diff --git a/chromeos/display/real_output_configurator_delegate.h b/chromeos/display/real_output_configurator_delegate.h index 9f083cf..2753ae5 100644 --- a/chromeos/display/real_output_configurator_delegate.h +++ b/chromeos/display/real_output_configurator_delegate.h @@ -39,11 +39,6 @@ class RealOutputConfiguratorDelegate : public OutputConfigurator::Delegate { virtual void ForceDPMSOn() OVERRIDE; virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs( const OutputConfigurator::StateController* state_controller) OVERRIDE; - virtual bool GetModeDetails( - RRMode mode, - int* width, - int* height, - bool* interlaced) OVERRIDE; virtual bool ConfigureCrtc( RRCrtc crtc, RRMode mode, @@ -60,6 +55,19 @@ class RealOutputConfiguratorDelegate : public OutputConfigurator::Delegate { virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE; private: + // Gets details corresponding to |mode|. Parameters may be NULL. Returns + // true on success. + bool GetModeDetails(RRMode mode, int* width, int* height, bool* interlaced); + + // Helper method for GetOutputs() that returns an OutputSnapshot struct based + // on the passed-in information. Further initialization is required (e.g. + // |selected_mode|, |mirror_mode|, and |touch_device_id|). + OutputConfigurator::OutputSnapshot InitOutputSnapshot( + RROutput id, + XRROutputInfo* info, + RRCrtc* last_used_crtc, + int index); + // Destroys unused CRTCs and parks used CRTCs in a way which allows a // framebuffer resize. This is faster than turning them off, resizing, // then turning them back on. |