diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-12 22:35:53 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-12 22:35:53 +0000 |
commit | 2bd1fcf0d9c29762b83d73839b6f016b09d66d62 (patch) | |
tree | dcb821d7421ff931fedd797cbcd51b9a9f58263b | |
parent | 1f8ae227e655d43caf0089f4bcc4a90923171fad (diff) | |
download | chromium_src-2bd1fcf0d9c29762b83d73839b6f016b09d66d62.zip chromium_src-2bd1fcf0d9c29762b83d73839b6f016b09d66d62.tar.gz chromium_src-2bd1fcf0d9c29762b83d73839b6f016b09d66d62.tar.bz2 |
Revert 250798 "Revert of Read compositor VSync information from ..."
Broke compilation.
> Revert of Read compositor VSync information from platform, when possible (https://chromiumcodereview.appspot.com/138903025/)
>
> Reason for revert:
> Reverting due to Windows crashes. See:
>
> http://crbug.com/343199
>
> Original issue's description:
> > Read compositor VSync information from platform, when possible
> >
> > The current query of VSync information through the GL context can be unreliable
> > on platforms that can dynamically disable vblanks, or multi-monitor setups.
> > Preferentially query the VSync information through the platform windowing
> > system (presently: XRandR on CrOS) when possible.
> >
> > BUG=328953
> > TEST=local build, run on CrOS snow
> >
> > Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=250250
>
> TBR=oshima@chromium.org,piman@chromium.org,brianderson@chromium.org,sky@chromium.org,mukai@chromium.org
> NOTREECHECKS=true
> NOTRY=true
> BUG=328953
>
> Review URL: https://codereview.chromium.org/161413002
TBR=sheu@chromium.org
Review URL: https://codereview.chromium.org/161743002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@250810 0039d316-1c4b-4281-b951-d872f2087c98
43 files changed, 599 insertions, 390 deletions
diff --git a/ash/display/display_change_observer_chromeos.cc b/ash/display/display_change_observer_chromeos.cc index b381d03..6343586 100644 --- a/ash/display/display_change_observer_chromeos.cc +++ b/ash/display/display_change_observer_chromeos.cc @@ -37,46 +37,52 @@ const unsigned int kHighDensityDPIThreshold = 160; // 1 inch in mm. const float kInchInMm = 25.4f; -// Resolution list are sorted by the area in pixels and the larger -// one comes first. -struct ResolutionSorter { - bool operator()(const Resolution& a, const Resolution& b) { - return a.size.width() * a.size.height() > b.size.width() * b.size.height(); +// Display mode list is sorted by (in descending priority): +// * the area in pixels. +// * refresh rate. +struct DisplayModeSorter { + bool operator()(const DisplayMode& a, const DisplayMode& b) { + if (a.size.GetArea() == b.size.GetArea()) + return (a.refresh_rate > b.refresh_rate); + return (a.size.GetArea() > b.size.GetArea()); } }; } // namespace // static -std::vector<Resolution> DisplayChangeObserver::GetResolutionList( +std::vector<DisplayMode> DisplayChangeObserver::GetDisplayModeList( const OutputConfigurator::OutputSnapshot& output) { - typedef std::map<std::pair<int,int>, Resolution> ResolutionMap; - ResolutionMap resolution_map; + typedef std::map<std::pair<int, int>, DisplayMode> DisplayModeMap; + DisplayModeMap display_mode_map; for (std::map<RRMode, OutputConfigurator::ModeInfo>::const_iterator it = output.mode_infos.begin(); it != output.mode_infos.end(); ++it) { const OutputConfigurator::ModeInfo& mode_info = it->second; const std::pair<int, int> size(mode_info.width, mode_info.height); - const Resolution resolution(gfx::Size(mode_info.width, mode_info.height), - mode_info.interlaced); - - // Add the resolution if it isn't already present and override interlaced - // resolutions with non-interlaced ones. - ResolutionMap::iterator resolution_it = resolution_map.find(size); - if (resolution_it == resolution_map.end()) - resolution_map.insert(std::make_pair(size, resolution)); - else if (resolution_it->second.interlaced && !resolution.interlaced) - resolution_it->second = resolution; + const DisplayMode display_mode(gfx::Size(mode_info.width, mode_info.height), + mode_info.refresh_rate, + mode_info.interlaced, + output.native_mode == it->first); + + // Add the display mode if it isn't already present and override interlaced + // display modes with non-interlaced ones. + DisplayModeMap::iterator display_mode_it = display_mode_map.find(size); + if (display_mode_it == display_mode_map.end()) + display_mode_map.insert(std::make_pair(size, display_mode)); + else if (display_mode_it->second.interlaced && !display_mode.interlaced) + display_mode_it->second = display_mode; } - std::vector<Resolution> resolution_list; - for (ResolutionMap::const_iterator iter = resolution_map.begin(); - iter != resolution_map.end(); + std::vector<DisplayMode> display_mode_list; + for (DisplayModeMap::const_iterator iter = display_mode_map.begin(); + iter != display_mode_map.end(); ++iter) { - resolution_list.push_back(iter->second); + display_mode_list.push_back(iter->second); } - std::sort(resolution_list.begin(), resolution_list.end(), ResolutionSorter()); - return resolution_list; + std::sort( + display_mode_list.begin(), display_mode_list.end(), DisplayModeSorter()); + return display_mode_list; } DisplayChangeObserver::DisplayChangeObserver() { @@ -105,14 +111,13 @@ ui::OutputState DisplayChangeObserver::GetStateForDisplayIds( bool DisplayChangeObserver::GetResolutionForDisplayId(int64 display_id, int* width, int* height) const { - gfx::Size resolution; - if (!Shell::GetInstance()->display_manager()-> - GetSelectedResolutionForDisplayId(display_id, &resolution)) { + DisplayMode mode; + if (!Shell::GetInstance()->display_manager()->GetSelectedModeForDisplayId( + display_id, &mode)) return false; - } - *width = resolution.width(); - *height = resolution.height(); + *width = mode.size.width(); + *height = mode.size.height(); return true; } @@ -145,9 +150,7 @@ void DisplayChangeObserver::OnDisplayModeChanged( gfx::Rect display_bounds( output.x, output.y, mode_info->width, mode_info->height); - std::vector<Resolution> resolutions; - if (output.type != chromeos::OUTPUT_TYPE_INTERNAL) - resolutions = GetResolutionList(output); + std::vector<DisplayMode> display_modes = GetDisplayModeList(output); std::string name = output.type == ui::OUTPUT_TYPE_INTERNAL @@ -168,7 +171,7 @@ void DisplayChangeObserver::OnDisplayModeChanged( displays.back().set_device_scale_factor(device_scale_factor); displays.back().SetBounds(display_bounds); displays.back().set_native(true); - displays.back().set_resolutions(resolutions); + displays.back().set_display_modes(display_modes); displays.back().set_touch_support( output.touch_device_id == 0 ? gfx::Display::TOUCH_SUPPORT_UNAVAILABLE : gfx::Display::TOUCH_SUPPORT_AVAILABLE); diff --git a/ash/display/display_change_observer_chromeos.h b/ash/display/display_change_observer_chromeos.h index b8d63e5..59c2dee 100644 --- a/ash/display/display_change_observer_chromeos.h +++ b/ash/display/display_change_observer_chromeos.h @@ -13,7 +13,7 @@ namespace ash { namespace internal { -struct Resolution; +struct DisplayMode; // An object that observes changes in display configuration and // update DisplayManagers. @@ -23,7 +23,7 @@ class DisplayChangeObserver public ShellObserver { public: // Returns the resolution list. - ASH_EXPORT static std::vector<Resolution> GetResolutionList( + ASH_EXPORT static std::vector<DisplayMode> GetDisplayModeList( const chromeos::OutputConfigurator::OutputSnapshot& output); DisplayChangeObserver(); diff --git a/ash/display/display_change_observer_chromeos_unittest.cc b/ash/display/display_change_observer_chromeos_unittest.cc index 1f64be7..d99b154 100644 --- a/ash/display/display_change_observer_chromeos_unittest.cc +++ b/ash/display/display_change_observer_chromeos_unittest.cc @@ -15,7 +15,7 @@ typedef testing::Test DisplayChangeObserverTest; namespace ash { namespace internal { -TEST_F(DisplayChangeObserverTest, GetResolutionList) { +TEST_F(DisplayChangeObserverTest, GetDisplayModeList) { OutputConfigurator::OutputSnapshot output; output.mode_infos[11] = OutputConfigurator::ModeInfo(1920, 1200, false, 60); @@ -40,31 +40,37 @@ TEST_F(DisplayChangeObserverTest, GetResolutionList) { // Just one interlaced mode. output.mode_infos[22] = OutputConfigurator::ModeInfo(640, 480, true, 60); - std::vector<Resolution> resolutions = - DisplayChangeObserver::GetResolutionList(output); - ASSERT_EQ(6u, resolutions.size()); - EXPECT_EQ("1920x1200", resolutions[0].size.ToString()); - EXPECT_FALSE(resolutions[0].interlaced); + std::vector<DisplayMode> display_modes = + DisplayChangeObserver::GetDisplayModeList(output); + ASSERT_EQ(6u, display_modes.size()); + EXPECT_EQ("1920x1200", display_modes[0].size.ToString()); + EXPECT_FALSE(display_modes[0].interlaced); + EXPECT_EQ(display_modes[0].refresh_rate, 60); - EXPECT_EQ("1920x1080", resolutions[1].size.ToString()); - EXPECT_FALSE(resolutions[1].interlaced); + EXPECT_EQ("1920x1080", display_modes[1].size.ToString()); + EXPECT_FALSE(display_modes[1].interlaced); + EXPECT_EQ(display_modes[1].refresh_rate, 80); - EXPECT_EQ("1280x720", resolutions[2].size.ToString()); - EXPECT_FALSE(resolutions[2].interlaced); + EXPECT_EQ("1280x720", display_modes[2].size.ToString()); + EXPECT_FALSE(display_modes[2].interlaced); + EXPECT_EQ(display_modes[2].refresh_rate, 60); - EXPECT_EQ("1024x768", resolutions[3].size.ToString()); - EXPECT_TRUE(resolutions[3].interlaced); + EXPECT_EQ("1024x768", display_modes[3].size.ToString()); + EXPECT_TRUE(display_modes[3].interlaced); + EXPECT_EQ(display_modes[3].refresh_rate, 70); - EXPECT_EQ("1024x600", resolutions[4].size.ToString()); - EXPECT_FALSE(resolutions[4].interlaced); + EXPECT_EQ("1024x600", display_modes[4].size.ToString()); + EXPECT_FALSE(display_modes[4].interlaced); + EXPECT_EQ(display_modes[4].refresh_rate, 70); - EXPECT_EQ("640x480", resolutions[5].size.ToString()); - EXPECT_TRUE(resolutions[5].interlaced); + EXPECT_EQ("640x480", display_modes[5].size.ToString()); + EXPECT_TRUE(display_modes[5].interlaced); + EXPECT_EQ(display_modes[5].refresh_rate, 60); // Outputs without any modes shouldn't cause a crash. output.mode_infos.clear(); - resolutions = DisplayChangeObserver::GetResolutionList(output); - EXPECT_EQ(0u, resolutions.size()); + display_modes = DisplayChangeObserver::GetDisplayModeList(output); + EXPECT_EQ(0u, display_modes.size()); } } // namespace internal diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc index 0633d12..031a6b1 100644 --- a/ash/display/display_controller.cc +++ b/ash/display/display_controller.cc @@ -34,6 +34,7 @@ #include "ui/aura/window_property.h" #include "ui/aura/window_tracker.h" #include "ui/compositor/compositor.h" +#include "ui/compositor/compositor_vsync_manager.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" @@ -120,6 +121,14 @@ void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, scoped_ptr<aura::RootWindowTransformer> transformer( internal::CreateRootWindowTransformerForDisplay(root->window(), display)); root->host()->SetRootWindowTransformer(transformer.Pass()); + + internal::DisplayMode mode; + if (GetDisplayManager()->GetSelectedModeForDisplayId(display.id(), &mode) && + mode.refresh_rate > 0.0f) { + root->host()->compositor()->vsync_manager()->SetAuthoritativeVSyncInterval( + base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond / + mode.refresh_rate)); + } } } // namespace diff --git a/ash/display/display_info.cc b/ash/display/display_info.cc index d35f0fc0..17a1bc1 100644 --- a/ash/display/display_info.cc +++ b/ash/display/display_info.cc @@ -23,10 +23,17 @@ namespace ash { namespace internal { -Resolution::Resolution(const gfx::Size& size, bool interlaced) +DisplayMode::DisplayMode() + : refresh_rate(0.0f), interlaced(false), native(false) {} + +DisplayMode::DisplayMode(const gfx::Size& size, + float refresh_rate, + bool interlaced, + bool native) : size(size), - interlaced(interlaced) { -} + refresh_rate(refresh_rate), + interlaced(interlaced), + native(native) {} // satic DisplayInfo DisplayInfo::CreateFromSpec(const std::string& spec) { @@ -104,17 +111,35 @@ DisplayInfo DisplayInfo::CreateFromSpecWithID(const std::string& spec, #endif } - std::vector<Resolution> resolutions; + std::vector<DisplayMode> display_modes; if (Tokenize(main_spec, "#", &parts) == 2) { + size_t native_mode = 0; + int largest_area = -1; + float highest_refresh_rate = -1.0f; main_spec = parts[0]; std::string resolution_list = parts[1]; count = Tokenize(resolution_list, "|", &parts); for (size_t i = 0; i < count; ++i) { std::string resolution = parts[i]; int width, height; - if (sscanf(resolution.c_str(), "%dx%d", &width, &height) == 2) - resolutions.push_back(Resolution(gfx::Size(width, height), false)); + float refresh_rate = 0.0f; + if (sscanf(resolution.c_str(), + "%dx%d%%%f", + &width, + &height, + &refresh_rate) >= 2) { + if (width * height >= largest_area && + refresh_rate > highest_refresh_rate) { + // Use mode with largest area and highest refresh rate as native. + largest_area = width * height; + highest_refresh_rate = refresh_rate; + native_mode = i; + } + display_modes.push_back( + DisplayMode(gfx::Size(width, height), refresh_rate, false, false)); + } } + display_modes[native_mode].native = true; } if (id == gfx::Display::kInvalidDisplayID) @@ -125,7 +150,7 @@ DisplayInfo DisplayInfo::CreateFromSpecWithID(const std::string& spec, display_info.set_rotation(rotation); display_info.set_configured_ui_scale(ui_scale); display_info.SetBounds(bounds_in_native); - display_info.set_resolutions(resolutions); + display_info.set_display_modes(display_modes); // To test the overscan, it creates the default 5% overscan. if (has_overscan) { @@ -177,7 +202,7 @@ void DisplayInfo::Copy(const DisplayInfo& native_info) { bounds_in_native_ = native_info.bounds_in_native_; size_in_pixel_ = native_info.size_in_pixel_; device_scale_factor_ = native_info.device_scale_factor_; - resolutions_ = native_info.resolutions_; + display_modes_ = native_info.display_modes_; touch_support_ = native_info.touch_support_; // Copy overscan_insets_in_dip_ if it's not empty. This is for test @@ -249,22 +274,28 @@ std::string DisplayInfo::ToString() const { overscan_insets_in_dip_.ToString().c_str(), rotation_degree, configured_ui_scale_, - touch_support_ == gfx::Display::TOUCH_SUPPORT_AVAILABLE ? "yes" : - touch_support_ == gfx::Display::TOUCH_SUPPORT_UNAVAILABLE ? "no" : - "unknown"); + touch_support_ == gfx::Display::TOUCH_SUPPORT_AVAILABLE + ? "yes" + : touch_support_ == gfx::Display::TOUCH_SUPPORT_UNAVAILABLE + ? "no" + : "unknown"); } std::string DisplayInfo::ToFullString() const { - std::string resolutions_str; - std::vector<Resolution>::const_iterator iter = resolutions_.begin(); - for (; iter != resolutions_.end(); ++iter) { - if (!resolutions_str.empty()) - resolutions_str += ","; - resolutions_str += iter->size.ToString(); - if (iter->interlaced) - resolutions_str += "(i)"; + std::string display_modes_str; + std::vector<DisplayMode>::const_iterator iter = display_modes_.begin(); + for (; iter != display_modes_.end(); ++iter) { + if (!display_modes_str.empty()) + display_modes_str += ","; + base::StringAppendF(&display_modes_str, + "(%dx%d@%f%c%s)", + iter->size.width(), + iter->size.height(), + iter->refresh_rate, + iter->interlaced ? 'I' : 'P', + iter->native ? "(N)" : ""); } - return ToString() + ", resolutions=" + resolutions_str; + return ToString() + ", display_modes==" + display_modes_str; } } // namespace internal diff --git a/ash/display/display_info.h b/ash/display/display_info.h index ca6f270..ccb989a 100644 --- a/ash/display/display_info.h +++ b/ash/display/display_info.h @@ -16,13 +16,18 @@ namespace ash { namespace internal { -// A struct that represents the display's resolution and -// interlaced info. -struct ASH_EXPORT Resolution { - Resolution(const gfx::Size& size, bool interlaced); - - gfx::Size size; - bool interlaced; +// A struct that represents the display's mode info. +struct ASH_EXPORT DisplayMode { + DisplayMode(); + DisplayMode(const gfx::Size& size, + float refresh_rate, + bool interlaced, + bool native); + + gfx::Size size; // Physical pixel size of the display. + float refresh_rate; // Refresh rate of the display, in Hz. + bool interlaced; // True if mode is interlaced. + bool native; // True if mode is native mode of the display. }; // DisplayInfo contains metadata for each display. This is used to @@ -47,7 +52,7 @@ class ASH_EXPORT DisplayInfo { // 270 degrees (to the 'l'eft). // - ui-scale is floating value, e.g. @1.5 or @1.25. // - |resolution list| is the list of size that is given in - // |width x height| separated by '|'. + // |width x height [% refresh_rate]| separated by '|'. // // A couple of examples: // "100x100" @@ -63,9 +68,9 @@ class ASH_EXPORT DisplayInfo { // "10+20-300x200/u@1.5" // 300x200 window at 10,20 origin. 1x device scale factor. // no overscan. flipped upside-down (180 degree) and 1.5 ui scale. - // "200x100#300x200|200x100|100x100" + // "200x100#300x200|200x100%59.0|100x100%60" // 200x100 window at 0,0 origin, with 3 possible resolutions, - // 300x200, 200x100 and 100x100. + // 300x200, 200x100 at 59 Hz, and 100x100 at 60 Hz. static DisplayInfo CreateFromSpec(const std::string& spec); // Creates a DisplayInfo from string spec using given |id|. @@ -142,19 +147,19 @@ class ASH_EXPORT DisplayInfo { void set_native(bool native) { native_ = native; } bool native() const { return native_; } - const std::vector<Resolution>& resolutions() const { - return resolutions_; + const std::vector<DisplayMode>& display_modes() const { + return display_modes_; } - void set_resolutions(std::vector<Resolution>& resolution) { - resolutions_.swap(resolution); + void set_display_modes(std::vector<DisplayMode>& display_modes) { + display_modes_.swap(display_modes); } - // Returns a string representation of the DisplayInfo - // excluding resolutions. + // Returns a string representation of the DisplayInfo, excluding display + // modes. std::string ToString() const; - // Returns a string representation of the DisplayInfo - // including resolutions. + // Returns a string representation of the DisplayInfo, including display + // modes. std::string ToFullString() const; private: @@ -188,8 +193,8 @@ class ASH_EXPORT DisplayInfo { // True if this comes from native platform (DisplayChangeObserver). bool native_; - // The list of resolutions supported by this display. - std::vector<Resolution> resolutions_; + // The list of modes supported by this display. + std::vector<DisplayMode> display_modes_; }; } // namespace internal diff --git a/ash/display/display_info_unittest.cc b/ash/display/display_info_unittest.cc index 9faa0aa..50c06cf 100644 --- a/ash/display/display_info_unittest.cc +++ b/ash/display/display_info_unittest.cc @@ -45,12 +45,17 @@ TEST_F(DisplayInfoTest, CreateFromSpec) { EXPECT_EQ(1.5f, info.configured_ui_scale()); info = DisplayInfo::CreateFromSpecWithID( - "200x200#300x200|200x200|100x100", 10); + "200x200#300x200|200x200%59.9|100x100%60", 10); EXPECT_EQ("0,0 200x200", info.bounds_in_native().ToString()); - EXPECT_EQ(3u, info.resolutions().size()); - EXPECT_EQ("300x200", info.resolutions()[0].size.ToString()); - EXPECT_EQ("200x200", info.resolutions()[1].size.ToString()); - EXPECT_EQ("100x100", info.resolutions()[2].size.ToString()); + EXPECT_EQ(3u, info.display_modes().size()); + EXPECT_EQ("300x200", info.display_modes()[0].size.ToString()); + EXPECT_EQ("200x200", info.display_modes()[1].size.ToString()); + EXPECT_EQ("100x100", info.display_modes()[2].size.ToString()); + EXPECT_EQ(59.9f, info.display_modes()[1].refresh_rate); + EXPECT_EQ(60.0f, info.display_modes()[2].refresh_rate); + EXPECT_TRUE(info.display_modes()[0].native); + EXPECT_FALSE(info.display_modes()[1].native); + EXPECT_FALSE(info.display_modes()[2].native); } } // namespace internal diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc index 6343aa0..b911bdd 100644 --- a/ash/display/display_manager.cc +++ b/ash/display/display_manager.cc @@ -78,11 +78,9 @@ struct DisplayInfoSortFunctor { } }; -struct ResolutionMatcher { - explicit ResolutionMatcher(const gfx::Size& size) : size(size) {} - bool operator()(const Resolution& resolution) { - return resolution.size == size; - } +struct DisplayModeMatcher { + DisplayModeMatcher(const gfx::Size& size) : size(size) {} + bool operator()(const DisplayMode& mode) { return mode.size == size; } gfx::Size size; }; @@ -446,22 +444,16 @@ void DisplayManager::SetDisplayResolution(int64 display_id, if (gfx::Display::InternalDisplayId() == display_id) return; const DisplayInfo& display_info = GetDisplayInfo(display_id); - const std::vector<Resolution>& resolutions = display_info.resolutions(); - DCHECK_NE(0u, resolutions.size()); - std::vector<Resolution>::const_iterator iter = - std::find_if(resolutions.begin(), - resolutions.end(), - ResolutionMatcher(resolution)); - if (iter == resolutions.end()) { + const std::vector<DisplayMode>& modes = display_info.display_modes(); + DCHECK_NE(0u, modes.size()); + std::vector<DisplayMode>::const_iterator iter = + std::find_if(modes.begin(), modes.end(), DisplayModeMatcher(resolution)); + if (iter == modes.end()) { LOG(WARNING) << "Unsupported resolution was requested:" << resolution.ToString(); return; - } else if (iter == resolutions.begin()) { - // The best resolution was set, so forget it. - resolutions_.erase(display_id); - } else { - resolutions_[display_id] = resolution; } + display_modes_[display_id] = *iter; #if defined(OS_CHROMEOS) && defined(USE_X11) if (base::SysInfo::IsRunningOnChromeOS()) Shell::GetInstance()->output_configurator()->ScheduleConfigureOutputs(); @@ -483,18 +475,20 @@ void DisplayManager::RegisterDisplayProperty( display_info_[display_id].set_configured_ui_scale(ui_scale); if (overscan_insets) display_info_[display_id].SetOverscanInsets(*overscan_insets); - if (!resolution_in_pixels.IsEmpty()) - resolutions_[display_id] = resolution_in_pixels; + if (!resolution_in_pixels.IsEmpty()) { + // Default refresh rate, until OnNativeDisplaysChanged() updates us with the + // actual display info, is 60 Hz. + display_modes_[display_id] = + DisplayMode(resolution_in_pixels, 60.0f, false, false); + } } -bool DisplayManager::GetSelectedResolutionForDisplayId( - int64 id, - gfx::Size* resolution_out) const { - std::map<int64, gfx::Size>::const_iterator iter = - resolutions_.find(id); - if (iter == resolutions_.end()) +bool DisplayManager::GetSelectedModeForDisplayId(int64 id, + DisplayMode* mode_out) const { + std::map<int64, DisplayMode>::const_iterator iter = display_modes_.find(id); + if (iter == display_modes_.end()) return false; - *resolution_out = iter->second; + *mode_out = iter->second; return true; } @@ -568,19 +562,19 @@ void DisplayManager::OnNativeDisplaysChanged( } const gfx::Size& resolution = iter->bounds_in_native().size(); - const std::vector<Resolution>& resolutions = iter->resolutions(); + const std::vector<DisplayMode>& display_modes = iter->display_modes(); // This is empty the displays are initialized from InitFromCommandLine. - if (!resolutions.size()) + if (!display_modes.size()) continue; - std::vector<Resolution>::const_iterator resolution_iter = - std::find_if(resolutions.begin(), - resolutions.end(), - ResolutionMatcher(resolution)); + std::vector<DisplayMode>::const_iterator display_modes_iter = + std::find_if(display_modes.begin(), + display_modes.end(), + DisplayModeMatcher(resolution)); // Update the actual resolution selected as the resolution request may fail. - if (resolution_iter == resolutions.begin()) - resolutions_.erase(iter->id()); - else if (resolutions_.find(iter->id()) != resolutions_.end()) - resolutions_[iter->id()] = resolution; + if (display_modes_iter == display_modes.end()) + display_modes_.erase(iter->id()); + else if (display_modes_.find(iter->id()) != display_modes_.end()) + display_modes_[iter->id()] = *display_modes_iter; } if (HasInternalDisplay() && !internal_display_connected && @@ -661,7 +655,7 @@ void DisplayManager::UpdateDisplays( non_desktop_display_ = CreateDisplayFromDisplayInfoById(non_desktop_display_id); ++new_info_iter; - // Remove existing external dispaly if it is going to be used as + // Remove existing external display if it is going to be used as // non desktop. if (curr_iter != displays_.end() && curr_iter->id() == non_desktop_display_id) { diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h index 3450a5d..a397c89 100644 --- a/ash/display/display_manager.h +++ b/ash/display/display_manager.h @@ -176,9 +176,9 @@ class ASH_EXPORT DisplayManager const gfx::Insets* overscan_insets, const gfx::Size& resolution_in_pixels); - // Returns the display's selected resolution. - bool GetSelectedResolutionForDisplayId(int64 display_id, - gfx::Size* resolution_out) const; + // Returns the display's selected mode. + bool GetSelectedModeForDisplayId(int64 display_id, + DisplayMode* mode_out) const; // Tells if the virtual resolution feature is enabled. bool IsDisplayUIScalingEnabled() const; @@ -340,8 +340,8 @@ private: // The mapping from the display ID to its internal data. std::map<int64, DisplayInfo> display_info_; - // Selected resolutions in pixels for displays. Key is the displays' ID. - std::map<int64, gfx::Size> resolutions_; + // Selected display modes for displays. Key is the displays' ID. + std::map<int64, DisplayMode> display_modes_; // When set to true, the host window's resize event updates // the display's size. This is set to true when running on diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc index 9300ccc8..5b43b1b 100644 --- a/ash/display/display_manager_unittest.cc +++ b/ash/display/display_manager_unittest.cc @@ -719,49 +719,60 @@ TEST_F(DisplayManagerTest, DontRememberBestResolution) { int display_id = 1000; DisplayInfo native_display_info = CreateDisplayInfo(display_id, gfx::Rect(0, 0, 1000, 500)); - std::vector<Resolution> resolutions; - resolutions.push_back(Resolution(gfx::Size(1000, 500), false)); - resolutions.push_back(Resolution(gfx::Size(800, 300), false)); - resolutions.push_back(Resolution(gfx::Size(400, 500), false)); + std::vector<DisplayMode> display_modes; + display_modes.push_back( + DisplayMode(gfx::Size(1000, 500), 58.0f, false, true)); + display_modes.push_back( + DisplayMode(gfx::Size(800, 300), 59.0f, false, false)); + display_modes.push_back( + DisplayMode(gfx::Size(400, 500), 60.0f, false, false)); - native_display_info.set_resolutions(resolutions); + native_display_info.set_display_modes(display_modes); std::vector<DisplayInfo> display_info_list; display_info_list.push_back(native_display_info); display_manager()->OnNativeDisplaysChanged(display_info_list); - gfx::Size selected; - EXPECT_FALSE(display_manager()->GetSelectedResolutionForDisplayId( - display_id, &selected)); + DisplayMode mode; + EXPECT_FALSE( + display_manager()->GetSelectedModeForDisplayId(display_id, &mode)); // Unsupported resolution. display_manager()->SetDisplayResolution(display_id, gfx::Size(800, 4000)); - EXPECT_FALSE(display_manager()->GetSelectedResolutionForDisplayId( - display_id, &selected)); + EXPECT_FALSE( + display_manager()->GetSelectedModeForDisplayId(display_id, &mode)); // Supported resolution. display_manager()->SetDisplayResolution(display_id, gfx::Size(800, 300)); - EXPECT_TRUE(display_manager()->GetSelectedResolutionForDisplayId( - display_id, &selected)); - EXPECT_EQ("800x300", selected.ToString()); + EXPECT_TRUE( + display_manager()->GetSelectedModeForDisplayId(display_id, &mode)); + EXPECT_EQ("800x300", mode.size.ToString()); + EXPECT_EQ(59.0f, mode.refresh_rate); + EXPECT_FALSE(mode.native); // Best resolution. display_manager()->SetDisplayResolution(display_id, gfx::Size(1000, 500)); - EXPECT_FALSE(display_manager()->GetSelectedResolutionForDisplayId( - display_id, &selected)); + EXPECT_TRUE( + display_manager()->GetSelectedModeForDisplayId(display_id, &mode)); + EXPECT_EQ("1000x500", mode.size.ToString()); + EXPECT_EQ(58.0f, mode.refresh_rate); + EXPECT_TRUE(mode.native); } TEST_F(DisplayManagerTest, ResolutionFallback) { int display_id = 1000; DisplayInfo native_display_info = CreateDisplayInfo(display_id, gfx::Rect(0, 0, 1000, 500)); - std::vector<Resolution> resolutions; - resolutions.push_back(Resolution(gfx::Size(1000, 500), false)); - resolutions.push_back(Resolution(gfx::Size(800, 300), false)); - resolutions.push_back(Resolution(gfx::Size(400, 500), false)); + std::vector<DisplayMode> display_modes; + display_modes.push_back( + DisplayMode(gfx::Size(1000, 500), 58.0f, false, true)); + display_modes.push_back( + DisplayMode(gfx::Size(800, 300), 59.0f, false, false)); + display_modes.push_back( + DisplayMode(gfx::Size(400, 500), 60.0f, false, false)); - std::vector<Resolution> copy = resolutions; - native_display_info.set_resolutions(copy); + std::vector<DisplayMode> copy = display_modes; + native_display_info.set_display_modes(copy); std::vector<DisplayInfo> display_info_list; display_info_list.push_back(native_display_info); @@ -770,31 +781,36 @@ TEST_F(DisplayManagerTest, ResolutionFallback) { display_manager()->SetDisplayResolution(display_id, gfx::Size(800, 300)); DisplayInfo new_native_display_info = CreateDisplayInfo(display_id, gfx::Rect(0, 0, 400, 500)); - copy = resolutions; - new_native_display_info.set_resolutions(copy); + copy = display_modes; + new_native_display_info.set_display_modes(copy); std::vector<DisplayInfo> new_display_info_list; new_display_info_list.push_back(new_native_display_info); display_manager()->OnNativeDisplaysChanged(new_display_info_list); - gfx::Size selected; - EXPECT_TRUE(display_manager()->GetSelectedResolutionForDisplayId( - display_id, &selected)); - EXPECT_EQ("400x500", selected.ToString()); + DisplayMode mode; + EXPECT_TRUE( + display_manager()->GetSelectedModeForDisplayId(display_id, &mode)); + EXPECT_EQ("400x500", mode.size.ToString()); + EXPECT_EQ(60.0f, mode.refresh_rate); + EXPECT_FALSE(mode.native); } { - // Best resolution should not be set. + // Best resolution should find itself on the resolutions list. display_manager()->SetDisplayResolution(display_id, gfx::Size(800, 300)); DisplayInfo new_native_display_info = CreateDisplayInfo(display_id, gfx::Rect(0, 0, 1000, 500)); - std::vector<Resolution> copy = resolutions; - new_native_display_info.set_resolutions(copy); + std::vector<DisplayMode> copy = display_modes; + new_native_display_info.set_display_modes(copy); std::vector<DisplayInfo> new_display_info_list; new_display_info_list.push_back(new_native_display_info); display_manager()->OnNativeDisplaysChanged(new_display_info_list); - gfx::Size selected; - EXPECT_FALSE(display_manager()->GetSelectedResolutionForDisplayId( - display_id, &selected)); + DisplayMode mode; + EXPECT_TRUE( + display_manager()->GetSelectedModeForDisplayId(display_id, &mode)); + EXPECT_EQ("1000x500", mode.size.ToString()); + EXPECT_EQ(58.0f, mode.refresh_rate); + EXPECT_TRUE(mode.native); } } diff --git a/ash/display/resolution_notification_controller_unittest.cc b/ash/display/resolution_notification_controller_unittest.cc index afbc4a7..e3b2740 100644 --- a/ash/display/resolution_notification_controller_unittest.cc +++ b/ash/display/resolution_notification_controller_unittest.cc @@ -157,7 +157,7 @@ TEST_F(ResolutionNotificationControllerTest, Basic) { if (!SupportsMultipleDisplays()) return; - UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200"); + UpdateDisplay("300x300#300x300%57|200x200%58,250x250#250x250%59|200x200%60"); int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); @@ -171,25 +171,26 @@ TEST_F(ResolutionNotificationControllerTest, Basic) { EXPECT_FALSE(controller()->DoesNotificationTimeout()); EXPECT_EQ(ExpectedNotificationMessage(id2, gfx::Size(200, 200)), GetNotificationMessage()); - gfx::Size resolution; - EXPECT_TRUE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + DisplayMode mode; + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(60.0, mode.refresh_rate); // Click the revert button, which reverts to the best resolution. ClickOnNotificationButton(0); RunAllPendingInMessageLoop(); EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(0, accept_count()); - EXPECT_FALSE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("250x250", mode.size.ToString()); + EXPECT_EQ(59.0, mode.refresh_rate); } TEST_F(ResolutionNotificationControllerTest, ClickMeansAccept) { if (!SupportsMultipleDisplays()) return; - UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200"); + UpdateDisplay("300x300#300x300%57|200x200%58,250x250#250x250%59|200x200%60"); int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); @@ -201,19 +202,19 @@ TEST_F(ResolutionNotificationControllerTest, ClickMeansAccept) { ScreenUtil::GetSecondaryDisplay(), gfx::Size(200, 200)); EXPECT_TRUE(IsNotificationVisible()); EXPECT_FALSE(controller()->DoesNotificationTimeout()); - gfx::Size resolution; - EXPECT_TRUE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + DisplayMode mode; + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(60.0, mode.refresh_rate); // Click the revert button, which reverts the resolution. ClickOnNotification(); RunAllPendingInMessageLoop(); EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(1, accept_count()); - EXPECT_TRUE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(60.0, mode.refresh_rate); } TEST_F(ResolutionNotificationControllerTest, AcceptButton) { @@ -223,7 +224,7 @@ TEST_F(ResolutionNotificationControllerTest, AcceptButton) { ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); - UpdateDisplay("300x300#300x300|200x200"); + UpdateDisplay("300x300#300x300%59|200x200%60"); const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay(); SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); EXPECT_TRUE(IsNotificationVisible()); @@ -234,13 +235,14 @@ TEST_F(ResolutionNotificationControllerTest, AcceptButton) { ClickOnNotificationButton(0); EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(1, accept_count()); - gfx::Size resolution; - EXPECT_TRUE(display_manager->GetSelectedResolutionForDisplayId( - display.id(), &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + DisplayMode mode; + EXPECT_TRUE( + display_manager->GetSelectedModeForDisplayId(display.id(), &mode)); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(60.0f, mode.refresh_rate); // In that case the second button is revert. - UpdateDisplay("300x300#300x300|200x200"); + UpdateDisplay("300x300#300x300%59|200x200%60"); SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); EXPECT_TRUE(IsNotificationVisible()); @@ -248,15 +250,17 @@ TEST_F(ResolutionNotificationControllerTest, AcceptButton) { ClickOnNotificationButton(1); EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(1, accept_count()); - EXPECT_FALSE(display_manager->GetSelectedResolutionForDisplayId( - display.id(), &resolution)); + EXPECT_TRUE( + display_manager->GetSelectedModeForDisplayId(display.id(), &mode)); + EXPECT_EQ("300x300", mode.size.ToString()); + EXPECT_EQ(59.0f, mode.refresh_rate); } TEST_F(ResolutionNotificationControllerTest, Close) { if (!SupportsMultipleDisplays()) return; - UpdateDisplay("100x100,150x150#150x150|200x200"); + UpdateDisplay("100x100,150x150#150x150%59|200x200%60"); int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); @@ -268,10 +272,10 @@ TEST_F(ResolutionNotificationControllerTest, Close) { ScreenUtil::GetSecondaryDisplay(), gfx::Size(200, 200)); EXPECT_TRUE(IsNotificationVisible()); EXPECT_FALSE(controller()->DoesNotificationTimeout()); - gfx::Size resolution; - EXPECT_TRUE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + DisplayMode mode; + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(60.0f, mode.refresh_rate); // Close the notification (imitates clicking [x] button). Also verifies if // this does not cause a crash. See crbug.com/271784 @@ -285,7 +289,7 @@ TEST_F(ResolutionNotificationControllerTest, Timeout) { if (!SupportsMultipleDisplays()) return; - UpdateDisplay("300x300#300x300|200x200"); + UpdateDisplay("300x300#300x300%59|200x200%60"); const gfx::Display& display = ash::Shell::GetScreen()->GetPrimaryDisplay(); SetDisplayResolutionAndNotify(display, gfx::Size(200, 200)); @@ -297,18 +301,21 @@ TEST_F(ResolutionNotificationControllerTest, Timeout) { } EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(0, accept_count()); - gfx::Size resolution; ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); - EXPECT_FALSE(display_manager->GetSelectedResolutionForDisplayId( - display.id(), &resolution)); + DisplayMode mode; + EXPECT_TRUE( + display_manager->GetSelectedModeForDisplayId(display.id(), &mode)); + EXPECT_EQ("300x300", mode.size.ToString()); + EXPECT_EQ(59.0f, mode.refresh_rate); } TEST_F(ResolutionNotificationControllerTest, DisplayDisconnected) { if (!SupportsMultipleDisplays()) return; - UpdateDisplay("300x300#300x300|200x200,200x200#250x250|200x200|100x100"); + UpdateDisplay("300x300#300x300%56|200x200%57," + "200x200#250x250%58|200x200%59|100x100%60"); int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); @@ -317,21 +324,23 @@ TEST_F(ResolutionNotificationControllerTest, DisplayDisconnected) { ASSERT_TRUE(IsNotificationVisible()); // Disconnects the secondary display and verifies it doesn't cause crashes. - UpdateDisplay("300x300#300x300|200x200"); + UpdateDisplay("300x300#300x300%56|200x200%57"); RunAllPendingInMessageLoop(); EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(0, accept_count()); + DisplayMode mode; + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); gfx::Size resolution; - EXPECT_TRUE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(59.0f, mode.refresh_rate); } TEST_F(ResolutionNotificationControllerTest, MultipleResolutionChange) { if (!SupportsMultipleDisplays()) return; - UpdateDisplay("300x300#300x300|200x200,250x250#250x250|200x200"); + UpdateDisplay("300x300#300x300%56|200x200%57," + "250x250#250x250%58|200x200%59"); int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); @@ -340,34 +349,37 @@ TEST_F(ResolutionNotificationControllerTest, MultipleResolutionChange) { ScreenUtil::GetSecondaryDisplay(), gfx::Size(200, 200)); EXPECT_TRUE(IsNotificationVisible()); EXPECT_FALSE(controller()->DoesNotificationTimeout()); - gfx::Size resolution; - EXPECT_TRUE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + DisplayMode mode; + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(59.0f, mode.refresh_rate); // Invokes SetDisplayResolutionAndNotify during the previous notification is // visible. SetDisplayResolutionAndNotify( ScreenUtil::GetSecondaryDisplay(), gfx::Size(250, 250)); - EXPECT_FALSE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("250x250", mode.size.ToString()); + EXPECT_EQ(58.0f, mode.refresh_rate); // Then, click the revert button. Although |old_resolution| for the second // SetDisplayResolutionAndNotify is 200x200, it should revert to the original - // size 150x150. + // size 250x250. ClickOnNotificationButton(0); RunAllPendingInMessageLoop(); EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(0, accept_count()); - EXPECT_FALSE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("250x250", mode.size.ToString()); + EXPECT_EQ(58.0f, mode.refresh_rate); } TEST_F(ResolutionNotificationControllerTest, Fallback) { if (!SupportsMultipleDisplays()) return; - UpdateDisplay("300x300#300x300|200x200,250x250#250x250|220x220|200x200"); + UpdateDisplay("300x300#300x300%56|200x200%57," + "250x250#250x250%58|220x220%59|200x200%60"); int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); ash::internal::DisplayManager* display_manager = ash::Shell::GetInstance()->display_manager(); @@ -385,18 +397,19 @@ TEST_F(ResolutionNotificationControllerTest, Fallback) { ExpectedFallbackNotificationMessage( id2, gfx::Size(220, 220), gfx::Size(200, 200)), GetNotificationMessage()); - gfx::Size resolution; - EXPECT_TRUE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); - EXPECT_EQ("200x200", resolution.ToString()); + DisplayMode mode; + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("200x200", mode.size.ToString()); + EXPECT_EQ(60.0f, mode.refresh_rate); // Click the revert button, which reverts to the best resolution. ClickOnNotificationButton(0); RunAllPendingInMessageLoop(); EXPECT_FALSE(IsNotificationVisible()); EXPECT_EQ(0, accept_count()); - EXPECT_FALSE( - display_manager->GetSelectedResolutionForDisplayId(id2, &resolution)); + EXPECT_TRUE(display_manager->GetSelectedModeForDisplayId(id2, &mode)); + EXPECT_EQ("250x250", mode.size.ToString()); + EXPECT_EQ(58.0f, mode.refresh_rate); } } // namespace internal diff --git a/ash/wm/window_animations.cc b/ash/wm/window_animations.cc index aad40c9..3a3e059 100644 --- a/ash/wm/window_animations.cc +++ b/ash/wm/window_animations.cc @@ -286,10 +286,6 @@ class CrossFadeObserver : public ui::CompositorObserver, virtual void OnCompositingLockStateChanged( ui::Compositor* compositor) OVERRIDE { } - virtual void OnUpdateVSyncParameters(ui::Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) OVERRIDE { - } // aura::WindowObserver overrides: virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc index 9ba6dbb..87d6e84 100644 --- a/cc/output/output_surface.cc +++ b/cc/output/output_surface.cc @@ -117,11 +117,14 @@ void OutputSurface::SetMaxFramesPending(int max_frames_pending) { max_frames_pending_ = max_frames_pending; } -void OutputSurface::OnVSyncParametersChanged(base::TimeTicks timebase, - base::TimeDelta interval) { - TRACE_EVENT2("cc", "OutputSurface::OnVSyncParametersChanged", - "timebase", (timebase - base::TimeTicks()).InSecondsF(), - "interval", interval.InSecondsF()); +void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + TRACE_EVENT2("cc", + "OutputSurface::CommitVSyncParameters", + "timebase", + (timebase - base::TimeTicks()).InSecondsF(), + "interval", + interval.InSecondsF()); if (frame_rate_controller_) frame_rate_controller_->SetTimebaseAndInterval(timebase, interval); } diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h index 4478754..b751f06 100644 --- a/cc/output/output_surface.h +++ b/cc/output/output_surface.h @@ -159,8 +159,8 @@ class CC_EXPORT OutputSurface : public FrameRateControllerClient { // The FrameRateController is deprecated. // Platforms should move to native BeginImplFrames instead. - void OnVSyncParametersChanged(base::TimeTicks timebase, - base::TimeDelta interval); + void CommitVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval); virtual void FrameRateControllerTick(bool throttled, const BeginFrameArgs& args) OVERRIDE; scoped_ptr<FrameRateController> frame_rate_controller_; diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc index 73a76a3..b0220fb 100644 --- a/cc/output/output_surface_unittest.cc +++ b/cc/output/output_surface_unittest.cc @@ -46,9 +46,9 @@ class TestOutputSurface : public OutputSurface { using OutputSurface::ReleaseGL; - void OnVSyncParametersChangedForTesting(base::TimeTicks timebase, - base::TimeDelta interval) { - OnVSyncParametersChanged(timebase, interval); + void CommitVSyncParametersForTesting(base::TimeTicks timebase, + base::TimeDelta interval) { + CommitVSyncParameters(timebase, interval); } void BeginImplFrameForTesting() { @@ -387,7 +387,7 @@ TEST(OutputSurfaceTest, // We need to subtract an epsilon from Now() because some platforms have // a slow clock. - output_surface.OnVSyncParametersChangedForTesting( + output_surface.CommitVSyncParametersForTesting( gfx::FrameTime::Now() - base::TimeDelta::FromSeconds(1), big_interval); output_surface.SetMaxFramesPending(2); diff --git a/chrome/browser/chromeos/display/display_preferences.cc b/chrome/browser/chromeos/display/display_preferences.cc index ab7697b..b41f056 100644 --- a/chrome/browser/chromeos/display/display_preferences.cc +++ b/chrome/browser/chromeos/display/display_preferences.cc @@ -199,11 +199,12 @@ void StoreCurrentDisplayProperties() { property_value->SetInteger( "ui-scale", static_cast<int>(info.configured_ui_scale() * 1000)); - gfx::Size resolution; + ash::internal::DisplayMode mode; if (!display.IsInternal() && - display_manager->GetSelectedResolutionForDisplayId(id, &resolution)) { - property_value->SetInteger("width", resolution.width()); - property_value->SetInteger("height", resolution.height()); + display_manager->GetSelectedModeForDisplayId(id, &mode) && + !mode.native) { + property_value->SetInteger("width", mode.size.width()); + property_value->SetInteger("height", mode.size.height()); } if (!info.overscan_insets_in_dip().empty()) diff --git a/chrome/browser/chromeos/display/display_preferences_unittest.cc b/chrome/browser/chromeos/display/display_preferences_unittest.cc index 03d604e..3abfaa5 100644 --- a/chrome/browser/chromeos/display/display_preferences_unittest.cc +++ b/chrome/browser/chromeos/display/display_preferences_unittest.cc @@ -231,7 +231,7 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_EQ(1, rotation); EXPECT_EQ(1250, ui_scale); - // Internal display never registere the resolution. + // Internal display never registered the resolution. int width = 0, height = 0; EXPECT_FALSE(property->GetInteger("width", &width)); EXPECT_FALSE(property->GetInteger("height", &height)); @@ -271,11 +271,11 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property)); width = 0; height = 0; - // Internal dispaly shouldn't store its resolution. + // Internal display shouldn't store its resolution. EXPECT_FALSE(property->GetInteger("width", &width)); EXPECT_FALSE(property->GetInteger("height", &height)); - // External dispaly's resolution must be stored this time because + // External display's resolution must be stored this time because // it's not best. EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); EXPECT_TRUE(property->GetInteger("width", &width)); @@ -320,7 +320,7 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_FALSE(property->GetInteger("width", &width)); EXPECT_FALSE(property->GetInteger("height", &height)); - // External dispaly's selected resolution must not change + // External display's selected resolution must not change // by mirroring. EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); EXPECT_TRUE(property->GetInteger("width", &width)); @@ -329,11 +329,8 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_EQ(200, height); // Set new display's selected resolution. - display_manager->RegisterDisplayProperty(id2 + 1, - gfx::Display::ROTATE_0, - 1.0f, - NULL, - gfx::Size(500, 400)); + display_manager->RegisterDisplayProperty( + id2 + 1, gfx::Display::ROTATE_0, 1.0f, NULL, gfx::Size(500, 400)); UpdateDisplay("200x200*2, 600x500#600x500|500x400"); @@ -357,14 +354,11 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_FALSE(property->GetInteger("height", &height)); // Set yet another new display's selected resolution. - display_manager->RegisterDisplayProperty(id2 + 1, - gfx::Display::ROTATE_0, - 1.0f, - NULL, - gfx::Size(500, 400)); + display_manager->RegisterDisplayProperty( + id2 + 1, gfx::Display::ROTATE_0, 1.0f, NULL, gfx::Size(500, 400)); // Disconnect 2nd display first to generate new id for external display. UpdateDisplay("200x200*2"); - UpdateDisplay("200x200*2, 500x400#600x500|500x400"); + UpdateDisplay("200x200*2, 500x400#600x500|500x400%60.0f"); // Update key as the 2nd display gets new id. id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); @@ -379,7 +373,7 @@ TEST_F(DisplayPreferencesTest, BasicStores) { EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); EXPECT_EQ(base::Int64ToString(id1), primary_id_str); - // External dispaly's selected resolution must be updated. + // External display's selected resolution must be updated. EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); EXPECT_TRUE(property->GetInteger("width", &width)); EXPECT_TRUE(property->GetInteger("height", &height)); diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc index eff7e64..528dc20 100644 --- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc @@ -54,9 +54,11 @@ int64 GetDisplayId(const base::ListValue* args) { return display_id; } -bool CompareResolution(ash::internal::Resolution r1, - ash::internal::Resolution r2) { - return r1.size.GetArea() < r2.size.GetArea(); +bool CompareDisplayMode(ash::internal::DisplayMode d1, + ash::internal::DisplayMode d2) { + if (d1.size.GetArea() == d2.size.GetArea()) + return d1.refresh_rate < d2.refresh_rate; + return d1.size.GetArea() < d2.size.GetArea(); } } // namespace @@ -187,7 +189,7 @@ void DisplayOptionsHandler::SendDisplayInfo( js_display->SetBoolean("isInternal", display.IsInternal()); js_display->SetInteger("orientation", static_cast<int>(display_info.rotation())); - std::vector<ash::internal::Resolution> resolutions; + std::vector<ash::internal::DisplayMode> display_modes; std::vector<float> ui_scales; if (display.IsInternal()) { ui_scales = DisplayManager::GetScalesForDisplay(display_info); @@ -202,21 +204,21 @@ void DisplayOptionsHandler::SendDisplayInfo( for (size_t i = 0; i < ui_scales.size(); ++i) { gfx::SizeF new_size = base_size; new_size.Scale(ui_scales[i]); - resolutions.push_back(ash::internal::Resolution( - gfx::ToFlooredSize(new_size), false /* interlaced */)); + display_modes.push_back(ash::internal::DisplayMode( + gfx::ToFlooredSize(new_size), -1.0f, false, false)); } } else { - for (size_t i = 0; i < display_info.resolutions().size(); ++i) - resolutions.push_back(display_info.resolutions()[i]); + for (size_t i = 0; i < display_info.display_modes().size(); ++i) + display_modes.push_back(display_info.display_modes()[i]); } - std::sort(resolutions.begin(), resolutions.end(), CompareResolution); + std::sort(display_modes.begin(), display_modes.end(), CompareDisplayMode); base::ListValue* js_resolutions = new base::ListValue(); gfx::Size current_size = display_info.bounds_in_native().size(); gfx::Insets current_overscan = display_info.GetOverscanInsetsInPixel(); - for (size_t i = 0; i < resolutions.size(); ++i) { + for (size_t i = 0; i < display_modes.size(); ++i) { base::DictionaryValue* resolution_info = new base::DictionaryValue(); - gfx::Size resolution = resolutions[i].size; + gfx::Size resolution = display_modes[i].size; if (!ui_scales.empty()) { resolution_info->SetDouble("scale", ui_scales[i]); if (ui_scales[i] == 1.0f) @@ -225,8 +227,8 @@ void DisplayOptionsHandler::SendDisplayInfo( "selected", display_info.configured_ui_scale() == ui_scales[i]); } else { // Picks the largest one as the "best", which is the last element - // because |resolutions| is sorted by its area. - if (i == resolutions.size() - 1) + // because |display_modes| is sorted by its area. + if (i == display_modes.size() - 1) resolution_info->SetBoolean("isBest", true); resolution_info->SetBoolean("selected", (resolution == current_size)); resolution.Enlarge( @@ -234,6 +236,10 @@ void DisplayOptionsHandler::SendDisplayInfo( } resolution_info->SetInteger("width", resolution.width()); resolution_info->SetInteger("height", resolution.height()); + if (display_modes[i].refresh_rate > 0.0f) { + resolution_info->SetDouble("refreshRate", + display_modes[i].refresh_rate); + } js_resolutions->Append(resolution_info); } js_display->Set("resolutions", js_resolutions); @@ -352,11 +358,11 @@ void DisplayOptionsHandler::HandleSetResolution(const base::ListValue* args) { gfx::Size old_resolution = display_info.bounds_in_native().size(); bool has_new_resolution = false; bool has_old_resolution = false; - for (size_t i = 0; i < display_info.resolutions().size(); ++i) { - ash::internal::Resolution resolution = display_info.resolutions()[i]; - if (resolution.size == new_resolution) + for (size_t i = 0; i < display_info.display_modes().size(); ++i) { + ash::internal::DisplayMode display_mode = display_info.display_modes()[i]; + if (display_mode.size == new_resolution) has_new_resolution = true; - if (resolution.size == old_resolution) + if (display_mode.size == old_resolution) has_old_resolution = true; } if (!has_new_resolution) { diff --git a/content/browser/compositor/browser_compositor_output_surface.cc b/content/browser/compositor/browser_compositor_output_surface.cc index 30ff485..ff09ab7 100644 --- a/content/browser/compositor/browser_compositor_output_surface.cc +++ b/content/browser/compositor/browser_compositor_output_surface.cc @@ -7,11 +7,9 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/location.h" -#include "base/message_loop/message_loop_proxy.h" #include "base/strings/string_number_conversions.h" #include "content/browser/compositor/reflector_impl.h" #include "content/common/gpu/client/context_provider_command_buffer.h" -#include "ui/compositor/compositor.h" #include "ui/compositor/compositor_switches.h" namespace content { @@ -20,13 +18,11 @@ BrowserCompositorOutputSurface::BrowserCompositorOutputSurface( const scoped_refptr<ContextProviderCommandBuffer>& context_provider, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor) + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager) : OutputSurface(context_provider), surface_id_(surface_id), output_surface_map_(output_surface_map), - compositor_message_loop_(compositor_message_loop), - compositor_(compositor) { + vsync_manager_(vsync_manager) { Initialize(); } @@ -34,13 +30,11 @@ BrowserCompositorOutputSurface::BrowserCompositorOutputSurface( scoped_ptr<cc::SoftwareOutputDevice> software_device, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor) + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager) : OutputSurface(software_device.Pass()), surface_id_(surface_id), output_surface_map_(output_surface_map), - compositor_message_loop_(compositor_message_loop), - compositor_(compositor) { + vsync_manager_(vsync_manager) { Initialize(); } @@ -49,6 +43,7 @@ BrowserCompositorOutputSurface::~BrowserCompositorOutputSurface() { if (!HasClient()) return; output_surface_map_->Remove(surface_id_); + vsync_manager_->RemoveObserver(this); } void BrowserCompositorOutputSurface::Initialize() { @@ -77,6 +72,7 @@ bool BrowserCompositorOutputSurface::BindToClient( output_surface_map_->AddWithID(this, surface_id_); if (reflector_) reflector_->OnSourceSurfaceReady(surface_id_); + vsync_manager_->AddObserver(this); return true; } @@ -92,11 +88,15 @@ void BrowserCompositorOutputSurface::OnUpdateVSyncParameters( base::TimeDelta interval) { DCHECK(CalledOnValidThread()); DCHECK(HasClient()); - OnVSyncParametersChanged(timebase, interval); - compositor_message_loop_->PostTask( - FROM_HERE, - base::Bind(&ui::Compositor::OnUpdateVSyncParameters, - compositor_, timebase, interval)); + CommitVSyncParameters(timebase, interval); +} + +void BrowserCompositorOutputSurface::OnUpdateVSyncParametersFromGpu( + base::TimeTicks timebase, + base::TimeDelta interval) { + DCHECK(CalledOnValidThread()); + DCHECK(HasClient()); + vsync_manager_->UpdateVSyncParameters(timebase, interval); } void BrowserCompositorOutputSurface::SetReflector(ReflectorImpl* reflector) { diff --git a/content/browser/compositor/browser_compositor_output_surface.h b/content/browser/compositor/browser_compositor_output_surface.h index bf0e366..7c26b083 100644 --- a/content/browser/compositor/browser_compositor_output_surface.h +++ b/content/browser/compositor/browser_compositor_output_surface.h @@ -6,19 +6,15 @@ #define CONTENT_BROWSER_COMPOSITOR_BROWSER_COMPOSITOR_OUTPUT_SURFACE_H_ #include "base/id_map.h" -#include "base/memory/weak_ptr.h" #include "base/threading/non_thread_safe.h" #include "cc/output/output_surface.h" #include "content/common/content_export.h" - -namespace base { class MessageLoopProxy; } +#include "ui/compositor/compositor_vsync_manager.h" namespace cc { class SoftwareOutputDevice; } -namespace ui { class Compositor; } - namespace content { class ContextProviderCommandBuffer; class ReflectorImpl; @@ -26,6 +22,7 @@ class WebGraphicsContext3DCommandBufferImpl; class CONTENT_EXPORT BrowserCompositorOutputSurface : public cc::OutputSurface, + public ui::CompositorVSyncManager::Observer, public base::NonThreadSafe { public: virtual ~BrowserCompositorOutputSurface(); @@ -34,8 +31,12 @@ class CONTENT_EXPORT BrowserCompositorOutputSurface virtual bool BindToClient(cc::OutputSurfaceClient* client) OVERRIDE; virtual void Reshape(const gfx::Size& size, float scale_factor) OVERRIDE; - void OnUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval); + // ui::CompositorOutputSurface::Observer implementation. + virtual void OnUpdateVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) OVERRIDE; + + void OnUpdateVSyncParametersFromGpu(base::TimeTicks tiembase, + base::TimeDelta interval); void SetReflector(ReflectorImpl* reflector); @@ -45,22 +46,19 @@ class CONTENT_EXPORT BrowserCompositorOutputSurface const scoped_refptr<ContextProviderCommandBuffer>& context, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor); + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager); // Constructor used by the software implementation. BrowserCompositorOutputSurface( scoped_ptr<cc::SoftwareOutputDevice> software_device, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor); + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager); int surface_id_; IDMap<BrowserCompositorOutputSurface>* output_surface_map_; - scoped_refptr<base::MessageLoopProxy> compositor_message_loop_; - base::WeakPtr<ui::Compositor> compositor_; + scoped_refptr<ui::CompositorVSyncManager> vsync_manager_; scoped_refptr<ReflectorImpl> reflector_; private: diff --git a/content/browser/compositor/browser_compositor_output_surface_proxy.cc b/content/browser/compositor/browser_compositor_output_surface_proxy.cc index d95c9b0..27fe55a 100644 --- a/content/browser/compositor/browser_compositor_output_surface_proxy.cc +++ b/content/browser/compositor/browser_compositor_output_surface_proxy.cc @@ -53,6 +53,6 @@ BrowserCompositorOutputSurfaceProxy::OnUpdateVSyncParametersOnCompositorThread( base::TimeDelta interval) { BrowserCompositorOutputSurface* surface = surface_map_->Lookup(surface_id); if (surface) - surface->OnUpdateVSyncParameters(timebase, interval); + surface->OnUpdateVSyncParametersFromGpu(timebase, interval); } } // namespace content diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.cc b/content/browser/compositor/gpu_browser_compositor_output_surface.cc index 17c4780..32a43fd 100644 --- a/content/browser/compositor/gpu_browser_compositor_output_surface.cc +++ b/content/browser/compositor/gpu_browser_compositor_output_surface.cc @@ -15,13 +15,11 @@ GpuBrowserCompositorOutputSurface::GpuBrowserCompositorOutputSurface( const scoped_refptr<ContextProviderCommandBuffer>& context, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor) + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager) : BrowserCompositorOutputSurface(context, surface_id, output_surface_map, - compositor_message_loop, - compositor) {} + vsync_manager) {} GpuBrowserCompositorOutputSurface::~GpuBrowserCompositorOutputSurface() {} diff --git a/content/browser/compositor/gpu_browser_compositor_output_surface.h b/content/browser/compositor/gpu_browser_compositor_output_surface.h index c677839..a773ad5 100644 --- a/content/browser/compositor/gpu_browser_compositor_output_surface.h +++ b/content/browser/compositor/gpu_browser_compositor_output_surface.h @@ -7,6 +7,10 @@ #include "content/browser/compositor/browser_compositor_output_surface.h" +namespace ui { +class CompositorVSyncManager; +} + namespace content { // Adapts a WebGraphicsContext3DCommandBufferImpl into a @@ -19,8 +23,7 @@ class GpuBrowserCompositorOutputSurface const scoped_refptr<ContextProviderCommandBuffer>& context, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor); + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager); virtual ~GpuBrowserCompositorOutputSurface(); diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index d97fdc1..d72958b 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc @@ -217,8 +217,7 @@ scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface( CreateSoftwareOutputDevice(compositor), per_compositor_data_[compositor]->surface_id, &output_surface_map_, - base::MessageLoopProxy::current().get(), - compositor->AsWeakPtr())); + compositor->vsync_manager())); return surface.PassAs<cc::OutputSurface>(); } @@ -237,8 +236,7 @@ scoped_ptr<cc::OutputSurface> GpuProcessTransportFactory::CreateOutputSurface( context_provider, per_compositor_data_[compositor]->surface_id, &output_surface_map_, - base::MessageLoopProxy::current().get(), - compositor->AsWeakPtr())); + compositor->vsync_manager())); if (data->reflector.get()) { data->reflector->CreateSharedTexture(); data->reflector->AttachToOutputSurface(surface.get()); diff --git a/content/browser/compositor/software_browser_compositor_output_surface.cc b/content/browser/compositor/software_browser_compositor_output_surface.cc index 4767e22..369fe93 100644 --- a/content/browser/compositor/software_browser_compositor_output_surface.cc +++ b/content/browser/compositor/software_browser_compositor_output_surface.cc @@ -21,13 +21,11 @@ SoftwareBrowserCompositorOutputSurface::SoftwareBrowserCompositorOutputSurface( scoped_ptr<cc::SoftwareOutputDevice> software_device, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor) + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager) : BrowserCompositorOutputSurface(software_device.Pass(), surface_id, output_surface_map, - compositor_message_loop, - compositor), + vsync_manager), output_surface_proxy_(surface_proxy) {} SoftwareBrowserCompositorOutputSurface:: diff --git a/content/browser/compositor/software_browser_compositor_output_surface.h b/content/browser/compositor/software_browser_compositor_output_surface.h index 88bf9a9..788d9da 100644 --- a/content/browser/compositor/software_browser_compositor_output_surface.h +++ b/content/browser/compositor/software_browser_compositor_output_surface.h @@ -8,16 +8,15 @@ #include "base/memory/weak_ptr.h" #include "content/browser/compositor/browser_compositor_output_surface.h" #include "content/common/content_export.h" -#include "ui/compositor/compositor.h" - -namespace base { -class MessageLoopProxy; -} namespace cc { class SoftwareOutputDevice; } +namespace ui { +class CompositorVSyncManager; +} + namespace content { class BrowserCompositorOutputSurfaceProxy; @@ -30,8 +29,7 @@ class CONTENT_EXPORT SoftwareBrowserCompositorOutputSurface scoped_ptr<cc::SoftwareOutputDevice> software_device, int surface_id, IDMap<BrowserCompositorOutputSurface>* output_surface_map, - base::MessageLoopProxy* compositor_message_loop, - base::WeakPtr<ui::Compositor> compositor); + const scoped_refptr<ui::CompositorVSyncManager>& vsync_manager); virtual ~SoftwareBrowserCompositorOutputSurface(); diff --git a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc b/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc index 047346f..3f48d21 100644 --- a/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc +++ b/content/browser/compositor/software_browser_compositor_output_surface_unittest.cc @@ -7,6 +7,7 @@ #include "content/browser/compositor/browser_compositor_output_surface_proxy.h" #include "content/browser/compositor/software_browser_compositor_output_surface.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/compositor/compositor.h" #include "ui/compositor/test/context_factories_for_test.h" #include "ui/gfx/vsync_provider.h" @@ -79,6 +80,8 @@ class SoftwareBrowserCompositorOutputSurfaceTest : public testing::Test { SoftwareBrowserCompositorOutputSurfaceTest:: SoftwareBrowserCompositorOutputSurfaceTest() { + // |message_loop_| is not used, but the main thread still has to exist for the + // compositor to use. message_loop_.reset(new base::MessageLoopForUI); } @@ -114,8 +117,7 @@ SoftwareBrowserCompositorOutputSurfaceTest::CreateSurface( device.Pass(), 1, &surface_map_, - compositor_->GetCompositorMessageLoop(), - compositor_->AsWeakPtr())); + compositor_->vsync_manager())); } TEST_F(SoftwareBrowserCompositorOutputSurfaceTest, NoVSyncProvider) { diff --git a/content/browser/renderer_host/media/desktop_capture_device_aura.cc b/content/browser/renderer_host/media/desktop_capture_device_aura.cc index 877ce82..5669bce 100644 --- a/content/browser/renderer_host/media/desktop_capture_device_aura.cc +++ b/content/browser/renderer_host/media/desktop_capture_device_aura.cc @@ -113,9 +113,6 @@ class DesktopVideoCaptureMachine virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE {} virtual void OnCompositingLockStateChanged( ui::Compositor* compositor) OVERRIDE {} - virtual void OnUpdateVSyncParameters(ui::Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) OVERRIDE {} private: // Captures a frame. diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 38bae4a..1c66023 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc @@ -3229,7 +3229,6 @@ void RenderWidgetHostViewAura::OnCompositingLockStateChanged( } void RenderWidgetHostViewAura::OnUpdateVSyncParameters( - ui::Compositor* compositor, base::TimeTicks timebase, base::TimeDelta interval) { if (IsShowing()) { @@ -3530,6 +3529,10 @@ void RenderWidgetHostViewAura::AddedToRootWindow() { legacy_render_widget_host_HWND_->UpdateParent( reinterpret_cast<HWND>(GetNativeViewId())); #endif + + ui::Compositor* compositor = GetCompositor(); + if (compositor) + compositor->vsync_manager()->AddObserver(this); } void RenderWidgetHostViewAura::RemovingFromRootWindow() { @@ -3553,8 +3556,12 @@ void RenderWidgetHostViewAura::RemovingFromRootWindow() { RunOnCommitCallbacks(); resize_lock_.reset(); host_->WasResized(); - if (compositor && compositor->HasObserver(this)) - compositor->RemoveObserver(this); + + if (compositor) { + if (compositor->HasObserver(this)) + compositor->RemoveObserver(this); + compositor->vsync_manager()->RemoveObserver(this); + } #if defined(OS_WIN) // Update the legacy window's parent temporarily to the desktop window. It diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 995aaf6..7c6605c 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h @@ -37,6 +37,7 @@ #include "ui/base/ime/text_input_client.h" #include "ui/compositor/compositor.h" #include "ui/compositor/compositor_observer.h" +#include "ui/compositor/compositor_vsync_manager.h" #include "ui/gfx/display_observer.h" #include "ui/gfx/rect.h" #include "webkit/common/cursors/webcursor.h" @@ -79,6 +80,7 @@ class ResizeLock; class CONTENT_EXPORT RenderWidgetHostViewAura : public RenderWidgetHostViewBase, public ui::CompositorObserver, + public ui::CompositorVSyncManager::Observer, public ui::TextInputClient, public gfx::DisplayObserver, public aura::RootWindowObserver, @@ -372,8 +374,9 @@ class CONTENT_EXPORT RenderWidgetHostViewAura virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE; virtual void OnCompositingLockStateChanged( ui::Compositor* compositor) OVERRIDE; - virtual void OnUpdateVSyncParameters(ui::Compositor* compositor, - base::TimeTicks timebase, + + // Overridden from ui::CompositorVSyncManager::Observer + virtual void OnUpdateVSyncParameters(base::TimeTicks timebase, base::TimeDelta interval) OVERRIDE; private: diff --git a/content/renderer/gpu/compositor_output_surface.cc b/content/renderer/gpu/compositor_output_surface.cc index 7cb5199..1ddafda 100644 --- a/content/renderer/gpu/compositor_output_surface.cc +++ b/content/renderer/gpu/compositor_output_surface.cc @@ -138,7 +138,8 @@ void CompositorOutputSurface::OnMessageReceived(const IPC::Message& message) { if (!HasClient()) return; IPC_BEGIN_MESSAGE_MAP(CompositorOutputSurface, message) - IPC_MESSAGE_HANDLER(ViewMsg_UpdateVSyncParameters, OnUpdateVSyncParameters); + IPC_MESSAGE_HANDLER(ViewMsg_UpdateVSyncParameters, + OnUpdateVSyncParametersFromBrowser); IPC_MESSAGE_HANDLER(ViewMsg_SwapCompositorFrameAck, OnSwapAck); IPC_MESSAGE_HANDLER(ViewMsg_ReclaimCompositorResources, OnReclaimResources); #if defined(OS_ANDROID) @@ -147,10 +148,11 @@ void CompositorOutputSurface::OnMessageReceived(const IPC::Message& message) { IPC_END_MESSAGE_MAP() } -void CompositorOutputSurface::OnUpdateVSyncParameters( - base::TimeTicks timebase, base::TimeDelta interval) { +void CompositorOutputSurface::OnUpdateVSyncParametersFromBrowser( + base::TimeTicks timebase, + base::TimeDelta interval) { DCHECK(CalledOnValidThread()); - OnVSyncParametersChanged(timebase, interval); + CommitVSyncParameters(timebase, interval); } #if defined(OS_ANDROID) diff --git a/content/renderer/gpu/compositor_output_surface.h b/content/renderer/gpu/compositor_output_surface.h index 7afaa51..62e159d 100644 --- a/content/renderer/gpu/compositor_output_surface.h +++ b/content/renderer/gpu/compositor_output_surface.h @@ -90,8 +90,8 @@ class CompositorOutputSurface }; void OnMessageReceived(const IPC::Message& message); - void OnUpdateVSyncParameters( - base::TimeTicks timebase, base::TimeDelta interval); + void OnUpdateVSyncParametersFromBrowser(base::TimeTicks timebase, + base::TimeDelta interval); #if defined(OS_ANDROID) void OnBeginImplFrame(const cc::BeginFrameArgs& args); #endif diff --git a/ui/aura/bench/bench_main.cc b/ui/aura/bench/bench_main.cc index 94a8f6f..4f59dd36 100644 --- a/ui/aura/bench/bench_main.cc +++ b/ui/aura/bench/bench_main.cc @@ -122,11 +122,6 @@ class BenchCompositorObserver : public ui::CompositorObserver { virtual void OnCompositingLockStateChanged( Compositor* compositor) OVERRIDE {} - virtual void OnUpdateVSyncParameters(ui::Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) OVERRIDE { - } - virtual void Draw() {} int frames() const { return frames_; } diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index e662533..7061599 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc @@ -27,6 +27,7 @@ #include "third_party/skia/include/core/SkBitmap.h" #include "ui/compositor/compositor_observer.h" #include "ui/compositor/compositor_switches.h" +#include "ui/compositor/compositor_vsync_manager.h" #include "ui/compositor/dip_util.h" #include "ui/compositor/layer.h" #include "ui/gfx/frame_time.h" @@ -183,6 +184,7 @@ namespace ui { Compositor::Compositor(gfx::AcceleratedWidget widget) : root_layer_(NULL), widget_(widget), + vsync_manager_(new CompositorVSyncManager()), posted_swaps_(new PostedSwapQueue()), device_scale_factor_(0.0f), last_started_frame_(0), @@ -420,6 +422,10 @@ void Compositor::SetBackgroundColor(SkColor color) { ScheduleDraw(); } +scoped_refptr<CompositorVSyncManager> Compositor::vsync_manager() const { + return vsync_manager_; +} + void Compositor::AddObserver(CompositorObserver* observer) { observer_list_.AddObserver(observer); } @@ -432,13 +438,6 @@ bool Compositor::HasObserver(CompositorObserver* observer) { return observer_list_.HasObserver(observer); } -void Compositor::OnUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval) { - FOR_EACH_OBSERVER(CompositorObserver, - observer_list_, - OnUpdateVSyncParameters(this, timebase, interval)); -} - void Compositor::Layout() { // We're sending damage that will be addressed during this composite // cycle, so we don't need to schedule another composite to address it. diff --git a/ui/compositor/compositor.gyp b/ui/compositor/compositor.gyp index 33f01ee..e1bd763 100644 --- a/ui/compositor/compositor.gyp +++ b/ui/compositor/compositor.gyp @@ -27,6 +27,8 @@ 'compositor.h', 'compositor_export.h', 'compositor_observer.h', + 'compositor_vsync_manager.cc', + 'compositor_vsync_manager.h', 'compositor_switches.cc', 'compositor_switches.h', 'debug_utils.cc', diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h index 81363ba..84ed365 100644 --- a/ui/compositor/compositor.h +++ b/ui/compositor/compositor.h @@ -43,6 +43,7 @@ class Size; namespace ui { class Compositor; +class CompositorVSyncManager; class Layer; class PostedSwapQueue; class Reflector; @@ -163,8 +164,7 @@ class COMPOSITOR_EXPORT CompositorLock // view hierarchy. class COMPOSITOR_EXPORT Compositor : NON_EXPORTED_BASE(public cc::LayerTreeHostClient), - NON_EXPORTED_BASE(public cc::LayerTreeHostSingleThreadClient), - public base::SupportsWeakPtr<Compositor> { + NON_EXPORTED_BASE(public cc::LayerTreeHostSingleThreadClient) { public: explicit Compositor(gfx::AcceleratedWidget widget); virtual ~Compositor(); @@ -222,6 +222,9 @@ class COMPOSITOR_EXPORT Compositor // Returns the widget for this compositor. gfx::AcceleratedWidget widget() const { return widget_; } + // Returns the vsync manager for this compositor. + scoped_refptr<CompositorVSyncManager> vsync_manager() const; + // Compositor does not own observers. It is the responsibility of the // observer to remove itself when it is done observing. void AddObserver(CompositorObserver* observer); @@ -244,9 +247,6 @@ class COMPOSITOR_EXPORT Compositor // Signals swap has aborted (e.g. lost context). void OnSwapBuffersAborted(); - void OnUpdateVSyncParameters(base::TimeTicks timebase, - base::TimeDelta interval); - // LayerTreeHostClient implementation. virtual void WillBeginMainFrame(int frame_id) OVERRIDE {} virtual void DidBeginMainFrame() OVERRIDE {} @@ -302,6 +302,9 @@ class COMPOSITOR_EXPORT Compositor scoped_refptr<cc::Layer> root_web_layer_; scoped_ptr<cc::LayerTreeHost> host_; + // The manager of vsync parameters for this compositor. + scoped_refptr<CompositorVSyncManager> vsync_manager_; + // Used to verify that we have at most one draw swap in flight. scoped_ptr<PostedSwapQueue> posted_swaps_; diff --git a/ui/compositor/compositor_observer.h b/ui/compositor/compositor_observer.h index aced251..badc5b4 100644 --- a/ui/compositor/compositor_observer.h +++ b/ui/compositor/compositor_observer.h @@ -38,11 +38,6 @@ class COMPOSITOR_EXPORT CompositorObserver { // Called when the compositor lock state changes. virtual void OnCompositingLockStateChanged(Compositor* compositor) = 0; - // Called when the compositor has received updated VSync parameters. - virtual void OnUpdateVSyncParameters(Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) = 0; - protected: virtual ~CompositorObserver() {} }; diff --git a/ui/compositor/compositor_vsync_manager.cc b/ui/compositor/compositor_vsync_manager.cc new file mode 100644 index 0000000..1a10d4a --- /dev/null +++ b/ui/compositor/compositor_vsync_manager.cc @@ -0,0 +1,63 @@ +// Copyright 2014 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 "ui/compositor/compositor_vsync_manager.h" + +namespace ui { + +CompositorVSyncManager::CompositorVSyncManager() + : observer_list_(new ObserverListThreadSafe<Observer>()), + authoritative_vsync_interval_(base::TimeDelta::FromSeconds(0)) {} + +CompositorVSyncManager::~CompositorVSyncManager() {} + +void CompositorVSyncManager::SetAuthoritativeVSyncInterval( + base::TimeDelta interval) { + base::TimeTicks timebase; + { + base::AutoLock lock(vsync_parameters_lock_); + timebase = last_timebase_; + authoritative_vsync_interval_ = interval; + last_interval_ = interval; + } + NotifyObservers(timebase, interval); +} + +void CompositorVSyncManager::UpdateVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) { + { + base::AutoLock lock(vsync_parameters_lock_); + if (authoritative_vsync_interval_ != base::TimeDelta::FromSeconds(0)) + interval = authoritative_vsync_interval_; + last_timebase_ = timebase; + last_interval_ = interval; + } + NotifyObservers(timebase, interval); +} + +void CompositorVSyncManager::AddObserver(Observer* observer) { + base::TimeTicks timebase; + base::TimeDelta interval; + { + base::AutoLock lock(vsync_parameters_lock_); + timebase = last_timebase_; + interval = last_interval_; + } + observer_list_->AddObserver(observer); + observer->OnUpdateVSyncParameters(timebase, interval); +} + +void CompositorVSyncManager::RemoveObserver(Observer* observer) { + observer_list_->RemoveObserver(observer); +} + +void CompositorVSyncManager::NotifyObservers(base::TimeTicks timebase, + base::TimeDelta interval) { + observer_list_->Notify( + &CompositorVSyncManager::Observer::OnUpdateVSyncParameters, + timebase, + interval); +} + +} // namespace ui diff --git a/ui/compositor/compositor_vsync_manager.h b/ui/compositor/compositor_vsync_manager.h new file mode 100644 index 0000000..abfbad6 --- /dev/null +++ b/ui/compositor/compositor_vsync_manager.h @@ -0,0 +1,71 @@ +// Copyright 2014 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. + +#ifndef UI_COMPOSITOR_COMPOSITOR_VSYNC_MANAGER_H_ +#define UI_COMPOSITOR_COMPOSITOR_VSYNC_MANAGER_H_ + +#include "base/memory/ref_counted.h" +#include "base/observer_list_threadsafe.h" +#include "base/synchronization/lock.h" +#include "base/time/time.h" +#include "ui/compositor/compositor_export.h" + +namespace ui { + +// This class manages vsync parameters for a compositor. It merges updates of +// the parameters from different sources and sends the merged updates to +// observers which register to it. This class is explicitly synchronized and is +// safe to use and update from any thread. Observers of the manager will be +// notified on the thread they have registered from, and should be removed from +// the same thread. +class COMPOSITOR_EXPORT CompositorVSyncManager + : public base::RefCountedThreadSafe<CompositorVSyncManager> { + public: + class Observer { + public: + virtual void OnUpdateVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval) = 0; + }; + + CompositorVSyncManager(); + + // The "authoritative" vsync interval, if provided, will override |interval| + // as reported by UpdateVSyncParameters() whenever it is called. This is + // typically the value reported by a more reliable source, e.g. the platform + // display configuration. In the particular case of ChromeOS -- this is the + // value queried through XRandR, which is more reliable than the value + // queried through the 3D context. + void SetAuthoritativeVSyncInterval(base::TimeDelta interval); + + // The vsync parameters consist of |timebase|, which is the platform timestamp + // of the last vsync, and |interval|, which is the interval between vsyncs. + // |interval| may be overriden by SetAuthoritativeVSyncInterval() above. + void UpdateVSyncParameters(base::TimeTicks timebase, + base::TimeDelta interval); + + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + private: + friend class base::RefCountedThreadSafe<CompositorVSyncManager>; + + ~CompositorVSyncManager(); + + void NotifyObservers(base::TimeTicks timebase, base::TimeDelta interval); + + // List of observers. + scoped_refptr<ObserverListThreadSafe<Observer> > observer_list_; + + // Protects the cached vsync parameters below. + base::Lock vsync_parameters_lock_; + base::TimeTicks last_timebase_; + base::TimeDelta last_interval_; + base::TimeDelta authoritative_vsync_interval_; + + DISALLOW_COPY_AND_ASSIGN(CompositorVSyncManager); +}; + +} // namespace ui + +#endif // UI_COMPOSITOR_COMPOSITOR_VSYNC_MANAGER_H_ diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc index 736f92a..a384f32 100644 --- a/ui/compositor/layer_unittest.cc +++ b/ui/compositor/layer_unittest.cc @@ -354,11 +354,6 @@ class TestCompositorObserver : public CompositorObserver { virtual void OnCompositingLockStateChanged(Compositor* compositor) OVERRIDE { } - virtual void OnUpdateVSyncParameters(Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) OVERRIDE { - } - bool committed_; bool started_; bool ended_; diff --git a/ui/compositor/test/draw_waiter_for_test.cc b/ui/compositor/test/draw_waiter_for_test.cc index 8429675..c471a6f 100644 --- a/ui/compositor/test/draw_waiter_for_test.cc +++ b/ui/compositor/test/draw_waiter_for_test.cc @@ -50,8 +50,4 @@ void DrawWaiterForTest::OnCompositingAborted(Compositor* compositor) {} void DrawWaiterForTest::OnCompositingLockStateChanged(Compositor* compositor) {} -void DrawWaiterForTest::OnUpdateVSyncParameters(Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) {} - } // namespace ui diff --git a/ui/compositor/test/draw_waiter_for_test.h b/ui/compositor/test/draw_waiter_for_test.h index d191ec4..051c58f 100644 --- a/ui/compositor/test/draw_waiter_for_test.h +++ b/ui/compositor/test/draw_waiter_for_test.h @@ -38,9 +38,6 @@ class DrawWaiterForTest : public CompositorObserver { virtual void OnCompositingEnded(Compositor* compositor) OVERRIDE; virtual void OnCompositingAborted(Compositor* compositor) OVERRIDE; virtual void OnCompositingLockStateChanged(Compositor* compositor) OVERRIDE; - virtual void OnUpdateVSyncParameters(Compositor* compositor, - base::TimeTicks timebase, - base::TimeDelta interval) OVERRIDE; scoped_ptr<base::RunLoop> wait_run_loop_; diff --git a/ui/gl/sync_control_vsync_provider.cc b/ui/gl/sync_control_vsync_provider.cc index 16b1e8a..66d3734 100644 --- a/ui/gl/sync_control_vsync_provider.cc +++ b/ui/gl/sync_control_vsync_provider.cc @@ -125,16 +125,23 @@ void SyncControlVSyncProvider::GetVSyncParameters( if (relative_change < kRelativeIntervalDifferenceThreshold) { if (new_interval.InMicroseconds() < kMinVsyncIntervalUs || new_interval.InMicroseconds() > kMaxVsyncIntervalUs) { - LOG(FATAL) << "Calculated bogus refresh interval of " - << new_interval.InMicroseconds() << " us. " - << "Last time base of " << last_timebase_.ToInternalValue() - << " us. " - << "Current time base of " << timebase.ToInternalValue() - << " us. " - << "Last media stream count of " - << last_media_stream_counter_ << ". " - << "Current media stream count of " << media_stream_counter - << "."; +#if defined(USE_ASH) + // On ash platforms (ChromeOS essentially), the real refresh interval is + // queried from XRandR, regardless of the value calculated here, and + // this value is overriden by ui::CompositorVSyncManager. The log + // should not be fatal in this case. Reconsider all this when XRandR + // support is added to non-ash platforms. + // http://crbug.com/340851 + LOG(ERROR) +#else + LOG(FATAL) +#endif // USE_ASH + << "Calculated bogus refresh interval=" + << new_interval.InMicroseconds() + << " us., last_timebase_=" << last_timebase_.ToInternalValue() + << " us., timebase=" << timebase.ToInternalValue() + << " us., last_media_stream_counter_=" << last_media_stream_counter_ + << ", media_stream_counter=" << media_stream_counter; } else { last_good_interval_ = new_interval; } |